From 1de426f2bcfb538f996d49e4eb72fd58f9fe9896 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Sat, 18 Jan 2025 16:11:27 +0100 Subject: [PATCH 01/70] Refactor Tiles, WIP --- nbproject/private/profiler/settings.xml | 9 + .../profiler/snapshot-1736349327025.nps | Bin 0 -> 14196 bytes .../commandStation/autopilot/AutoPilot.java | 6 +- .../autopilot/state/Dispatcher.java | 8 +- .../virtual/VirtualCommandStationImpl.java | 101 +- .../jcs/persistence/H2PersistenceService.java | 13 +- src/main/java/jcs/ui/layout/LayoutCanvas.java | 690 +++++----- src/main/java/jcs/ui/layout/LayoutPanel.java | 12 +- .../java/jcs/ui/layout/LayoutPanelTester.java | 3 +- .../jcs/ui/layout/LayoutPanelTesterRO.java | 3 +- src/main/java/jcs/ui/layout/RoutesDialog.java | 5 +- src/main/java/jcs/ui/layout/TileCache.java | 414 ++++++ .../ui/layout/dialogs/BlockControlDialog.java | 8 +- .../jcs/ui/layout/dialogs/BlockDialog.java | 9 +- .../jcs/ui/layout/dialogs/SensorDialog.java | 4 +- .../jcs/ui/layout/dialogs/SignalDialog.java | 4 +- .../jcs/ui/layout/dialogs/SwitchDialog.java | 4 +- .../jcs/ui/layout/tiles/AbstractTile.java | 893 ------------ src/main/java/jcs/ui/layout/tiles/Block.java | 268 ++-- src/main/java/jcs/ui/layout/tiles/Cross.java | 55 +- .../java/jcs/ui/layout/tiles/Crossing.java | 22 +- src/main/java/jcs/ui/layout/tiles/Curved.java | 45 +- .../jcs/ui/layout/tiles/DefaultTileModel.java | 289 ++++ src/main/java/jcs/ui/layout/tiles/End.java | 51 +- src/main/java/jcs/ui/layout/tiles/Sensor.java | 45 +- src/main/java/jcs/ui/layout/tiles/Signal.java | 51 +- .../java/jcs/ui/layout/tiles/Straight.java | 44 +- .../ui/layout/tiles/StraightDirection.java | 22 +- src/main/java/jcs/ui/layout/tiles/Switch.java | 86 +- src/main/java/jcs/ui/layout/tiles/Tile.java | 1216 +++++++++++++++-- src/main/java/jcs/ui/layout/tiles/Tile1.java | 221 +++ .../java/jcs/ui/layout/tiles/TileFactory.java | 395 +----- .../java/jcs/ui/layout/tiles/TileModel.java | 85 ++ .../tiles/sandbox/AlphaButtonPolicy.java | 91 ++ .../tiles/sandbox/BasicJogShuttleUI.java | 156 +++ .../ui/layout/tiles/sandbox/FocusExample.java | 86 ++ .../tiles/sandbox/FocusTraversalExample.java | 38 + .../layout/tiles/sandbox/InvokeExample.java | 115 ++ .../ui/layout/tiles/sandbox/JogShuttle.java | 154 +++ .../ui/layout/tiles/sandbox/JogShuttleUI.java | 11 + .../ui/layout/tiles/sandbox/SimpleModel.java | 84 ++ .../tiles/sandbox/SimpleModelInterface.java | 24 + .../jcs/ui/layout/tiles/sandbox/Sketch.java | 85 ++ .../jcs/ui/layout/tiles/BlockTileTester.form | 220 +++ .../jcs/ui/layout/tiles/BlockTileTester.java | 403 ++++-- .../jcs/ui/layout/tiles/CrossTileTester.java | 40 +- .../ui/layout/tiles/CrossingTileTester.form | 197 +++ .../ui/layout/tiles/CrossingTileTester.java | 253 +++- .../jcs/ui/layout/tiles/CurvedTileTester.form | 197 +++ .../jcs/ui/layout/tiles/CurvedTileTester.java | 239 +++- .../jcs/ui/layout/tiles/DotGridCanvas.java | 70 + .../jcs/ui/layout/tiles/EndTileTester.form | 197 +++ .../jcs/ui/layout/tiles/EndTileTester.java | 239 +++- .../jcs/ui/layout/tiles/SensorTileTester.form | 208 +++ .../jcs/ui/layout/tiles/SensorTileTester.java | 254 +++- .../jcs/ui/layout/tiles/SignalTileTester.form | 208 +++ .../jcs/ui/layout/tiles/SignalTileTester.java | 436 ++++-- .../tiles/StraightDirectionTileTester.form | 197 +++ .../tiles/StraightDirectionTileTester.java | 235 +++- .../ui/layout/tiles/StraightTileTester.form | 197 +++ .../ui/layout/tiles/StraightTileTester.java | 236 +++- .../jcs/ui/layout/tiles/SwitchTileTester.form | 208 +++ .../jcs/ui/layout/tiles/SwitchTileTester.java | 354 +++-- .../java/jcs/ui/layout/tiles/TileTester.form | 175 +++ .../java/jcs/ui/layout/tiles/TileTester.java | 170 +++ .../ui/layout/tiles/UnscaledBlockCanvas.java | 72 +- .../layout/tiles/UnscaledBlockTileFrame.java | 42 +- .../ui/layout/tiles/UnscaledTileFrame.form | 5 +- .../ui/layout/tiles/UnscaledTileFrame.java | 118 +- src/test/resources/images/DHG 6505.png | Bin 0 -> 25034 bytes 70 files changed, 8279 insertions(+), 2816 deletions(-) create mode 100644 nbproject/private/profiler/settings.xml create mode 100644 nbproject/private/profiler/snapshot-1736349327025.nps create mode 100644 src/main/java/jcs/ui/layout/TileCache.java delete mode 100755 src/main/java/jcs/ui/layout/tiles/AbstractTile.java create mode 100644 src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java mode change 100644 => 100755 src/main/java/jcs/ui/layout/tiles/Tile.java create mode 100644 src/main/java/jcs/ui/layout/tiles/Tile1.java create mode 100644 src/main/java/jcs/ui/layout/tiles/TileModel.java create mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/AlphaButtonPolicy.java create mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/BasicJogShuttleUI.java create mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/FocusExample.java create mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/FocusTraversalExample.java create mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/InvokeExample.java create mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/JogShuttle.java create mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/JogShuttleUI.java create mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/SimpleModel.java create mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/SimpleModelInterface.java create mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/Sketch.java create mode 100644 src/test/java/jcs/ui/layout/tiles/BlockTileTester.form create mode 100644 src/test/java/jcs/ui/layout/tiles/CrossingTileTester.form create mode 100644 src/test/java/jcs/ui/layout/tiles/CurvedTileTester.form create mode 100644 src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java create mode 100644 src/test/java/jcs/ui/layout/tiles/EndTileTester.form create mode 100644 src/test/java/jcs/ui/layout/tiles/SensorTileTester.form create mode 100644 src/test/java/jcs/ui/layout/tiles/SignalTileTester.form create mode 100644 src/test/java/jcs/ui/layout/tiles/StraightDirectionTileTester.form create mode 100644 src/test/java/jcs/ui/layout/tiles/StraightTileTester.form create mode 100644 src/test/java/jcs/ui/layout/tiles/SwitchTileTester.form create mode 100644 src/test/java/jcs/ui/layout/tiles/TileTester.form create mode 100644 src/test/java/jcs/ui/layout/tiles/TileTester.java create mode 100644 src/test/resources/images/DHG 6505.png diff --git a/nbproject/private/profiler/settings.xml b/nbproject/private/profiler/settings.xml new file mode 100644 index 00000000..31c9a1f4 --- /dev/null +++ b/nbproject/private/profiler/settings.xml @@ -0,0 +1,9 @@ + + + +10 +#org.netbeans.modules.profiler.v2.features.LocksFeature@#org.netbeans.modules.profiler.v2.features.MethodsFeature@#org.netbeans.modules.profiler.v2.features.MonitorFeature@ +true +ProjectClassesMode +false + diff --git a/nbproject/private/profiler/snapshot-1736349327025.nps b/nbproject/private/profiler/snapshot-1736349327025.nps new file mode 100644 index 0000000000000000000000000000000000000000..194a49f32e0d7900b9edfda03217f697cf01e92b GIT binary patch literal 14196 zcma*Nby(X=_b&=L<*Psm) zx#`~Td4K1gXYYH@KP&T{S!-sNeP+!(aeM>Tbdt4I25F)`LP0@6MM2?yhk~*$=$Uck zg9)XSOZ;W0UklPta=2~>8P>>2STUG7m#@7|D)%J3{=~2p_A$QR%0SaF|9J2sk{wO@ z1tsmbCr>@*UJDUFrD2Exr@J;g5$io#H;F!!YtoN??SEMIr7|rm>q}Z}x#h3lKBAJ} zw5K1u<-VWp&kCcMt#u^3sorlqx%=R_e76a6HFsZ?@8gMoEfLGR-9)C6ItJzg;>vs| zr)2{QW0q<30Mb=?Kp-<+rk&1m`Dq2c%A5eAy~y-xv6H4P1_x_B6cfxA6>AmIr9G>j z=h;$Uk3bldymp@ri^(Eh1+$Ad^eZn28m7uVJ70ZOb=3DJEml|fF+owsQKB$BNGSSfNZOIrWj>* zp4aPJvM4pKE4%Q$7u9DAA|s`$YkSLgEaXVHv)!84iUVhVoE|jKDk}O&CH8eR7s%kT znzu_d5KvUEyIEWGnkr82h;r`(&9S+bd zq(eEGA5D03%{Om|-Wlym{!d^wf=OS9C1>Q7f};cP>g{k);OhM6jxn`w&xIDZ7RQ{wt4JNC?4@+; zp1pYX98;_ZRs5y?_NoIj}cA5OEcm`(+W0)QJgs}Oh`mL@K;+)^Y=JA#7R$4GY8*$I;`x`f(m7UceWEb6_~BYHl9BuF#zb!3uvmpp zUxd)JqYI5OSe2CYjb0Q^tD64~-JYUj!BjHYE~9j1m+k5Gv=R7O&`dH_E1)N85BhBI zT>s{2(pjJK+k9BAnxT1SI$5-pgEh|<04Ou4H>pLYJxj*%@=}x4j#szq&H0?QcRuxu zt8+aSK4&3O-qg#%0fjmtK6Azi94m4)b3@kZcZNd+ADas#K{MY7aWz=0++GH5n{CGl z_O|CJ%&Gl00j6kuJ&L?JqIQi=)B?>>Hkc`((sXDA6f#W9xy!b(4}#etW$BIJC?$=p zLUuOe!*v9hD!7|t%)(Tacy%)3${_XhjYm?MRDg{s-4SzYW>;Lpt+rArSO3rrj(3>b zaF;!AZ1t4B-pDGxRuAdim%P%N$z)p~M2Swu^1ZoK*H-VNu!sUegKX8*1zJH~;%te} zIk!YI;aZv-EHTFmHOn>@4Bj*D=Q#uH{0_!3#Ef&?SQzg;Z@F!lg$z?`lq={D+J+eL+?h5TT#j84NXOaj`P#^+Xp;vgMW> zAVx-qnr_9^c-=U@!KqPT-@G76N|}Gd8mGGu8 z&umc0myt{K@(xfo<|I;CWk;yue(^Xv&mrQ7wa%{MjCO>&+X^NIE*ECnDqtqESv*>n zo2R=hV>C)1-dLPZ=BE0LC?qRkdem}6`xQ$2iX3}Pm{*uen75abYdilqIgG`3hBICy zYW*qiI-7O{A#o;S6z}n-AzPW;@Ebxo)!GZ!x>SV=zrK{O%Q~tpxUeyImK_FpqR&+0 zdJ3ZER?hQ_g}e9*5tn+T{p_PtD-M9OBjV_CMQ@_JaL&~#4d=;Ed$F|hO^Nn2FngZmGgz%H`DLQ;yTa)Xwo&F%FEAURVj*P69zH@vT!Kk2s`F_-sGqCoDPhiUv~u zV9{=|J*4&+-1RAoxDpEZBCI=qd^=z;rpli4H z*yTk+-$))-P;VO^O zrD%5F0uQa2A`%WFA@r#62fa@Nl)oXABiaBM81I{5iagV4)r!2D?YHW+Z``9YSzYI! z8xVaUu9heOq>ugtQj~Kj=jxofeCnV4%`#{qVIJ#YV=dRhvOEO-$v($RFTX z#_TkAx5Z~S7C;`~o0l6mr1X3nbeJ&r01jqu8>->sPSXyU8a=d_Pae@2g9f+i4Vl;Y z*RW7pUr0+2sQyY(ouZ<@uifE}FiwWx0Wln-HdxSxAM47s#4-ug@@`M}K$lj&9G&a_ zM3nc_QPG^PEXuizm4w=S!T3P0`QF*sFRY#xYihX1x@)iSZ{&!m=%2PpJ-J2)4%gf7x7u^+75uHyh0&^PXjng;cx%y>w&mR*%*O?=& zT$~y4WDJIu#FOw?FtDZx+G9?0Wa5-sXxYuBvJN5y<5y_U z9j00|M}A4Qb3`0QeS|g?)k2Hc3T#B(v52XJy`q>ixEIB2PZ+ZVEo9d|g^cX;P$^w? zUt$W1FYMIrV7N+4LmUlODloFqF%8boby%1_c~-~4ovdZ>3F-h!ih~4fOWMUj);pB# zt>2S;x|XcD`eClSGS2DQOMU*UnQ7@fEx# zWm!#eaqSDotUJAqZYJ`EJ9&X~3Z@ctcDcQ0HKTLb(H1JTKepRn$7IzyXSnGWeF_&~ znH#j=jtdtPcd5K29H2n+3gx%l)?6s77?dKpyHFL3J)b}GDr&XgP2R6%04{%Q*G)Q$ z5cR$1Ll@HfX}>`2JXBh<++$uEZt4@WYR;A@dnq7y^Luz*Zh2uwzpMIpf|=J3Iwtl3 zT||8__RQU#@s_;pfD#$+^Gd;I4wA=J9@kE$4j&49q6|?Vieqx>`tx)GBCCHGp)c16 zw>tzWrD{n{_v_v0Ip6eMscxeqaLFQC8WK#RqL#Pk&88v+)cESg+qbuk70SH6OUwZl zZawyXm8oe+MBVaJcpQhMSl~oUT%}}wYM7M7m?WxJ4n00y&|}}$?o$SO2~rQu**O*B+yOkvByV#L*L{R{jUA z@;@G868+6^Exo7rzfL&UT}@c}+e1?n=|hK8=1_qe}nDH6y`=)H)2H&wl9>u&94IX6H>!7$ra(MFX4=5()V z|11&P;iP#Sj0nqFRIxtdzW6vPkl62*S?xAc`}XHpQ#zM|WA%;ts0x>>sz=Nw^t85L z5$Fr@v0Fx#m)oik%E`Dxh|tii8s6_6EkA0f*=u;q+Uy4rKa$(C zsEXd;Z#aHS_K~M5&rGF>ZS{b?0A~XT)SVKj(|u2{{nj&HH-^1MN+o|d_2mt2i=Lx$ zk4>IlmUG#a@KJi@8&P2k=2l(PAH>EWuQ#Ay$($d!%bqy`4%jHZ<^A?mufj|urIEf# z_58g>fLqd=iuvk-zieDwfNztLM~Ga;wPNkfHT$bI=@ygT0GEd`O%~vOLX{Fk5Vh&yze@;OpV+`19;#yoUO0%J* zHvO#UR$TJz8H#RF5Z+{Z#eRbNY8q&}Vpv+BsAHnquE!_!1GX;^qVH5R!55Y28R}{D zi@3MD)OJ@l{yVO>Vi_+emF>}VQkyWdX(w0m3<{H{8pDqQg>TrdRx(@z?t9O&JJ?r3 z72%E^S{COivU6$hivtB-5OYnaaI`6w%PIQyL~VV|qqcDN@AcaHWV(gYt%nb9#TPj= z@!ASn*q6)Re&vrl*(NO5>cBHR)+=|gdD^xlG4@&ifzCm7zg|BjH~#EmxZ&eqe6E`G z>+FPsqPCKp)6o5hp2ysJo~{8V2{_A=P8ViFV~xaLGRSzI>xQQC&yHjFA7y1WU`@pt zg>!$dD^F&~Mm?@q@Q%BpoP$|<`3#Vg1(}rdU%}-Y#fT4-D76B-q&Gi>cW`yixhTc5 z17e=2jzM~_?-w-P9g=%0M*>jKT6jZiG*C z<;x{K*?M%XLAhBo?MSVlg9st$TH%UTLJGQbtsm@C?BD<{xQ}BNHt>JXejO(33)SB`$)m- z#EMlPG58{X#1eiwN7vu1FpF2``y!i2qK{d|P95d5AY0S+YGF)M;;RiJOIN795JN!n zNQkEJPmd!k_lq_=J;!N8dz^5^P%LZMg6SKa8}(@t?Q{}CCz9X%3D2Vp5B zb28K1(#|HSBC*g_U&HG{G#bRF*6WeUPARo=gxG-n25x9^hkYj`g03_*sE!*rVk?|9 zWUdpo_&(PS4?E`XpR%M)hoH8GjYU;o;}cP6CUVQXFU{T zylp%9vR5Z5$k#UmNl`l6Z)zoDGW!V?uDH{wV!!g@1gtk&>1lBTG&L}YzdFb@+O|m8S~*< z>V6blsO)d=pvU^A4kuPVH-UPiGt5VHe`Xfap8LWX)0OF|fK6n;TMm#+QC!iORpCsf z`hKt&6Le;HC_|dgk>%$377Y^Q4#>!`wU-+IAz0GR?NaYckaqvQg3Pi%m+z3xl(OtAHlI7LM@| zO2T67h#~3x+-;R}ODap3K!A}U#v2Qb+1s&h&v;_1MhW$mpa4Uj`2*^-0RpPH2^!WD zMoW>nQq$86S3&}}^vdnrJI1Mvv6u)z&B*kH237Jkrpvw>oGi9UG;lN_JzBL8MCUii z>++s5lWsWwfOHdczmYqmDxlm#AuxV!Q-L1yk>PUjfW0qj-HXeOPYl;Cr&uY)o4G0H zRJEA}YRxi^%Mr~)rYQKuemo{W%>`w~WM}fxsCrKeQ)yj?AO|m2--~V4-PfjmwTVTi z(j6ja+DQvd6?))7F{L@o(Qlz>vDW@v(d#|IPm~I1V3*-cEmIsRArANe)USyJ!mZ|3 zLv;>ff1k5o*^}30-m*8DC^i5y3$sKQ)Mog=>aHXMU6y?+*13|^lONlABq+_uM>}A!7Jpb0Vg`LXXx*@UCLu+PMM&;yS!87?-i-6|4yyn9|&@{?^6`Qj0?GZ0sR-}qb?OTlk zO`Cm_LOk)KmpaCtDzv>$znwJ13PuTMsK4^)y@S@#mDcN6iDafRe5+}gh3DZ>mlHZZ zohCWjXi6uS(@YWXadhx~Uz(`=%3x0Qp-YBVq=bg>YEo`bvVtr>8)?{;D z%<;0SYj;*RT%Rv*B|G=u3g@_Rz_WkGhw&Q5 zvC_F%NDmh*T2DbWjIb(6(sJ1%wt2D~N>f3GnUD{uwWoVmXK3F~r?)omrl+G;n7(~d zLCXS*u_=k2QdV*9ucqpa$X7dNHi%;bEkDOX#virO)eO)P^QS1$p_L(I9E!3Vl5agV zYJF6=u%mbP$hnWe;DkBh2{Nve^mZ8{y&f4!ugYZzw~6K}DK@<{9!TLk{k)e{JY0#N z9UlK2rnXBt^bp_N?DMX$&wohnSdVmJ74uP>s()kL9(v$jgJBY`hEXw6Lt8HEj`e%f zm+hx%H&ymoqD27hF~pJH4jaem_wd7YxXk@{47X}16ByF*VW=Z{vT7!^_=5ae2hTx) zS4HfHBIH^ty!K5ga58-~43q6SRgK(eB$Z13{H{59v1Ep81E_E`;em}FmM%q9@NxG= zbA>~$N?QF-(@iPg0)I{uFTvQwQCjb22Ue>Hv9sZq3w0^Dn`a+tEo(H#q7HG4wkZ60 z2VrmPv4g}oe%32!0L0V`75u(U?$`?N<{3@`0jzI$W+>j?Eo$Xve|X947Im=c=l9Z6 zv{kJqJ~_MkrIgTgnd@xW_S9R5u6{OHSjCgwLHNQKv`?~?K6Vxps{)X{Gu&t2TsnNy4KDuR>$?U`<}rkn`HC`aH*LsB?(V z`;Pi|3Y7Qhk5`M{sm(fi>?=u%S zwUv{LZb}WN6(3f(7E=bF+b`H3Rf3xcZr7#Vq_JEMUd0>Qm3~cJ6}4je1^>`*law@8 zuXEo3l<^9cF%E7PT+ZnD^oDJKa3A$LRWmL9p^ic)mZQz#eA?E}rXbCiD3n-<8MrO? z3Ig!KACIFU9Pr441cux{(NE5TW+hWl*46d%Sf;kM+55@gNN3(%$USvu^%GGrX?8bR zq%1c|b7Sq$yypDT^xU-B^nT1hV%HxLM1H7oS9Y!w`Lvj|V`4(xRiCrRP$5<#>f1oy zc1&>YWfT8x!u?a7`#^JJsd&kIwpaHPkRZyPE6AkDvKqA$VQ?| zxtuh%o8x?%ObBR_mrrOcM@TvnJ1+A!t1f?*JmEINd=`&d9_`)!prkn>HRY^NxJDo; zyAmD2arql!ZgqFP`b8nKr;8-x>wAzfua5pSL1RLqK_3-c)59$$emm`pj0gDZ0q3kt ztEzTY);6{k9qKZ)NSzf-&R#7C@Ih)K-PaOg05xjT6pg+q!yGR8t*I8XWY4`tIGMWe z^#U3n`6t@;tS9dgDB3LR`Y4$GhA3n4EcaCz%HqTTl=~qesS9SAfST_9#{SL+IH^RN z*;_Zbw5&3QSZokty|HNgZ)4Gez-!z^8d5QW?Ha9qG$rP;Eyb&OQ;R=C!mCV6N%qjuC zPv0kST|aTvxn6JnqVy&ZtAxH|ct=F^)-;6Kp)|CN?j2ZsWEzH%ql=LpaxH?OoY`AD zuYQeT>K`nEpw%k~q6zlKwPz3Q74hU`*XY{h)!LFh)mL9~|Kf!4HRkPp&@F$#zImx_ z#Fl@%o~qW*GFESLj!-U`5oH6_r2H8*6gX?H$^|e?ab}8fiK9m z>rsBh^4RIw)nY(P<}{L&lcA2F3~_q)OsBe&)5up_VwYk-f_H)^>0r&Z`VB_*cMm=i zvqGfhbobWe%p1^UKQzi>oCG(BAfA*@!xoqa$>VBaVn*`i=Jy_a?tJ;1Njr!kZHZrv z6nC4rj{)zV4g0hKBv5cg5PbF%upP5}fCOGT1de8--L+flOA?8(M)2aY?W`r625$$G z$1`#chbYqBssYd*N&K0hJ!uYy5&DPRVj1v4n^;DL@So!@nT%$3ylx~l4XzVG2y*2H zun~6_5M-edean5%SRdIr`ud#Io4iR?EJVzE-Bv^>Xsa^dq~K4iYAx98lQmy;p|kmkD7EaI&iZpf+X?ACt;HG z%f$qhSnoyD_>*{aDo9(BjqNl6d%$s;fn~oAefRi5Udh;@Gd&RQN&+SY>g?=Y9f4UyJ?NHjD3G3V)az$vrzSPhY!duxWo`)ZT!xc-YL(>2y6`?JX zFmc3_4+CGsf80Ie-n@93@*B;QO&zb~{fem<7PWN6D#n8xhU8PHX_%k?SG%=lr8N_( zR_x9to-H9M{5&i&QaS?BF1dvZO5stSOB!W1B)8dLby@Kjtm;z`fVUOV& zR8U@k6+he<&MAVpg9u1r`o%}bB*JO-o~CxM^Z7mA_Rn-&Q}Z10UnHh{Vz>4a-UM*B zrBCiAQvbj_;+JLaZ#pS4rUfVE@hsNJ4eGEMnSyojyyS=9Udtu|Rvbs>VDBi9h(eYx z@{|O9qryFNyFe_Yz=>yje@%^?Uj)(LCx&bE&U|Kn4Yv1@_0lSb=2# zYQaWipinF!aS-w4vqSdiU$I5hUKHeqYl_#EyT)v^pZ?;4+iYF;{Z=A4!@!GC>`g^0 zK|8MRm!Q>h>w8x5^Xv(Zw`iPcGT-nSTc1(S!5rW;A_!SThX{fgkqYpAC6*T?i6i+P zwpvIPL*N_f{`zH;FVT^I0vu!^Vu)qRR#aCA*XPbuSyxZCIHD@fg- zTyk%LiDvxpl6uVcqTJ&`f1lE2Yxl%lut23TK2M^NGTuHy z6ajoGph_5i)YMZj$si}YwZd6A6;&%*ds&d^`UjEuz>|ZuolZOmoMJsxN{A3YKl0V2 zkZ!jE{V%Mk6RmHhA0K3oim*%?Ll#vSe<<3e5*!y-ekI5%KoVafx3)z1?~;Rxk2D2I zYM2iJ1`F4w{c^H`Z2t$~lKhy+-_r-oZWxBK=5TeY12X^+(j3?N$M! zgPM94MiV4?utw8qiX8V8yzih4onC6ZNr;eShIS^F*+|ldT6Yh1S07v12;ortHk;O+ zzi?ihJw#1;XnufeMd+cGi# z`bg>FkePsc^OSLMhh^P#LP8GkuJenC-lf&zQ4Aqd_B{#rW8I^iek^!c+YqNE0-$gv>Z)GvQ!kpaTQE*WzDE4hJ zGNf)zF#J-E;m^P(A?pb-VQcw34T? z3@{~Me|XP$tFx$u-NeN;@Sceu%!$k}tIkCO?tQipHZuppxpok zS}WW__@%{Mj06r^kDJulK1?6~=Ea`zjGIQ+NpWQa!9A0kaRQvCv``avkgWM#2J@r{ z*?U}wBxCBx&s7Cu62@EA{T7z>sz2Wk;Vm35o6IHtNV)H~fQ2$bltHm%z1!bik)Swb zj`&DW=^wIW-tFPfH?@F(x(61oaa)4%po$oN=n@q{G$G?QYq&aaeX1W%v!`K4a4#ep zP_WO#H4u-u(l08D&kr}aE#Z`iJb*7flobgc{hg+-9&9zt4$(SJ!*Hd=LhK(bjJ^a2 zR`Ol#t@-qU{sg}uvD|Lm{S6kf3W%A>x6;Mz__(OY2$gK8acO!a;7cV?D_kjZ>wTpr zgUS!n8;;ufaikTIf||Zxg1HT5$#G<74f*Q0LDmJ7Cogs^C!o$nlJ=;U8b!qDOcW8A zWlj2QKuw7CGwohS1Z^{p;}dR%7$Ynid}$X}r~%GkAzb)R=gyx_Q)K527a^3) z-_i8`*hKYatRnCNZ>Ax+yKXH`2R!%~e?iTT+pV&4BMgbqN*wtOdYGncVrZ;TT~91c z1d&Br64GD4)cH}f?&<%^I~|b`^{$TGZXBXkFH|ZsmUWgtgdXBg8_H%@hi$m>g7Ug( z^^{O71jmGh(u);Z1>P)#lLXUq2K#YPdXcpj$_kxnHYp$pqWaI!U*!BFy&6qO;BWs_ z#EK~ro~5V!a)CUIx6=E2EbIMyDavSabCcYu{?e$Xc=IOM$P>zhx#+ME{xPLCxvPp$ z>q-;RW-(-fqL*V;%{DaxoCGG2AQq*e;rB7 z_1zj>G`UpK1ozbZnTm+28OWD4sxn)UX4mi1J?*aV8qMx8Mca=N^&Pn6im7DA} z5yoAh_%74u9O;Dj72pL+FeDeePyqgGs07)9r+^oByVYOlCi(tVI-Lwwu@A0|Z@x>i zgm+&jGGbDe4gKlqyB&(daUB2Cg#Bsy>iUBAe)Xbe3pN1Hw3bDO1?p2$>1 zHx(4vU0Wri;0F)W0pkIV0_4bp7vJQ!8}iDs+E0f^jFDSMJzh<>BX#!7TKrc0dSf?e zKHt=p)7Clk?RAZ@ypsTz)~6i23p$yiQ^&=;BEzAzZkF zMzeG0&i7MS9AAo@&q>L3PiSRlN9l)-``qymubA;ypC#`-;Z+~U?c?xftNo3n8}mVO zN!z2*#L%0!G(q9JYpxRoLF3)JR8Ul8h43Jb-Wx478a&r6N->~ugYF^-?Phg(Be@3< z>{0d9?Tf&T{l-3?g6T04k*P58AQ~5R5x!vKf}dF4()az_;`IyDy|OgII=AcRF)n%; z{t4a1=HCeVoG&ZmQbMcNPc+R z$@+{~2>cSPjhTzOpVN4GQ8?XxB(l+Z_{j|E;`Jgw1M@_Y7a z^wCe}5U?>E%b;;S^%^JD4`b^7LqC8RgI=QX+)iv5 z33p#WW(RBHV5X;`k2>s3?*mtTLLf)0-m|})o(vY3*zL&jI7uCR`b0h-F3?_e=PAv3 zSFs%;FA%#z6VYJQ$h%nUVOqa6G<6UmeUyJJ1Wfov9>`=2z>en# zRg+f6$PTiif>IkGZ(;MLK{SEJA_$H7ih!E$tNB5{x=g5`k2prVeeo|20#|ZKss`zk8$X{iV~0{$!qR(ZBpdByzt<@7AI zf%*zLVSl|Bxu#b18}};2+S1scy4lFp<@?fmzlYj8bovY@D8IVB{mRg;<@{*^1U` zFPwGy37U_7HQe~pLTJ+WY`wa~7{O7%@_TP-gct0yOG$iHWAUd?270j_7hZD1_s;}( z^z)Mvi{43&@c3kwQP6A;kN2f1A<{Q1vMGt@)Bxw)pC4@lsmY8K9M8B`@Q8kOl?y}Q zTETk);(ewMErM7A+5W>2_-C^Y0@;2?04Wn`6}qOFYmWEyP8IGBpKjvlg%t%O^b^41 z&(#=MV|gRzvrW~i7+-Pu}fQ%<|hV$16S$bHiAC%JL?iXEJ4JG z$6XE!7vNeiqRAq-zxw`IK*SAP<(vo@BMo(fXUd8pi;Q$AyE_f@7B|Bkox_A8VrLC) zy{l7bpza0-*?EB}NMQ$o)8>mKIVWB;p7l6=bccN=?YVJyU5_=%wB|x*A;B)z>Wa~^ z6u&Y;k1jBR7`{A@P}?tb#Wwdf6!B@ubimg-?n}P@z~1z`(037S%zzkn??peDCCcT? z0vDs<9hl!hzV*m@#sb>WOv-~yu|3e&)Xm@#-wa&Vzccn)l~2Gvle6(x*Zj~cM7~m$ zAz!H`X_VH>YjiO>X7q}KXz+DHx@2tSdHu{?u5@;bFT{W1u9`e#ap9d|3c70CUjId`Dg;3h&PL28ICMRNsm%}UN@;AKxsX^ImjjR>;_4aawJn8}AZ!*|AG@lHgcC~uoz znweB$r6iX<+TMB@w8#GV%BkGOding|Ap9Ip;*g}`(S4<9Jr;ty!)A-iAV`1;n)>I{ zpu>ihQWXf{!ku3Vd8B(-b#+WCP5B+QH|g48IMMGzUzZ!xk3qxaXa`?#rYW1NkUZ+u4i0h5Sd zyK8N-RRonUg2juwcY&-geTUyszl}7iw$4!R8d&2fDG^kyB?K>J-xAV=;H)@hOu<(9 zDraGSe3jT;!2#=>#@h3%>t9Yuqcsd8KLR8i8QiMv^h6NBeKCOc@1%1uQ$E=QIJ-;3 zN;$9krD$4JV#@KM>)l&AS&sSq>n|UHe5Q$TjkGFC0EQ)Ipt2_vg273EM2Dp)UJ(Q} zP#eRqPkwJLG>RM7NFO95(liNn1AmL1g9XjJQ|}s|8urbMorKZwi&5SB(3b^0SZxNv zqb*-py`Cip{s=uG{Cado+Evkqtmd7Rch?jQ@Dkx=HsZ+3ZvLe@rlkBqu0QtUAk){) zY+VXof0X`F9+VzcytfAI6Q(*ORr?O}ARR}(DhWDH!c4ickSNWaRT!`{!taQD@%g#% z=YT`ZCixuvb-=yRLsr^l)tj1#%dR-3_0O0}sx%>w{8*|F>I}i`(;odxjrReD6@hA# z>i!;9*T+%pQn}c5IfA}AtGQY9xb(dpOD}#K-Bz#eeuwQuqEbOuJih?i%`)a-cx2xX z*5sln__$i|1^3t5LP~?wY)%a2>U3|~-8`=+1`I%0XA96?f>)|VE)UoW`GkEaC}z2FuQ;pP|N<#{13qy2)1i-#Wz?BZl)YY%eaa0Njiw$_fW9Ja1t z7ZCDG+{)bE74&~FI9j`M0G%vB94;VhTPH^jAlMDrbmg#cv*K{I^#+M^b8&I~lMIp% zP1lE`VhIdtbJW)*KKoFi4!|U*>c*cL3Y};j(f8IlF-z zfnLZR`~$D8qbmfdBhUtfT$cOa7~C8{jt~xz0~q4P;Q)fzI9a;>s}=s5@o#~@SvhPS z-JR_IRjL1t-xX}`;Rv$ifY`Wz%>S>JFo*mxHqucLq^Gp?)n&y0Rms1$^#9`5l~UG` z5&!?x`EPy)a~C`0{QuGXZ-4&ZtmES31o^*^LVDnDds!nx?LQIsKg<2Aq3xZ3c0eab z2+}owjNstpXbW+2`Qvktqq&7W$nxL9$nifx^gov7u(x%vg@|+W2>pXKoGjjRnA;;) z<8XzT1MN8e8(NkiFvR8`4gRkpw#e z`cKaLFO!Fpi`^e?nAJAnR({p$|?kL(lR`v-gdmj~>G zRM++Y&l@gojvUrN4x|T>?*D@sZuUqaTckrl4o)s!|C8|lx~cy< getDevices() { List devices = new ArrayList<>(); @@ -130,12 +130,12 @@ public List getDevices() { } return devices; } - + @Override public String getIp() { return NetworkUtil.getIPv4HostAddress().getHostAddress(); } - + @Override public boolean power(boolean on) { Logger.trace("Switching Power " + (on ? "On" : "Off")); @@ -143,7 +143,7 @@ public boolean power(boolean on) { this.power = on; Logger.trace("Power is " + (power ? "On" : "Off")); PowerEvent pe = new PowerEvent(this.power); - + executor.execute(() -> fireAllPowerEventListeners(pe)); synchronized (this) { notifyAll(); @@ -152,22 +152,22 @@ public boolean power(boolean on) { } else { return false; } - + } - + private void fireAllPowerEventListeners(final PowerEvent powerEvent) { for (PowerEventListener listener : powerEventListeners) { listener.onPowerChange(powerEvent); } } - + @Override public void changeDirection(int locUid, LocomotiveBean.Direction direction) { if (this.power && this.connected) { Logger.debug("locUid " + locUid + " direction " + direction); - + LocomotiveDirectionEvent lde = new LocomotiveDirectionEvent(locUid, direction, commandStationBean.getId()); - + notifyLocomotiveDirectionEventListeners(lde); } else { if (!this.power) { @@ -175,11 +175,11 @@ public void changeDirection(int locUid, LocomotiveBean.Direction direction) { } } } - + private void notifyLocomotiveDirectionEventListeners(final LocomotiveDirectionEvent directionEvent) { executor.execute(() -> fireAllDirectionEventListeners(directionEvent)); } - + private void fireAllDirectionEventListeners(final LocomotiveDirectionEvent directionEvent) { if (directionEvent.isValid()) { for (LocomotiveDirectionEventListener listener : this.locomotiveDirectionEventListeners) { @@ -187,12 +187,12 @@ private void fireAllDirectionEventListeners(final LocomotiveDirectionEvent direc } } } - + @Override public void changeVelocity(int locUid, int speed, LocomotiveBean.Direction direction) { if (this.power && connected) { Logger.debug("locUid " + locUid + " speed " + speed); - + LocomotiveSpeedEvent lse = new LocomotiveSpeedEvent(locUid, speed, commandStationBean.getId()); executor.execute(() -> { fireAllLocomotiveSpeedEventListeners(lse); @@ -210,7 +210,7 @@ public void changeVelocity(int locUid, int speed, LocomotiveBean.Direction direc } } } - + private void fireAllLocomotiveSpeedEventListeners(final LocomotiveSpeedEvent speedEvent) { if (speedEvent.isValid()) { for (LocomotiveSpeedEventListener listener : this.locomotiveSpeedEventListeners) { @@ -218,7 +218,7 @@ private void fireAllLocomotiveSpeedEventListeners(final LocomotiveSpeedEvent spe } } } - + @Override public void changeFunctionValue(int locUid, int functionNumber, boolean flag) { if (this.power && connected) { @@ -231,7 +231,7 @@ public void changeFunctionValue(int locUid, int functionNumber, boolean flag) { } } } - + private void fireAllFunctionEventListeners(final LocomotiveFunctionEvent functionEvent) { if (functionEvent.isValid()) { for (LocomotiveFunctionEventListener listener : this.locomotiveFunctionEventListeners) { @@ -239,42 +239,42 @@ private void fireAllFunctionEventListeners(final LocomotiveFunctionEvent functio } } } - + @Override public List getLocomotives() { throw new UnsupportedOperationException("Not supported yet."); } - + @Override public Image getLocomotiveImage(String icon) { throw new UnsupportedOperationException("Not supported yet."); } - + @Override public Image getLocomotiveFunctionImage(String icon) { throw new UnsupportedOperationException("Not supported yet."); } - + @Override public boolean isSupportTrackMeasurements() { return false; } - + @Override public Map getTrackMeasurements() { throw new UnsupportedOperationException("Not supported yet."); } - + @Override public void switchAccessory(Integer address, AccessoryBean.AccessoryValue value) { switchAccessory(address, value, 200); } - + @Override public void switchAccessory(String id, AccessoryBean.AccessoryValue value) { throw new UnsupportedOperationException("Not supported yet."); } - + @Override public void switchAccessory(Integer address, AccessoryBean.AccessoryValue value, Integer switchTime) { if (this.power && connected) { @@ -289,37 +289,40 @@ public void switchAccessory(Integer address, AccessoryBean.AccessoryValue value, } ab.setId(id); ab.setCommandStationId(commandStationBean.getId()); - + AccessoryEvent ae = new AccessoryEvent(ab); - executor.execute(() -> fireAllAccessoryEventListeners(ae)); + //executor.execute(() -> fireAllAccessoryEventListeners(ae)); + Logger.trace("Switched accessory " + id + " to " + value.getValue()); + fireAllAccessoryEventListeners(ae); } else { if (!this.power) { Logger.warn("Can't switch accessory " + address + " to: " + value + " Power is OFF!"); } } } - + private void fireAllAccessoryEventListeners(final AccessoryEvent accessoryEvent) { for (AccessoryEventListener listener : this.accessoryEventListeners) { listener.onAccessoryChange(accessoryEvent); + Logger.trace("Fired accessory listener " + accessoryEvent.getId()); } } - + @Override public List getAccessories() { throw new UnsupportedOperationException("Not supported yet."); } - + @Override public DeviceBean getFeedbackDevice() { throw new UnsupportedOperationException("Not supported yet."); } - + @Override public List getFeedbackModules() { throw new UnsupportedOperationException("Not supported yet."); } - + @Override public synchronized void fireSensorEventListeners(final SensorEvent sensorEvent) { for (SensorEventListener listener : sensorEventListeners) { @@ -328,14 +331,14 @@ public synchronized void fireSensorEventListeners(final SensorEvent sensorEvent) } } } - + @Override public void simulateSensor(SensorEvent sensorEvent) { List acl = JCS.getJcsCommandStation().getFeedbackControllers(); - + for (FeedbackController fbc : acl) { fbc.fireSensorEventListeners(sensorEvent); } } - + } diff --git a/src/main/java/jcs/persistence/H2PersistenceService.java b/src/main/java/jcs/persistence/H2PersistenceService.java index 6b4e8534..0409ec81 100755 --- a/src/main/java/jcs/persistence/H2PersistenceService.java +++ b/src/main/java/jcs/persistence/H2PersistenceService.java @@ -611,12 +611,13 @@ public synchronized TileBean persist(TileBean tileBean) { if (tileBean == null) { return null; } - TileBean tb; - if (tileBean instanceof Tile tile) { - tb = tile.getTileBean(); - } else { - tb = tileBean; - } +// //TODO + TileBean tb = null; +// if (tileBean instanceof Tile tile) { +// tb = tile.getTileBean(); +// } else { +// tb = tileBean; +// } if (tb != null && tb.getId() != null) { if (database.where("id=?", tb.getId()).first(TileBean.class) != null) { diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.java b/src/main/java/jcs/ui/layout/LayoutCanvas.java index 40a5407e..fa7d4a8c 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.java +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.java @@ -30,15 +30,11 @@ import java.awt.image.BufferedImage; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import java.util.HashMap; import java.util.HashSet; -import java.util.LinkedList; import java.util.List; -import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.stream.Collectors; import javax.swing.JFrame; import javax.swing.JMenuItem; import javax.swing.JPanel; @@ -52,14 +48,10 @@ import jcs.entities.BlockBean; import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; -import jcs.entities.RouteElementBean; import jcs.entities.SensorBean; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; -import static jcs.entities.TileBean.Orientation.EAST; -import static jcs.entities.TileBean.Orientation.SOUTH; -import static jcs.entities.TileBean.Orientation.WEST; import static jcs.entities.TileBean.TileType.BLOCK; import static jcs.entities.TileBean.TileType.CROSS; import static jcs.entities.TileBean.TileType.CURVED; @@ -114,14 +106,14 @@ public enum Mode { private final ExecutorService executor; - private final Map tiles; - private final Map altTiles; +// private final Map tiles; +// private final Map altTiles; private final Set selectedTiles; private Tile selectedTile; private RoutesDialog routesDialog; - private final Map selectedRouteElements; + //private final Map selectedRouteElements; private Point movingTileCenterPoint; private BufferedImage movingTileImage; @@ -132,11 +124,11 @@ public LayoutCanvas() { public LayoutCanvas(boolean readonly) { this.readonly = readonly; - this.tiles = new HashMap<>(); - this.altTiles = new HashMap<>(); +// this.tiles = new HashMap<>(); +// this.altTiles = new HashMap<>(); this.selectedTiles = new HashSet<>(); - this.selectedRouteElements = new HashMap<>(); +// this.selectedRouteElements = new HashMap<>(); this.executor = Executors.newSingleThreadExecutor(); //this.executor = Executors.newCachedThreadPool(); @@ -156,8 +148,11 @@ private void postInit() { @Override protected void paintComponent(Graphics g) { + long started = System.currentTimeMillis(); + super.paintComponent(g); + Graphics2D g2 = (Graphics2D) g.create(); - Set snapshot = new HashSet<>(tiles.values()); + Set snapshot = new HashSet<>(TileCache.tiles.values()); if (this.drawGrid) { if (lineGrid) { @@ -170,7 +165,8 @@ protected void paintComponent(Graphics g) { } for (Tile tile : snapshot) { - tile.setDrawOutline(drawGrid); + //for (Tile tile : TileCache.tiles.values()) { + //tile.setDrawOutline(drawGrid); if (Mode.CONTROL != mode) { if (selectedTiles.contains(tile.getCenter())) { @@ -181,11 +177,11 @@ protected void paintComponent(Graphics g) { } } - tile.drawTile(g2, drawGrid); + tile.drawTile(g2); //debug - if (!this.readonly) { - tile.drawCenterPoint(g2, Color.magenta, 3); - } +// if (!this.readonly) { +// tile.drawCenterPoint(g2, Color.magenta, 3); +// } } if (this.movingTileCenterPoint != null && this.movingTileImage != null) { @@ -197,13 +193,18 @@ protected void paintComponent(Graphics g) { } g2.dispose(); + + long now = System.currentTimeMillis(); + Logger.trace("Duration: " + (now - started) + " ms."); } @Override public void propertyChange(PropertyChangeEvent evt) { if ("repaintTile".equals(evt.getPropertyName())) { Tile tile = (Tile) evt.getNewValue(); - this.repaint(tile.getBounds()); + + Logger.trace("Repainting Tile: " + tile.getId()); + repaint(tile.getBounds()); } } @@ -331,79 +332,101 @@ void setDirection(Direction direction) { void loadLayoutInBackground() { this.executor.execute(() -> loadTiles()); + +// new Thread(new Runnable() { +// public void run() { +// final String text = readHugeFile(); +// SwingUtilities.invokeLater(new Runnable() { +// public void run() { +// canvas.setTiles(); +// } +// }); +// } +// }).start(); } - public void loadTiles() { + private void loadTiles() { boolean showValues = Mode.CONTROL.equals(mode); + TileCache.loadTiles(this); + TileCache.setShowValues(showValues); + //TileCache.setDrawOutline(drawGrid); + TileCache.setDrawCenterPoint(!this.readonly); - List tileBeans = PersistenceFactory.getService().getTileBeans(); - +// List tileBeans = PersistenceFactory.getService().getTileBeans(); selectedTiles.clear(); - altTiles.clear(); - tiles.clear(); - selectedRouteElements.clear(); - - for (TileBean tb : tileBeans) { - Tile tile = TileFactory.createTile(tb, drawGrid, showValues); - tile.setPropertyChangeListener(this); - tiles.put(tile.getCenter(), tile); - - //Alternative point(s) to be able to find all points - if (!tile.getAltPoints().isEmpty()) { - Set alt = tile.getAltPoints(); - for (Point ap : alt) { - altTiles.put(ap, tile); - } - } +// altTiles.clear(); +// tiles.clear(); +// selectedRouteElements.clear(); + +// for (TileBean tb : tileBeans) { +// Tile tile = TileFactory.createTile(tb, drawGrid, showValues); +// tile.setPropertyChangeListener(this); +// tiles.put(tile.getCenter(), tile); +// +// //Alternative point(s) to be able to find all points +// if (!tile.getAltPoints().isEmpty()) { +// Set alt = tile.getAltPoints(); +// for (Point ap : alt) { +// altTiles.put(ap, tile); +// } +// } +// } +// Logger.debug("Loaded " + tiles.size() + " Tiles..."); + for (Tile tile : TileCache.tiles.values()) { + this.add(tile); } - Logger.debug("Loaded " + tiles.size() + " Tiles..."); + repaint(); } - public void saveLayout() { + void saveLayout() { //Create a snapshot as persisting is done in worker thread - Set snapshot = new HashSet<>(tiles.values()); +// Set snapshot = new HashSet<>(tiles.values()); this.selectedTiles.clear(); - this.executor.execute(() -> saveTiles(snapshot)); - } - - private synchronized void saveTiles(Set snapshot) { - Logger.debug("Saving " + snapshot.size() + " tiles..."); - List beans = new LinkedList<>(); +// this.executor.execute(() -> saveTiles(snapshot)); - for (Tile tile : snapshot) { - if (tile != null) { - TileBean tb = tile.getTileBean(); - Logger.trace("Saving " + tile + " -> " + tb); - beans.add(tb); - } else { - Logger.warn("Tile is null?"); - } - } - PersistenceFactory.getService().persist(beans); + this.executor.execute(() -> TileCache.saveTiles()); } +// private synchronized void saveTiles(Set snapshot) { +// TileCache.saveTiles(); +// +// Logger.debug("Saving " + snapshot.size() + " tiles..."); +// List beans = new LinkedList<>(); +// +// for (Tile tile : snapshot) { +// if (tile != null) { +// TileBean tb = tile.getTileBean(); +// Logger.trace("Saving " + tile + " -> " + tb); +// beans.add(tb); +// } else { +// Logger.warn("Tile is null?"); +// } +// } +// PersistenceFactory.getService().persist(beans); +// } private void saveTile(final Tile tile) { - if (tile != null) { - TileBean tb = tile.getTileBean(); - this.executor.execute(() -> PersistenceFactory.getService().persist(tb)); - } else { - Logger.warn("Tile is null?"); - } - } - - private void deleteTile(final Tile tile) { - if (tile != null) { - TileBean tb = tile.getTileBean(); - this.executor.execute(() -> PersistenceFactory.getService().remove(tb)); - } else { - Logger.warn("Tile is null?"); - } +// if (tile != null) { +// TileBean tb = tile.getTileBean(); +// this.executor.execute(() -> PersistenceFactory.getService().persist(tb)); + this.executor.execute(() -> TileCache.saveTile(tile)); +// } else { +// Logger.warn("Tile is null?"); +// } } +// private void deleteTile(final Tile tile) { +// if (tile != null) { +// TileBean tb = tile.getTileBean(); + //this.executor.execute(() -> PersistenceFactory.getService().remove(tb)); +// this.executor.execute(() -> TileCache.deleteTile(tile)); +// } else { +// Logger.warn("Tile is null?"); +// } +// } private void mouseMoveAction(MouseEvent evt) { Point sp = LayoutUtil.snapToGrid(evt.getPoint()); - Tile tile = findTile(sp); + Tile tile = TileCache.findTile(sp); if (tile != null) { setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)); } else { @@ -415,7 +438,8 @@ private Tile getSelectedTile() { Tile t = null; if (!selectedTiles.isEmpty()) { for (Point p : this.selectedTiles) { - t = tiles.get(p); + //t = tiles.get(p); + t = TileCache.tiles.get(p); if (t != null) { return t; } @@ -426,7 +450,7 @@ private Tile getSelectedTile() { private void mousePressedAction(MouseEvent evt) { Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); - Tile tile = findTile(snapPoint); + Tile tile = TileCache.findTile(snapPoint); //Clear any previous selection selectedTiles.clear(); @@ -471,9 +495,13 @@ private void mousePressedAction(MouseEvent evt) { if (MouseEvent.BUTTON3 == evt.getButton() && tile != null) { showOperationsPopupMenu(tile, snapPoint); } + repaint(); } case DELETE -> { - removeTiles(selectedTiles); + //removeTiles(selectedTiles); + TileCache.removeTiles(selectedTiles); + this.selectedTiles.clear(); + repaint(); } default -> { Logger.trace((tile != null ? "Selected tile: " + tile.getId() + ", " + tile.xyToString() : "No tile selected")); @@ -486,7 +514,6 @@ private void mousePressedAction(MouseEvent evt) { } } } - repaint(); } private void mouseDragAction(MouseEvent evt) { @@ -502,23 +529,23 @@ private void mouseDragAction(MouseEvent evt) { repaint(); } - private boolean checkTileOccupation(Tile tile) { - Set tilePoints = tile.getAllPoints(); - for (Point p : tilePoints) { - if (tiles.containsKey(p) || altTiles.containsKey(p)) { - //The is a match, check if it is an other tile - Tile mt = this.findTile(p); - if (tile.getId().equals(mt.getId())) { - //same tile continue - } else { - //Other tile so really occupied - return true; - } - } - } - return false; - } - +// private boolean checkTileOccupation(Tile tile) { +// Set tilePoints = tile.getAllPoints(); +// for (Point p : tilePoints) { +// if (tiles.containsKey(p) || altTiles.containsKey(p)) { +// //The is a match, check if it is an other tile +// Tile mt = this.findTile(p); +// if (tile.getId().equals(mt.getId())) { +// //same tile continue +// } else { +// //Other tile so really occupied +// return true; +// } +// } +// } +// return false; +// return TileCache.checkTileOccupation(tile); +// } private void mouseReleasedAction(MouseEvent evt) { Tile selTile = getSelectedTile(); if (selTile != null) { @@ -533,8 +560,9 @@ private void mouseReleasedAction(MouseEvent evt) { Logger.tag("Moving Tile from " + tp + " to " + snapPoint + " Tile to move: " + selTile); //Check if new position is free boolean canMove = true; - if (tiles.containsKey(snapPoint) || altTiles.containsKey(snapPoint)) { - Tile tile = findTile(snapPoint); + //if (tiles.containsKey(snapPoint) || altTiles.containsKey(snapPoint)) { + if (TileCache.containsPoint(snapPoint)) { + Tile tile = TileCache.findTile(snapPoint); if (selTile.getId().equals(tile.getId())) { //same tile so we can move canMove = true; @@ -546,48 +574,50 @@ private void mouseReleasedAction(MouseEvent evt) { if (canMove) { //Remove the original tile center from the tiles - Tile movingTile = tiles.remove(tp); + Tile movingTile = TileCache.tiles.remove(tp); if (movingTile != null) { //Also remove from the alt points Point oldCenter = movingTile.getCenter(); Set oldAltPoints = movingTile.getAltPoints(); //Logger.trace("Removing " + oldAltPoints.size() + " alt tile points"); for (Point ep : oldAltPoints) { - altTiles.remove(ep); - tiles.remove(ep); + TileCache.altTiles.remove(ep); + TileCache.tiles.remove(ep); } //Set the new center position movingTile.setCenter(snapPoint); //Check again, needed for tiles which are longer then 1 square, like a block - if (!checkTileOccupation(movingTile)) { + if (!TileCache.checkTileOccupation(movingTile)) { Logger.trace("Moved Tile " + movingTile.getId() + " from " + tp + " to " + snapPoint + "..."); - tiles.put(snapPoint, movingTile); + TileCache.tiles.put(snapPoint, movingTile); for (Point ep : movingTile.getAltPoints()) { - altTiles.put(ep, movingTile); + TileCache.altTiles.put(ep, movingTile); } selectedTiles.clear(); selectedTiles.addAll(movingTile.getAllPoints()); } else { //Do not move Tile, put back where it was movingTile.setCenter(oldCenter); - tiles.put(oldCenter, movingTile); + TileCache.tiles.put(oldCenter, movingTile); for (Point ep : movingTile.getAltPoints()) { - altTiles.put(ep, movingTile); + TileCache.altTiles.put(ep, movingTile); } } - if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { - this.saveTile(movingTile); - } + //if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { + //this.saveTile(movingTile); + TileCache.saveTile(movingTile); + //} } + repaint(); } } } movingTileImage = null; movingTileCenterPoint = null; - repaint(); + //repaint(); } private void executeControlActionForTile(Tile tile, Point p) { @@ -607,7 +637,7 @@ private void executeControlActionForTile(Tile tile, Point p) { BlockControlDialog bcd = new BlockControlDialog(getParentFrame(), block); bcd.setVisible(true); - this.repaint(block.getX(), block.getY(), block.getWidth(), block.getHeight()); + //this.repaint(block.getX(), block.getY(), block.getWidth(), block.getHeight()); } case SIGNAL -> this.executor.execute(() -> toggleSignal((Signal) tile)); @@ -625,10 +655,10 @@ private void toggleSwitch(Switch turnout) { if (turnout.getAccessoryBean() != null) { AccessoryBean ab = turnout.getAccessoryBean(); ab.toggle(); - turnout.setValue(ab.getAccessoryValue()); + turnout.setAccessoryValue(ab.getAccessoryValue()); JCS.getJcsCommandStation().switchAccessory(ab, ab.getAccessoryValue()); - repaint(turnout.getX(), turnout.getY(), turnout.getWidth(), turnout.getHeight()); + //repaint(turnout.getX(), turnout.getY(), turnout.getWidth(), turnout.getHeight()); } else { Logger.trace("No AccessoryBean configured for Turnout: " + turnout.getId()); } @@ -641,7 +671,7 @@ private void toggleSignal(Signal signal) { Logger.trace("A: " + ab.getAddress() + " S: " + ab.getStates() + " P: " + ab.getState()); JCS.getJcsCommandStation().switchAccessory(ab, ab.getAccessoryValue()); - repaint(signal.getX(), signal.getY(), signal.getWidth(), signal.getHeight()); + //repaint(signal.getX(), signal.getY(), signal.getWidth(), signal.getHeight()); } else { Logger.trace("No AccessoryBean configured for Signal: " + signal.getId()); } @@ -653,11 +683,8 @@ private void toggleSensor(Sensor sensor) { sb.toggle(); sensor.setActive((sb.getStatus() == 1)); Logger.trace("id: " + sb.getId() + " state " + sb.getStatus()); - - sensor.repaintTile(); - + //sensor.repaintTile(); SensorEvent sensorEvent = new SensorEvent(sb); - //this.executor.execute(() -> fireFeedbackEvent(sensorEvent)); fireFeedbackEvent(sensorEvent); } } @@ -679,7 +706,7 @@ private void editSelectedTileProperties() { if (!this.selectedTiles.isEmpty()) { Point tcp = this.selectedTiles.iterator().next(); - Tile tile = findTile(tcp); + Tile tile = TileCache.findTile(tcp); TileBean.TileType tt = tile.getTileType(); Logger.trace("Seleted tile " + tile.getId() + " TileType " + tt); @@ -725,9 +752,8 @@ private void editSelectedTileProperties() { default -> { } } + repaint(); } - //this.executor.execute(() -> repaint()); - repaint(); } private void showBlockPopupMenu(Tile tile, Point p) { @@ -765,8 +791,10 @@ private void showOperationsPopupMenu(Tile tile, Point p) { //which items should be shown boolean showProperties = false; boolean showFlip = false; + @SuppressWarnings("UnusedAssignment") boolean showRotate = false; boolean showMove = false; + @SuppressWarnings("UnusedAssignment") boolean showDelete = false; TileBean.TileType tt = tile.getTileType(); @@ -823,52 +851,50 @@ private void showOperationsPopupMenu(Tile tile, Point p) { this.operationsPM.show(this, p.x, p.y); } - public Tile findTile(Point cp) { - Tile result = this.tiles.get(cp); - if (result == null) { - //Logger.trace("Using alternative points..."); - result = this.altTiles.get(cp); - if (result != null) { - //Logger.trace("Found " + result + " in alt tiles"); - } - } - return result; - } - - private Point getCheckAvailable(Point newPoint) { - if (this.tiles.containsKey(newPoint)) { - Tile et = this.tiles.get(newPoint); - Logger.debug("@ " + newPoint + " is allready occcupied by: " + et + "..."); - //Search for the nearest avalaible free point - //first get the Center point of the tile which is occuping this slot - // show warning! - Point ecp = et.getCenter(); - - int w = et.getWidth(); - int h = et.getHeight(); - - Point np; - np = switch (this.orientation) { - case EAST -> - new Point(ecp.x + w, ecp.y); - case WEST -> - new Point(newPoint.x - w, ecp.y); - case SOUTH -> - new Point(ecp.x, newPoint.y + h); - default -> - new Point(ecp.x, newPoint.y - h); - }; - - Logger.trace("Alternative CP: " + np); - // recursive check - return getCheckAvailable(np); - } else { - Logger.debug("@ " + newPoint + " is not yet used..."); - - return newPoint; - } - } - +// public Tile findTile(Point cp) { +// Tile result = this.tiles.get(cp); +// if (result == null) { +// //Logger.trace("Using alternative points..."); +// result = this.altTiles.get(cp); +// if (result != null) { +// //Logger.trace("Found " + result + " in alt tiles"); +// } +// } +// return result; +// } +// private Point getCheckAvailable(Point newPoint) { +// if (this.tiles.containsKey(newPoint)) { +// Tile et = this.tiles.get(newPoint); +// Logger.debug("@ " + newPoint + " is allready occcupied by: " + et + "..."); +// //Search for the nearest avalaible free point +// //first get the Center point of the tile which is occuping this slot +// // show warning! +// Point ecp = et.getCenter(); +// +// int w = et.getWidth(); +// int h = et.getHeight(); +// +// Point np; +// np = switch (this.orientation) { +// case EAST -> +// new Point(ecp.x + w, ecp.y); +// case WEST -> +// new Point(newPoint.x - w, ecp.y); +// case SOUTH -> +// new Point(ecp.x, newPoint.y + h); +// default -> +// new Point(ecp.x, newPoint.y - h); +// }; +// +// Logger.trace("Alternative CP: " + np); +// // recursive check +// return getCheckAvailable(np); +// } else { +// Logger.debug("@ " + newPoint + " is not yet used..."); +// +// return newPoint; +// } +// } private Tile addTile(Point p) { if (this.orientation == null) { this.orientation = Orientation.EAST; @@ -879,41 +905,41 @@ private Tile addTile(Point p) { } Logger.trace("Adding: " + tileType + " @ " + p); - Point chkp = getCheckAvailable(p); + Point chkp = TileCache.checkAvailable(p, this.orientation); boolean fullRepaint = !chkp.equals(p); Tile tile = TileFactory.createTile(tileType, orientation, direction, chkp, drawGrid); //Can the tile be placed, keeping in mind the extra points - boolean canBeAdded = true; - if (!tile.getAltPoints().isEmpty()) { - //Check if the extra point positions are not occupied - Set tilePoints = tile.getAllPoints(); - - for (Point tp : tilePoints) { - if (tiles.containsKey(tp) || altTiles.containsKey(tp)) { - Logger.trace("Point " + p + " occupied by " + findTile(p).getId() + " Can't add new Tile: " + tile); - canBeAdded = false; - } - } - } - + boolean canBeAdded = TileCache.checkTileOccupation(tile); + +// if (!tile.getAltPoints().isEmpty()) { +// //Check if the extra point positions are not occupied +// Set tilePoints = tile.getAllPoints(); +// +// for (Point tp : tilePoints) { +// if (TileCache.containsPoint(tp)) { +// Logger.trace("Point " + p + " occupied by " + TileCache.findTile(p).getId() + " Can't add new Tile: " + tile); +// canBeAdded = false; +// } +// } +// } if (canBeAdded) { - tiles.put(chkp, tile); - //Alternative point(s) to be able to find all points - if (!tile.getAltPoints().isEmpty()) { - Set alt = tile.getAltPoints(); - for (Point ap : alt) { - this.altTiles.put(ap, tile); - } - } - - if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { - this.saveTile(tile); - } - + TileCache.addTile(tile); + +// TileCache.tiles.put(chkp, tile); +// //Alternative point(s) to be able to find all points +// if (!tile.getAltPoints().isEmpty()) { +// Set alt = tile.getAltPoints(); +// for (Point ap : alt) { +// TileCache.altTiles.put(ap, tile); +// } +// } +// +// if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { +// this.saveTile(tile); +// } Logger.trace("Added Tile " + tile.getClass().getSimpleName() + " " + tile.getOrientation() + " @ " + tile.getCenter() + " Full repaint: " + fullRepaint); - Logger.trace("Added " + tile + " There are now " + this.tiles.size() + " tiles..."); } if (fullRepaint) { @@ -928,30 +954,32 @@ private Tile addTile(Point p) { } void removeTiles() { - removeTiles(selectedTiles); - } - - private void removeTiles(Set pointsToRemove) { - for (Point p : pointsToRemove) { - Tile removed = this.tiles.remove(p); - - if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { - this.deleteTile(removed); - } - - if (removed != null && removed.getAllPoints() != null) { - Set rps = removed.getAltPoints(); - //Also remove alt points - for (Point ap : rps) { - tiles.remove(ap); - } - - Logger.trace("Removed: " + removed); - } - } - selectedTiles.clear(); + TileCache.removeTiles(selectedTiles); + //removeTiles(selectedTiles); repaint(); } +// private void removeTiles(Set pointsToRemove) { +// TileCache.removeTiles(pointsToRemove); +// for (Point p : pointsToRemove) { +// Tile removed = TileCache.tiles.remove(p); +// +// if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { +// this.deleteTile(removed); +// } +// +// if (removed != null && removed.getAllPoints() != null) { +// Set rps = removed.getAltPoints(); +// //Also remove alt points +// for (Point ap : rps) { +// tiles.remove(ap); +// } +// +// Logger.trace("Removed: " + removed); +// } +// } +// selectedTiles.clear(); +// repaint(); +// } private JFrame getParentFrame() { JFrame frame = (JFrame) SwingUtilities.getRoot(this); @@ -960,104 +988,111 @@ private JFrame getParentFrame() { public void rotateSelectedTile() { Logger.trace("Selected Tiles " + selectedTiles.size()); - - //make copy as the map could be cleared - Set snapshot = new HashSet<>(selectedTiles); - for (Point p : snapshot) { - Logger.trace("Selected Tile @ " + p); - if (this.tiles.containsKey(p)) { - Tile t = this.tiles.get(p); - //Remove the alternative or extra points... - for (Point ep : t.getAltPoints()) { - this.altTiles.remove(ep); - } - - t.rotate(); - Logger.trace("Rotated " + t); - this.orientation = t.getOrientation(); - this.direction = t.getDirection(); - - //override - this.tiles.put(p, t); - for (Point ep : t.getAltPoints()) { - this.altTiles.put(ep, t); - } - - this.selectedTiles.clear(); - this.selectedTiles.addAll(t.getAllPoints()); - - if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { - this.saveTile(t); - } - } - } + TileCache.rotateTile(selectedTiles); + +// //make copy as the map could be cleared +// Set snapshot = new HashSet<>(selectedTiles); +// +// for (Point p : snapshot) { +// Logger.trace("Selected Tile @ " + p); +// if (this.tiles.containsKey(p)) { +// Tile t = this.tiles.get(p); +// //Remove the alternative or extra points... +// for (Point ep : t.getAltPoints()) { +// this.altTiles.remove(ep); +// } +// +// t.rotate(); +// Logger.trace("Rotated " + t); +// this.orientation = t.getOrientation(); +// this.direction = t.getDirection(); +// +// //override +// this.tiles.put(p, t); +// for (Point ep : t.getAltPoints()) { +// this.altTiles.put(ep, t); +// } +// +// this.selectedTiles.clear(); +// this.selectedTiles.addAll(t.getAllPoints()); +// +// if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { +// this.saveTile(t); +// } +// } +// } repaint(); } public void flipSelectedTileHorizontal() { - Set snapshot = new HashSet<>(selectedTiles); - for (Point p : snapshot) { - Logger.trace("Selected Tile @ " + p); - if (this.tiles.containsKey(p)) { - Tile t = this.tiles.get(p); - //Remove the alternative or extra points... - for (Point ep : t.getAltPoints()) { - this.altTiles.remove(ep); - } - - t.flipHorizontal(); - Logger.trace("Flipped " + t); - this.orientation = t.getOrientation(); - this.direction = t.getDirection(); - - //override - this.tiles.put(p, t); - for (Point ep : t.getAltPoints()) { - this.altTiles.put(ep, t); - } - - if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { - this.saveTile(t); - } - - this.selectedTiles.clear(); - this.selectedTiles.addAll(t.getAllPoints()); - } - } - this.executor.execute(() -> repaint()); + TileCache.flipHorizontal(selectedTiles); +// Set snapshot = new HashSet<>(selectedTiles); +// for (Point p : snapshot) { +// Logger.trace("Selected Tile @ " + p); +// if (this.tiles.containsKey(p)) { +// Tile t = this.tiles.get(p); +// //Remove the alternative or extra points... +// for (Point ep : t.getAltPoints()) { +// this.altTiles.remove(ep); +// } +// +// t.flipHorizontal(); +// Logger.trace("Flipped " + t); +// this.orientation = t.getOrientation(); +// this.direction = t.getDirection(); +// +// //override +// this.tiles.put(p, t); +// for (Point ep : t.getAltPoints()) { +// this.altTiles.put(ep, t); +// } +// +// if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { +// this.saveTile(t); +// } +// +// this.selectedTiles.clear(); +// this.selectedTiles.addAll(t.getAllPoints()); +// } +// } +// this.executor.execute(() -> repaint()); + repaint(); } public void flipSelectedTileVertical() { - Set snapshot = new HashSet<>(selectedTiles); - for (Point p : snapshot) { - Logger.trace("Selected Tile @ " + p); - if (this.tiles.containsKey(p)) { - Tile t = this.tiles.get(p); - //Remove the alternative or extra points... - for (Point ep : t.getAltPoints()) { - this.altTiles.remove(ep); - } - - t.flipVertical(); - Logger.trace("Flipped " + t); - this.orientation = t.getOrientation(); - this.direction = t.getDirection(); - - //override - this.tiles.put(p, t); - for (Point ep : t.getAltPoints()) { - this.altTiles.put(ep, t); - } - - if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { - this.saveTile(t); - } - - this.selectedTiles.clear(); - this.selectedTiles.addAll(t.getAllPoints()); - } - } - this.executor.execute(() -> repaint()); + TileCache.flipVertical(selectedTiles); + +// Set snapshot = new HashSet<>(selectedTiles); +// for (Point p : snapshot) { +// Logger.trace("Selected Tile @ " + p); +// if (this.tiles.containsKey(p)) { +// Tile t = this.tiles.get(p); +// //Remove the alternative or extra points... +// for (Point ep : t.getAltPoints()) { +// this.altTiles.remove(ep); +// } +// +// t.flipVertical(); +// Logger.trace("Flipped " + t); +// this.orientation = t.getOrientation(); +// this.direction = t.getDirection(); +// +// //override +// this.tiles.put(p, t); +// for (Point ep : t.getAltPoints()) { +// this.altTiles.put(ep, t); +// } +// +// if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { +// this.saveTile(t); +// } +// +// this.selectedTiles.clear(); +// this.selectedTiles.addAll(t.getAllPoints()); +// } +// } +// this.executor.execute(() -> repaint()); + repaint(); } void routeLayout() { @@ -1066,11 +1101,12 @@ void routeLayout() { private void routeLayoutWithAStar() { //Make sure the layout is saved - Set snapshot = new HashSet<>(tiles.values()); - this.saveTiles(snapshot); + TileCache.saveTiles(); +// Set snapshot = new HashSet<>(tiles.values()); +// this.saveTiles(snapshot); AStar astar = new AStar(); - astar.buildGraph(this.tiles.values().stream().collect(Collectors.toList())); + astar.buildGraph(TileCache.getTiles()); astar.routeAll(); astar.persistRoutes(); if (this.routesDialog.isVisible()) { @@ -1360,7 +1396,9 @@ private void moveMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_moveMIAct }//GEN-LAST:event_moveMIActionPerformed private void deleteMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_deleteMIActionPerformed - this.removeTiles(selectedTiles); + //this.removeTiles(selectedTiles); + TileCache.removeTiles(selectedTiles); + this.selectedTiles.clear(); }//GEN-LAST:event_deleteMIActionPerformed private void propertiesMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_propertiesMIActionPerformed @@ -1396,8 +1434,10 @@ private void resetDispatcherMIActionPerformed(ActionEvent evt) {//GEN-FIRST:even Block block = (Block) selectedTile; LocomotiveBean locomotive = block.getBlockBean().getLocomotive(); - this.executor.execute(() -> AutoPilot.resetDispatcher(locomotive)); - repaint(); + this.executor.execute(() -> { + AutoPilot.resetDispatcher(locomotive); + repaint(); + }); } }//GEN-LAST:event_resetDispatcherMIActionPerformed @@ -1414,8 +1454,8 @@ private void removeLocMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_remo this.executor.execute(() -> { PersistenceFactory.getService().persist(block.getBlockBean()); PersistenceFactory.getService().persist(locomotive); + repaint(); }); - this.repaint(); } }//GEN-LAST:event_removeLocMIActionPerformed @@ -1441,8 +1481,10 @@ private void reverseArrivalSideMIActionPerformed(ActionEvent evt) {//GEN-FIRST:e block.getBlockBean().setArrivalSuffix("+"); } block.getBlockBean().setReverseArrival(!block.getBlockBean().isReverseArrival()); - this.executor.execute(() -> PersistenceFactory.getService().persist(block.getBlockBean())); - this.repaint(); + this.executor.execute(() -> { + PersistenceFactory.getService().persist(block.getBlockBean()); + block.repaintTile(); + }); } }//GEN-LAST:event_reverseArrivalSideMIActionPerformed @@ -1461,7 +1503,7 @@ private void toggleLocomotiveDirectionMIActionPerformed(ActionEvent evt) {//GEN- Logger.trace(block.getId() + " Logical changed from " + curDir + " to " + newDir + " for " + locomotive.getName()); this.executor.execute(() -> { - PersistenceFactory.getService().persist(block); + PersistenceFactory.getService().persist(block.getTileBean()); block.repaintTile(); }); } @@ -1478,8 +1520,10 @@ private void toggleOutOfOrderMIActionPerformed(ActionEvent evt) {//GEN-FIRST:eve } if (currentState != block.getRouteBlockState()) { - this.executor.execute(() -> PersistenceFactory.getService().persist(block.getBlockBean())); - this.repaint(); + this.executor.execute(() -> { + PersistenceFactory.getService().persist(block.getBlockBean()); + block.repaintTile(); + }); } } }//GEN-LAST:event_toggleOutOfOrderMIActionPerformed @@ -1494,8 +1538,10 @@ private void resetGhostMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_res } else { block.setBlockState(BlockBean.BlockState.FREE); } - this.executor.execute(() -> PersistenceFactory.getService().persist(block.getBlockBean())); - this.repaint(); + this.executor.execute(() -> { + PersistenceFactory.getService().persist(block.getBlockBean()); + block.repaintTile(); + }); } } }//GEN-LAST:event_resetGhostMIActionPerformed diff --git a/src/main/java/jcs/ui/layout/LayoutPanel.java b/src/main/java/jcs/ui/layout/LayoutPanel.java index 52efe209..dc8936c2 100755 --- a/src/main/java/jcs/ui/layout/LayoutPanel.java +++ b/src/main/java/jcs/ui/layout/LayoutPanel.java @@ -191,18 +191,14 @@ private void postInit() { } - public void saveLayout() { - this.canvas.saveLayout(); - } +// void saveLayout() { +// this.canvas.saveLayout(); +// } public void loadLayout() { this.canvas.loadLayoutInBackground(); } - public void loadTiles() { - this.canvas.loadTiles(); - } - /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. */ @@ -885,7 +881,7 @@ private void propertiesMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_pro }//GEN-LAST:event_propertiesMIActionPerformed private void saveBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_saveBtnActionPerformed - this.saveLayout(); + this.canvas.saveLayout(); }//GEN-LAST:event_saveBtnActionPerformed private void loadBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_loadBtnActionPerformed diff --git a/src/main/java/jcs/ui/layout/LayoutPanelTester.java b/src/main/java/jcs/ui/layout/LayoutPanelTester.java index bf0c9cac..21c26fb0 100644 --- a/src/main/java/jcs/ui/layout/LayoutPanelTester.java +++ b/src/main/java/jcs/ui/layout/LayoutPanelTester.java @@ -35,7 +35,6 @@ public static void main(String args[]) { //System.setProperty("trackServiceAlwaysUseDemo", "true"); try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); - //UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { Logger.error(ex); } @@ -51,7 +50,7 @@ public static void main(String args[]) { } f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - layoutPanel.loadTiles(); + layoutPanel.loadLayout(); f.pack(); Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); diff --git a/src/main/java/jcs/ui/layout/LayoutPanelTesterRO.java b/src/main/java/jcs/ui/layout/LayoutPanelTesterRO.java index da56baff..7eb4f2d7 100644 --- a/src/main/java/jcs/ui/layout/LayoutPanelTesterRO.java +++ b/src/main/java/jcs/ui/layout/LayoutPanelTesterRO.java @@ -35,7 +35,6 @@ public static void main(String args[]) { //System.setProperty("trackServiceAlwaysUseDemo", "true"); try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); - //UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { Logger.error(ex); } @@ -51,7 +50,7 @@ public static void main(String args[]) { } f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - layoutPanel.loadLayout(); + //layoutPanel.loadLayout(); f.pack(); Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); diff --git a/src/main/java/jcs/ui/layout/RoutesDialog.java b/src/main/java/jcs/ui/layout/RoutesDialog.java index b23106e4..742a03e0 100644 --- a/src/main/java/jcs/ui/layout/RoutesDialog.java +++ b/src/main/java/jcs/ui/layout/RoutesDialog.java @@ -33,7 +33,6 @@ import jcs.entities.TileBean.Orientation; import jcs.persistence.PersistenceFactory; import jcs.ui.layout.events.TileEvent; -import jcs.ui.layout.tiles.TileFactory; import org.tinylog.Logger; /** @@ -120,7 +119,7 @@ private void resetRoute(List routeElements) { for (RouteElementBean re : routeElements) { String tileId = re.getTileId(); TileEvent tileEvent = new TileEvent(tileId, false); - TileFactory.fireTileEventListener(tileEvent); + TileCache.fireTileEventListener(tileEvent); } } @@ -145,7 +144,7 @@ private void showRoute(RouteBean routeBean) { } else { tileEvent = new TileEvent(tileId, true, incomingSide); } - TileFactory.fireTileEventListener(tileEvent); + TileCache.fireTileEventListener(tileEvent); } } diff --git a/src/main/java/jcs/ui/layout/TileCache.java b/src/main/java/jcs/ui/layout/TileCache.java new file mode 100644 index 00000000..28b78f8f --- /dev/null +++ b/src/main/java/jcs/ui/layout/TileCache.java @@ -0,0 +1,414 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout; + +import jcs.ui.layout.tiles.*; +import java.awt.Point; +import java.beans.PropertyChangeListener; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import jcs.entities.AccessoryBean.AccessoryValue; +import jcs.entities.AccessoryBean.SignalValue; +import jcs.entities.TileBean; +import jcs.entities.TileBean.Orientation; +import static jcs.entities.TileBean.Orientation.EAST; +import static jcs.entities.TileBean.Orientation.SOUTH; +import static jcs.entities.TileBean.Orientation.WEST; +import static jcs.entities.TileBean.TileType.CROSS; +import jcs.persistence.PersistenceFactory; +import jcs.ui.layout.events.TileEvent; +import jcs.ui.layout.events.TileEventListener; +import org.tinylog.Logger; + +/** + * Factory object to create Tiles and cache tiles + * + * @author frans + */ +public class TileCache { + + private static final Map tileEventListeners = new HashMap<>(); + + private static boolean drawOutline; + private static boolean drawCenterPoint; + private static boolean showValues; + + static final Map tiles = new HashMap<>(); + static final Map altTiles = new HashMap<>(); + + private TileCache() { + } + +// static void setDrawOutline(boolean drawOutline) { +// TileCache.drawOutline = drawOutline; +// +// for (Tile tile : tiles.values()) { +// tile.setDrawOutline(drawOutline); +// } +// } + static void setDrawCenterPoint(boolean drawCenterPoint) { + TileCache.drawCenterPoint = drawCenterPoint; + + for (Tile tile : tiles.values()) { + //if (tile instanceof AbstractTile abstractTile) { + tile.setDrawCenterPoint(drawCenterPoint); + //} + } + } + + public static void setShowValues(boolean showValues) { + TileCache.showValues = showValues; + + for (Tile tile : tiles.values()) { + TileBean.TileType tileType = tile.getTileType(); + //AbstractTile tile = null; + switch (tileType) { + case SWITCH -> { + if (showValues && ((Switch) tile).getTileBean().getAccessoryBean() != null) { + tile.setAccessoryValue(tile.getTileBean().getAccessoryBean().getAccessoryValue()); + } else { + tile.setAccessoryValue(AccessoryValue.OFF); + } + } + case CROSS -> { + if (showValues && ((Cross) tile).getTileBean().getAccessoryBean() != null) { + tile.setAccessoryValue(tile.getTileBean().getAccessoryBean().getAccessoryValue()); + } else { + tile.setAccessoryValue(AccessoryValue.OFF); + } + } + case SIGNAL -> { + if (showValues && ((Signal) tile).getTileBean().getAccessoryBean() != null) { + tile.setSignalValue(tile.getTileBean().getAccessoryBean().getSignalValue()); + } else { + tile.setSignalValue(SignalValue.OFF); + } + } + case SENSOR -> { + if (showValues && ((Sensor) tile).getTileBean().getSensorBean() != null) { + tile.setActive(tile.getTileBean().getSensorBean().isActive()); + } else { + tile.setActive(false); + } + } + case BLOCK -> { + } + } + } + } + + static void loadTiles(PropertyChangeListener listener) { + List tileBeans = PersistenceFactory.getService().getTileBeans(); + + tileEventListeners.clear(); + altTiles.clear(); + tiles.clear(); + + for (TileBean tb : tileBeans) { + Tile tile = TileFactory.createTile(tb, showValues); + //tile.setPropertyChangeListener(listener); + tiles.put(tile.getCenter(), tile); + addTileEventListener((TileEventListener) tile); + + //Alternative point(s) to be able to find all points + if (!tile.getAltPoints().isEmpty()) { + Set alt = tile.getAltPoints(); + for (Point ap : alt) { + altTiles.put(ap, tile); + } + } + } + + Logger.trace("Loaded " + tiles.size() + " Tiles..."); + } + + static List getTiles() { + return tiles.values().stream().collect(Collectors.toList()); + } + + static void addTile(Tile tile) { + tiles.put(tile.getCenter(), tile); + + addTileEventListener((TileEventListener) tile); + + //Alternative point(s) to be able to find all points + if (!tile.getAltPoints().isEmpty()) { + Set alt = tile.getAltPoints(); + for (Point ap : alt) { + altTiles.put(ap, tile); + } + } + + saveTile(tile); + Logger.trace("Added " + tile + " There are now " + TileCache.tiles.size() + " tiles..."); + } + + static void removeTiles(Set pointsToRemove) { + for (Point p : pointsToRemove) { + Tile removed = tiles.remove(p); + removeTileEventListener(removed); + + deleteTile(removed); + + if (removed != null && removed.getAllPoints() != null) { + Set rps = removed.getAltPoints(); + //Also remove alt points + for (Point ap : rps) { + altTiles.remove(ap); + } + + } + } + } + + static void deleteTile(final Tile tile) { + if (tile != null) { + TileBean tb = tile.getTileBean(); + PersistenceFactory.getService().remove(tb); + } else { + Logger.warn("Tile is null?"); + } + } + + static void saveTile(final Tile tile) { + if (tile != null) { + TileBean tb = tile.getTileBean(); + PersistenceFactory.getService().persist(tb); + } else { + Logger.warn("Tile is null?"); + } + } + + static void saveTiles() { + for (Tile tile : tiles.values()) { + saveTile(tile); + } + } + + public static Tile findTile(Point cp) { + Tile result = tiles.get(cp); + if (result == null) { + result = altTiles.get(cp); + if (result != null) { + } + } + return result; + } + + static boolean checkTileOccupation(Tile tile) { + Set tilePoints = tile.getAllPoints(); + for (Point p : tilePoints) { + if (tiles.containsKey(p) || altTiles.containsKey(p)) { + //The is a match, check if it is an other tile + Tile mt = findTile(p); + if (tile.getId().equals(mt.getId())) { + //same tile continue + } else { + //Other tile so really occupied + return true; + } + } + } + return false; + } + + static boolean containsPoint(Point point) { + return tiles.containsKey(point) || altTiles.containsKey(point); + } + + static Point checkAvailable(Point newPoint, Orientation orientation) { + if (tiles.containsKey(newPoint)) { + Tile et = tiles.get(newPoint); + Logger.trace("@ " + newPoint + " is allready occcupied by: " + et + "..."); + //Search for the nearest avalaible free point + //first get the Center point of the tile which is occuping this slot + // show warning! + Point ecp = et.getCenter(); + + int w = et.getWidth(); + int h = et.getHeight(); + + Point np; + np = switch (orientation) { + case EAST -> + new Point(ecp.x + w, ecp.y); + case WEST -> + new Point(newPoint.x - w, ecp.y); + case SOUTH -> + new Point(ecp.x, newPoint.y + h); + default -> + new Point(ecp.x, newPoint.y - h); + }; + + Logger.trace("Alternative CP: " + np); + // recursive check + return checkAvailable(np, orientation); + } else { + Logger.trace("@ " + newPoint + " is not yet used..."); + + return newPoint; + } + } + + static void rotateTile(Set centerPoints) { + for (Point p : centerPoints) { + if (tiles.containsKey(p)) { + Tile t = tiles.get(p); + //Remove the alternative or extra points... + for (Point ep : t.getAltPoints()) { + altTiles.remove(ep); + } + + t.rotate(); + + //update + tiles.put(p, t); + for (Point ep : t.getAltPoints()) { + altTiles.put(ep, t); + } + + saveTile(t); + } + } + } + + public static void flipHorizontal(Set points) { + flipTile(points, true); + } + + public static void flipVertical(Set points) { + flipTile(points, false); + } + + private static void flipTile(Set points, boolean horizontal) { + for (Point p : points) { + if (tiles.containsKey(p)) { + Tile t = tiles.get(p); + //Remove the alternative or extra points... + for (Point ep : t.getAltPoints()) { + altTiles.remove(ep); + } + + if (horizontal) { + t.flipHorizontal(); + } else { + t.flipVertical(); + } + //Update + tiles.put(p, t); + for (Point ep : t.getAltPoints()) { + altTiles.put(ep, t); + } + + if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { + saveTile(t); + } + } + } + } + + static void moveTile(Point snapPoint, Tile tile) { + Point tp = tile.getCenter(); + if (!tp.equals(snapPoint)) { + //Check if new position is free + boolean canMove = true; + if (tiles.containsKey(snapPoint) || altTiles.containsKey(snapPoint)) { + Tile t = findTile(snapPoint); + if (tile.getId().equals(t.getId())) { + //same tile so we can move + canMove = true; + } else { + Logger.trace("Position " + snapPoint + " is occupied with tile: " + t + ", can't move tile " + tile.getId()); + canMove = false; + } + + if (canMove) { + //Remove the original tile center from the tiles + Tile movingTile = tiles.remove(tp); + if (movingTile != null) { + //Also remove from the alt points + Point oldCenter = movingTile.getCenter(); + Set oldAltPoints = movingTile.getAltPoints(); + //Logger.trace("Removing " + oldAltPoints.size() + " alt tile points"); + for (Point ep : oldAltPoints) { + altTiles.remove(ep); + tiles.remove(ep); + } + + //Set the new center position + movingTile.setCenter(snapPoint); + //Check again, needed for tiles which are longer then 1 square, like a block + if (!checkTileOccupation(movingTile)) { + Logger.trace("Moved Tile " + movingTile.getId() + " from " + tp + " to " + snapPoint + "..."); + tiles.put(snapPoint, movingTile); + for (Point ep : movingTile.getAltPoints()) { + altTiles.put(ep, movingTile); + } + } else { + //Do not move Tile, put back where it was + movingTile.setCenter(oldCenter); + tiles.put(oldCenter, movingTile); + for (Point ep : movingTile.getAltPoints()) { + altTiles.put(ep, movingTile); + } + } + + if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { + saveTile(movingTile); + } + } + } + } + } + } + + static void addTileEventListener(TileEventListener listener) { + String key = listener.getId(); + tileEventListeners.put(key, listener); + } + + static void removeTileEventListener(Tile tile) { + if (tile instanceof TileEventListener tileEventListener) { + removeTileEventListener(tileEventListener); + } + } + + static void removeTileEventListener(TileEventListener listener) { + String key = listener.getId(); + tileEventListeners.remove(key, listener); + } + + public static void fireTileEventListener(TileEvent tileEvent) { + String key = tileEvent.getTileId(); + TileEventListener listener = tileEventListeners.get(key); + if (listener != null) { + listener.onTileChange(tileEvent); + Logger.trace("Fire listener on tile " + key); + } else { + //Logger.trace("Tile " + key + " not available"); + } + } + + static void fireAllTileEventListeners(TileEvent tileEvent) { + for (TileEventListener listener : tileEventListeners.values()) { + listener.onTileChange(tileEvent); + } + } + +} diff --git a/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java b/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java index 30d4b4fb..88057929 100644 --- a/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java +++ b/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java @@ -24,9 +24,9 @@ import jcs.entities.BlockBean; import jcs.entities.LocomotiveBean; import jcs.persistence.PersistenceFactory; +import jcs.ui.layout.TileCache; import jcs.ui.layout.events.TileEvent; import jcs.ui.layout.tiles.Block; -import jcs.ui.layout.tiles.TileFactory; import org.tinylog.Logger; /** @@ -74,7 +74,7 @@ private void postInit() { Logger.warn("Block has no BlockBean. Creating one..."); bb = new BlockBean(); bb.setId(block.getId()); - bb.setTile(block); + bb.setTile(block.getTileBean()); bb.setTileId(block.getId()); bb.setBlockState(BlockBean.BlockState.FREE); bb.setMaxWaitTime(0); @@ -421,7 +421,9 @@ private void saveExitBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-F PersistenceFactory.getService().persist(loc); } TileEvent tileEvent = new TileEvent(bb); - TileFactory.fireTileEventListener(tileEvent); + //TileFactory.fireTileEventListener(tileEvent); + TileCache.fireTileEventListener(tileEvent); + } this.setVisible(false); diff --git a/src/main/java/jcs/ui/layout/dialogs/BlockDialog.java b/src/main/java/jcs/ui/layout/dialogs/BlockDialog.java index 69e9826b..aa1974ba 100644 --- a/src/main/java/jcs/ui/layout/dialogs/BlockDialog.java +++ b/src/main/java/jcs/ui/layout/dialogs/BlockDialog.java @@ -27,6 +27,7 @@ import jcs.entities.SensorBean; import jcs.persistence.PersistenceFactory; import jcs.ui.layout.LayoutCanvas; +import jcs.ui.layout.TileCache; import jcs.ui.layout.tiles.Block; import jcs.ui.layout.tiles.Sensor; import jcs.ui.layout.tiles.Tile; @@ -100,7 +101,7 @@ private void postInit() { if (bb == null) { Logger.tags("bb is null for " + this.block.getId()); bb = new BlockBean(); - bb.setTile(block); + bb.setTile(block.getTileBean()); bb.setTileId(this.block.getId()); bb.setBlockState(BlockBean.BlockState.FREE); this.block.setBlockBean(bb); @@ -161,8 +162,10 @@ private void autoLink() { Logger.trace("Neighbor point +: " + pnp + " -: " + mnp); - Tile neighborPlus = this.layoutCanvas.findTile(pnp); - Tile neighborMin = this.layoutCanvas.findTile(mnp); + //Tile neighborPlus = this.layoutCanvas.findTile(pnp); + Tile neighborPlus = TileCache.findTile(pnp); + //Tile neighborMin = this.layoutCanvas.findTile(mnp); + Tile neighborMin = TileCache.findTile(mnp); if (neighborPlus != null && neighborPlus instanceof Sensor) { Sensor ps = (Sensor) neighborPlus; diff --git a/src/main/java/jcs/ui/layout/dialogs/SensorDialog.java b/src/main/java/jcs/ui/layout/dialogs/SensorDialog.java index 88b823c5..baf222ca 100644 --- a/src/main/java/jcs/ui/layout/dialogs/SensorDialog.java +++ b/src/main/java/jcs/ui/layout/dialogs/SensorDialog.java @@ -263,7 +263,7 @@ private void saveExitBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-F if (PersistenceFactory.getService() != null) { PersistenceFactory.getService().persist(sensorBean); - PersistenceFactory.getService().persist((sensor)); + PersistenceFactory.getService().persist((sensor.getTileBean())); JCS.getJcsCommandStation().addSensorEventListener(sensor); } } else if (this.sensor != null && this.sensor.getSensorBean() == null) { @@ -274,7 +274,7 @@ private void saveExitBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-F sensor.setSensorBean(sensorBean); Logger.trace("Created " + sensorBean); - PersistenceFactory.getService().persist((sensor)); + PersistenceFactory.getService().persist((sensor.getTileBean())); JCS.getJcsCommandStation().addSensorEventListener(sensor); } } diff --git a/src/main/java/jcs/ui/layout/dialogs/SignalDialog.java b/src/main/java/jcs/ui/layout/dialogs/SignalDialog.java index 064ae907..2e457e98 100644 --- a/src/main/java/jcs/ui/layout/dialogs/SignalDialog.java +++ b/src/main/java/jcs/ui/layout/dialogs/SignalDialog.java @@ -183,11 +183,11 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { private void saveExitBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveExitBtnActionPerformed if (this.signal != null && this.signal.getAccessoryBean() != null) { if (this.signal.getAccessoryBean().getName() != null) { - PersistenceFactory.getService().persist((signal)); + PersistenceFactory.getService().persist((signal.getTileBean())); JCS.getJcsCommandStation().addAccessoryEventListener(signal); } else { this.signal.setAccessoryBean(null); - PersistenceFactory.getService().persist((signal)); + PersistenceFactory.getService().persist((signal.getTileBean())); } } this.setVisible(false); diff --git a/src/main/java/jcs/ui/layout/dialogs/SwitchDialog.java b/src/main/java/jcs/ui/layout/dialogs/SwitchDialog.java index 5916bbb3..0334d85b 100644 --- a/src/main/java/jcs/ui/layout/dialogs/SwitchDialog.java +++ b/src/main/java/jcs/ui/layout/dialogs/SwitchDialog.java @@ -189,12 +189,12 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { private void saveExitBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveExitBtnActionPerformed if (this.turnout != null && this.turnout.getAccessoryBean() != null) { if (this.turnout.getAccessoryBean().getName() != null) { - PersistenceFactory.getService().persist((turnout)); + PersistenceFactory.getService().persist((turnout.getTileBean())); JCS.getJcsCommandStation().addAccessoryEventListener(turnout); } else { this.turnout.setAccessoryBean(null); - PersistenceFactory.getService().persist((turnout)); + PersistenceFactory.getService().persist((turnout.getTileBean())); } } this.setVisible(false); diff --git a/src/main/java/jcs/ui/layout/tiles/AbstractTile.java b/src/main/java/jcs/ui/layout/tiles/AbstractTile.java deleted file mode 100755 index 87013362..00000000 --- a/src/main/java/jcs/ui/layout/tiles/AbstractTile.java +++ /dev/null @@ -1,893 +0,0 @@ -/* - * Copyright 2024 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout.tiles; - -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.geom.AffineTransform; -import java.awt.geom.Ellipse2D; -import java.awt.geom.PathIterator; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.awt.image.AffineTransformOp; -import java.awt.image.BufferedImage; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import jcs.entities.AccessoryBean.AccessoryValue; -import jcs.entities.TileBean; -import jcs.ui.layout.LayoutUtil; -import jcs.ui.layout.events.TileEvent; -import jcs.ui.layout.events.TileEventListener; -import static jcs.ui.layout.tiles.Tile.DEFAULT_TRACK_COLOR; -import org.imgscalr.Scalr; -import org.imgscalr.Scalr.Method; -import org.imgscalr.Scalr.Mode; - -/** - * Basic graphic element to display a track, turnout, etc on the screen.
- * By default the drawing of a Tile is Horizontal from L to R or West to East.
- * The default orientation is East. - * - *

- * The default size of a Tile is 40 x 40 pixels.
- * The center point of a Tile is stored and always snapped to the nearest grid point.
- * The basic grid is 20x 20 pixels.
- * - *

- * A Tile can be rotated (always clockwise).
- * Rotation will change the orientation from East -> South -> West -> North -> East.
- * - *

- * A Tile is rendered to a Buffered Image to speed up the display - */ -abstract class AbstractTile extends TileBean implements Tile, TileEventListener { - - protected int width; - protected int height; - protected int renderWidth; - protected int renderHeight; - - protected int offsetX = 0; - protected int offsetY = 0; - - protected int renderOffsetX = 0; - protected int renderOffsetY = 0; - - protected Color trackColor; - protected Color trackRouteColor; - protected Orientation incomingSide; - protected boolean drawRoute = false; - - protected Color backgroundColor; - protected boolean drawName = true; - - protected boolean drawOutline = false; - - protected boolean scaleImage = true; - - protected BufferedImage tileImage; - - protected PropertyChangeListener propertyChangeListener; - - protected AbstractTile(Point center) { - this(Orientation.EAST, Direction.CENTER, center.x, center.y); - } - - protected AbstractTile(Orientation orientation, Point center) { - this(orientation, Direction.CENTER, center.x, center.y); - } - - protected AbstractTile(Orientation orientation, int x, int y) { - this(orientation, Direction.CENTER, x, y); - } - - protected AbstractTile(Orientation orientation, Direction direction, int x, int y) { - this(orientation, direction, x, y, null); - } - - protected AbstractTile(Orientation orientation, Direction direction, int x, int y, Color backgroundColor) { - this.tileOrientation = orientation.getOrientation(); - this.tileDirection = direction.getDirection(); - - this.x = x; - this.y = y; - this.width = DEFAULT_WIDTH; - this.height = DEFAULT_HEIGHT; - this.renderWidth = RENDER_WIDTH; - this.renderHeight = RENDER_HEIGHT; - - this.trackColor = DEFAULT_TRACK_COLOR; - this.backgroundColor = backgroundColor; - if (this.backgroundColor == null) { - this.backgroundColor = DEFAULT_BACKGROUND_COLOR; - } - } - - protected AbstractTile(TileBean tileBean) { - copyInto(tileBean); - this.trackColor = DEFAULT_TRACK_COLOR; - this.backgroundColor = DEFAULT_BACKGROUND_COLOR; - this.renderWidth = RENDER_WIDTH; - this.renderHeight = RENDER_HEIGHT; - } - - private void copyInto(TileBean other) { - this.id = other.getId(); - this.type = other.getType(); - this.tileOrientation = other.getTileOrientation(); - this.tileDirection = other.getTileDirection(); - this.x = other.getX(); - this.y = other.getY(); - - if (other instanceof AbstractTile abstractTile) { - this.renderWidth = abstractTile.renderWidth; - this.renderHeight = abstractTile.renderHeight; - } - - this.setSignalType(other.getSignalType()); - this.accessoryId = other.getAccessoryId(); - this.signalAccessoryType = other.getSignalAccessoryType(); - this.sensorId = other.getSensorId(); - this.accessoryBean = other.getAccessoryBean(); - this.sensorBean = other.getSensorBean(); - this.blockBean = other.getBlockBean(); - } - - @Override - public TileBean getTileBean() { - TileBean tb = new TileBean(); - - tb.setId(this.id); - tb.setX(this.x); - tb.setY(this.y); - tb.setType(this.type); - tb.setTileOrientation(this.tileOrientation); - tb.setTileDirection(this.tileDirection); - tb.setSignalAccessoryType(this.signalAccessoryType); - tb.setAccessoryId(this.accessoryId); - tb.setSensorId(this.sensorId); - tb.setAccessoryBean(this.accessoryBean); - tb.setSensorBean(this.sensorBean); - tb.setBlockBean(this.blockBean); - - return tb; - } - - @Override - public Color getTrackColor() { - return trackColor; - } - - @Override - public final void setTrackColor(Color trackColor) { - this.trackColor = trackColor; - } - - @Override - public Color getTrackRouteColor() { - return trackRouteColor; - } - - @Override - public void setTrackRouteColor(Color trackRouteColor) { - this.trackRouteColor = trackRouteColor; - } - - @Override - public Orientation getIncomingSide() { - return incomingSide; - } - - @Override - public void setIncomingSide(Orientation incomingSide) { - this.incomingSide = incomingSide; - } - - @Override - public Color getBackgroundColor() { - return backgroundColor; - } - - @Override - public void setBackgroundColor(Color backgroundColor) { - this.backgroundColor = backgroundColor; - } - - @Override - public boolean isDrawRoute() { - return drawRoute; - } - - @Override - public void setDrawRoute(boolean drawRoute) { - this.drawRoute = drawRoute; - } - - public int getRenderWidth() { - return renderWidth; - } - - public int getRenderHeight() { - return renderHeight; - } - - /** - * Draw the AbstractTile - * - * @param g2d The graphics handle - * @param drawOutline - */ - @Override - public void drawTile(Graphics2D g2d, boolean drawOutline) { - // by default and image is rendered in the EAST orientation - Orientation o = getOrientation(); - if (o == null) { - o = Orientation.EAST; - } - - tileImage = createImage(); - Graphics2D g2di = tileImage.createGraphics(); - - //Avoid errors - if (drawRoute && incomingSide == null) { - incomingSide = getOrientation(); - } - - g2di.setBackground(backgroundColor); - g2di.clearRect(0, 0, this.renderWidth, this.renderHeight); - int ox = 0, oy = 0; - - AffineTransform trans = new AffineTransform(); - switch (o) { - case SOUTH -> { - trans.rotate(Math.PI / 2, this.renderWidth / 2, this.renderHeight / 2); - ox = (this.renderHeight - this.renderWidth) / 2; - oy = (this.renderWidth - this.renderHeight) / 2; - trans.translate(-ox, -oy); - } - case WEST -> { - trans.rotate(Math.PI, this.renderWidth / 2, this.renderHeight / 2); - trans.translate(ox, oy); - } - case NORTH -> { - trans.rotate(-Math.PI / 2, this.renderWidth / 2, this.renderHeight / 2); - ox = (this.renderHeight - this.renderWidth) / 2; - oy = (this.renderWidth - this.renderHeight) / 2; - trans.translate(-ox, -oy); - } - default -> { - trans.rotate(0.0, this.renderWidth / 2, this.renderHeight / 2); - trans.translate(ox, oy); - } - } - - g2di.setTransform(trans); - renderTile(g2di); - - if (drawRoute) { - renderTileRoute(g2di); - } - - //When the line grid is one the scale tile must be a little smaller - int sw, sh; - if (drawOutline) { - sw = this.getWidth() - 2; - sh = this.getHeight() - 2; - } else { - sw = this.getWidth(); - sh = this.getHeight(); - } - // Scale the image back... - if (scaleImage) { - tileImage = Scalr.resize(tileImage, Method.QUALITY, Mode.FIT_EXACT, sw, sh, Scalr.OP_ANTIALIAS); - } - - g2di.dispose(); - int oxx, oyy; - if (scaleImage) { - oxx = offsetX; - oyy = offsetY; - } else { - oxx = renderOffsetX; - oyy = renderOffsetY; - } - - g2d.drawImage(tileImage, (x - tileImage.getWidth() / 2) + oxx, (y - tileImage.getHeight() / 2) + oyy, null); - } - - @Override - public BufferedImage getTileImage() { - return tileImage; - } - - /** - * Render a tile image Always starts at (0,0) used the default width and height - * - * @param g2 the Graphic context - */ - @Override - public void drawName(Graphics2D g2) { - } - - @Override - public void drawCenterPoint(Graphics2D g2d) { - drawCenterPoint(g2d, Color.GRAY); - } - - @Override - public void drawCenterPoint(Graphics2D g2, Color color) { - drawCenterPoint(g2, color, 4); - } - - @Override - public void drawCenterPoint(Graphics2D g2d, Color color, double size) { - double dX = (this.x - size / 2); - double dY = (this.y - size / 2); - - g2d.setColor(color); - g2d.fill(new Ellipse2D.Double(dX, dY, size, size)); - - if (!getAltPoints().isEmpty()) { - // Also draw the alt points - Set alt = new HashSet<>(getAltPoints()); - - for (Point ap : alt) { - g2d.fill(new Ellipse2D.Double(ap.x, ap.y, size - 1, size - 1)); - } - } - } - - @Override - public void drawBounds(Graphics2D g2d) { - g2d.setColor(Color.yellow); - g2d.draw(getBounds()); - } - - /** - * Rotate the tile clockwise 90 deg - */ - @Override - public void rotate() { - switch (getOrientation()) { - case EAST -> - setOrientation(Orientation.SOUTH); - case SOUTH -> - setOrientation(Orientation.WEST); - case WEST -> - setOrientation(Orientation.NORTH); - default -> - setOrientation(Orientation.EAST); - } - } - - @Override - public void flipHorizontal() { - if (Orientation.NORTH.equals(getOrientation()) || Orientation.SOUTH.equals(getOrientation())) { - rotate(); - rotate(); - } - } - - @Override - public void flipVertical() { - if (Orientation.EAST.equals(getOrientation()) || Orientation.WEST.equals(getOrientation())) { - rotate(); - rotate(); - } - } - - @Override - public void move(int newX, int newY) { - Point cs = LayoutUtil.snapToGrid(newX, newY); - this.setCenter(cs); - } - - protected static void drawRotate(Graphics2D g2d, double x, double y, int angle, String text) { - g2d.translate((float) x, (float) y); - g2d.rotate(Math.toRadians(angle)); - g2d.drawString(text, 0, 0); - g2d.rotate(-Math.toRadians(angle)); - g2d.translate(-x, -y); - } - - public static BufferedImage flipHorizontally(BufferedImage source) { - BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); - - AffineTransform flip = AffineTransform.getScaleInstance(1, -1); - flip.translate(0, -source.getHeight()); - AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); - - op.filter(source, output); - - return output; - } - - public static BufferedImage flipVertically(BufferedImage source) { - BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); - - AffineTransform flip = AffineTransform.getScaleInstance(-1, 1); - flip.translate(-source.getWidth(), 0); - AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); - - op.filter(source, output); - - return output; - } - - @Override - public void setOrientation(Orientation orientation) { - this.tileOrientation = orientation.getOrientation(); - } - - @Override - public void setDirection(Direction direction) { - this.tileDirection = direction.getDirection(); - } - - @Override - public void setCenter(Point center) { - this.x = center.x; - this.y = center.y; - } - - @Override - public Set getAltPoints() { - return Collections.EMPTY_SET; - } - - @Override - public final int getOffsetX() { - return offsetX; - } - - @Override - public void setOffsetX(int offsetX) { - this.offsetX = offsetX; - } - - @Override - public final int getOffsetY() { - return offsetY; - } - - @Override - public void setOffsetY(int offsetY) { - this.offsetY = offsetY; - } - - protected BufferedImage createImage() { - return new BufferedImage(this.renderWidth, this.renderHeight, BufferedImage.TYPE_INT_RGB); - } - - @Override - public int getCenterX() { - if (this.x > 0) { - return this.x; - } else { - return GRID; - } - } - - @Override - public int getCenterY() { - if (this.y > 0) { - return this.y; - } else { - return GRID; - } - } - - public boolean isDrawName() { - return drawName; - } - - public void setDrawName(boolean drawName) { - this.drawName = drawName; - } - - @Override - public boolean isDrawOutline() { - return drawOutline; - } - - public boolean isScaleImage() { - return scaleImage; - } - - public void setScaleImage(boolean scaleImage) { - this.scaleImage = scaleImage; - } - - @Override - public void setDrawOutline(boolean drawOutline) { - if (this.drawOutline != drawOutline) { - this.drawOutline = drawOutline; - } - } - - @Override - public String toString() { - return this.getClass().getSimpleName() - + " {id: " - + id - + ", orientation: " - + getOrientation() - + ", direction: " - + getDirection() - + ", center: " - + xyToString() - + "}"; - } - - @Override - public Rectangle getBounds() { - int w, h, cx, cy; - if (this.width > 0 & this.height > 0) { - w = this.width; - h = this.height; - } else { - w = DEFAULT_WIDTH; - h = DEFAULT_HEIGHT; - } - - if (this.x > 0 && this.y > 0) { - cx = this.x + this.offsetX; - cy = this.y + this.offsetY; - } else { - cx = w / 2; - cy = h / 2; - } - - int ltx = cx - w / 2; - int lty = cy - h / 2; - return new Rectangle(ltx, lty, w, h); - } - - @Override - public Rectangle2D getBounds2D() { - return getBounds().getBounds2D(); - } - - @Override - public boolean contains(double x, double y) { - int w, h, cx, cy, tlx, tly; - if (this.width > 0 & this.height > 0) { - w = this.width; - h = this.height; - } else { - w = DEFAULT_WIDTH; - h = DEFAULT_HEIGHT; - } - - if (this.width > 0 & this.height > 0) { - cx = this.x; - cy = this.y; - } else { - cx = w / 2; - cy = h / 2; - } - - // top left dX and dY - tlx = cx - w / 2; - tly = cy - h / 2; - - // Check if X and Y range is ok - return !(x < tlx || x > (tlx + w) || y < tly || y > (tly + h)); - } - - @Override - public String xyToString() { - return "(" + this.x + "," + this.y + ")"; - } - - @Override - public boolean contains(Point2D p) { - return this.contains(p.getX(), p.getY()); - } - - @Override - public boolean intersects(double x, double y, double w, double h) { - return getBounds().intersects(x, y, w, h); - } - - @Override - public boolean intersects(Rectangle2D r2d) { - return getBounds().intersects(r2d); - } - - @Override - public boolean contains(double x, double y, double w, double h) { - return getBounds().contains(x, y, w, h); - } - - @Override - public boolean contains(Rectangle2D r2d) { - return getBounds().contains(r2d); - } - - @Override - public PathIterator getPathIterator(AffineTransform at) { - return getBounds().getPathIterator(at); - } - - @Override - public PathIterator getPathIterator(AffineTransform at, double flatness) { - return getBounds().getPathIterator(at, flatness); - } - - public PropertyChangeListener getPropertyChangeListener() { - return this.propertyChangeListener; - } - - @Override - public void setPropertyChangeListener(PropertyChangeListener propertyChangeListener) { - this.propertyChangeListener = propertyChangeListener; - } - - public void repaintTile() { - if (this.propertyChangeListener != null) { - this.propertyChangeListener.propertyChange(new PropertyChangeEvent(this, "repaintTile", this, this)); - } - } - - @Override - public void onTileChange(TileEvent tileEvent) { - if (tileEvent.isEventFor(this)) { - drawRoute = tileEvent.isShowRoute(); - setIncomingSide(tileEvent.getIncomingSide()); - - if (isJunction()) { - ((Switch) this).setRouteValue(tileEvent.getRouteState()); - } - - if (tileEvent.getBlockBean() != null) { - setBlockBean(tileEvent.getBlockBean()); - } - - if (tileEvent.getTileBean() != null) { - TileBean other = tileEvent.getTileBean(); - this.copyInto(other); - } - - if (isBlock()) { - ((Block) this).setRouteBlockState(tileEvent.getBlockState()); - if (!drawRoute) { - ((Block) this).setRouteBlockState(null); - } - } - - setBackgroundColor(tileEvent.getBackgroundColor()); - setTrackColor(tileEvent.getTrackColor()); - setTrackRouteColor(tileEvent.getTrackRouteColor()); - -// if (tileEvent.getBlockBean() != null) { -// setBlockBean(tileEvent.getBlockBean()); -// } - repaintTile(); - } - } - - @Override - public int getWidth() { - return this.width; - } - - @Override - public int getHeight() { - return this.height; - } - - @Override - public int getGridX() { - return (getCenterX() - Tile.GRID) / (Tile.GRID * 2); - } - - @Override - public int getGridY() { - return (getCenterY() - Tile.GRID) / (Tile.GRID * 2); - } - - /** - * The main route of the tile is horizontal - * - * @return true when main route goes from East to West or vv - */ - @Override - public boolean isHorizontal() { - return (Orientation.EAST == getOrientation() || Orientation.WEST == getOrientation()) && TileType.CURVED != getTileType(); - } - - /** - * The main route of the tile is vertical - * - * @return true when main route goes from North to South or vv - */ - @Override - public boolean isVertical() { - return (Orientation.NORTH == getOrientation() || Orientation.SOUTH == getOrientation()) && TileType.CURVED != getTileType(); - } - - @Override - public boolean isJunction() { - return false; - } - - @Override - public boolean isBlock() { - return false; - } - - @Override - public boolean isDirectional() { - return false; - } - - /** - * The main route of the tile is diagonal - * - * @return true when main route goes from North to East or West to South and vv - */ - @Override - public boolean isDiagonal() { - return TileType.CURVED == getTileType(); - } - - @Override - public boolean isCrossing() { - return TileType.CROSSING == getTileType(); - } - - public List getNeighbours() { - return neighbours; - } - - public void setNeighbours(List neighbours) { - this.neighbours = neighbours; - } - - @Override - public String getIdSuffix(Tile other) { - return ""; - } - - @Override - public Map getNeighborOrientations() { - Map edgeOrientations = new HashMap<>(); - - Map neighborPoints = getNeighborPoints(); - - for (Orientation o : Orientation.values()) { - edgeOrientations.put(neighborPoints.get(o), o); - } - return edgeOrientations; - } - - @Override - public Map getEdgeOrientations() { - Map edgeOrientations = new HashMap<>(); - - Map edgeConnections = getEdgePoints(); - - for (Orientation o : Orientation.values()) { - edgeOrientations.put(edgeConnections.get(o), o); - } - return edgeOrientations; - } - - @Override - public boolean isAdjacent(Tile other) { - boolean adjacent = false; - - if (other != null) { - Collection thisEdgePoints = getEdgePoints().values(); - Collection otherEdgePoints = other.getEdgePoints().values(); - - for (Point p : thisEdgePoints) { - adjacent = otherEdgePoints.contains(p); - if (adjacent) { - break; - } - } - } - - return adjacent; - } - - /** - * When the tile has a specific direction a train may travel then this method will indicate whether the other tile is in on the side where the arrow is pointing to - * - * @param other A Tile - * @return true where other is on the side of this tile where the arrow points to - */ - @Override - public boolean isArrowDirection(Tile other) { - return true; - } - - @Override - public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { - return AccessoryValue.OFF; - } - - protected StringBuilder getImageKeyBuilder() { - StringBuilder sb = new StringBuilder(); - //sb.append(id); - sb.append(type); - sb.append("~"); - sb.append(getOrientation().getOrientation()); - sb.append("~"); - sb.append(getDirection().getDirection()); - sb.append("~"); - sb.append(isDrawOutline() ? "y" : "n"); - sb.append("~"); - int r = backgroundColor.getRed(); - int g = backgroundColor.getGreen(); - int b = backgroundColor.getBlue(); - sb.append("#"); - sb.append(r); - sb.append("#"); - sb.append(g); - sb.append("#"); - sb.append(b); - sb.append("~"); - r = trackColor.getRed(); - g = trackColor.getGreen(); - b = trackColor.getBlue(); - sb.append("#"); - sb.append(r); - sb.append("#"); - sb.append(g); - sb.append("#"); - sb.append(b); - sb.append("~"); - sb.append(isDrawRoute() ? "y" : "n"); - if (isDrawRoute()) { - if (incomingSide != null) { - sb.append("~"); - sb.append(incomingSide.getOrientation()); - } - sb.append("~"); - r = trackRouteColor.getRed(); - g = trackRouteColor.getGreen(); - b = trackRouteColor.getBlue(); - sb.append("#"); - sb.append(r); - sb.append("#"); - sb.append(g); - sb.append("#"); - sb.append(b); - } - - //sb.append("~"); - //Tile specific properties - //AccessoryValue - //SignalType - //SignalValue - //active; - //Logger.trace(sb); - return sb; - } - -} diff --git a/src/main/java/jcs/ui/layout/tiles/Block.java b/src/main/java/jcs/ui/layout/tiles/Block.java index 4635a845..780c3907 100755 --- a/src/main/java/jcs/ui/layout/tiles/Block.java +++ b/src/main/java/jcs/ui/layout/tiles/Block.java @@ -17,10 +17,13 @@ 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.Image; import java.awt.Point; +import java.awt.geom.Ellipse2D; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -29,7 +32,6 @@ import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; import jcs.entities.TileBean; -import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.EAST; import static jcs.entities.TileBean.Orientation.NORTH; @@ -42,56 +44,106 @@ import static jcs.ui.layout.tiles.Tile.RENDER_HEIGHT; import static jcs.ui.layout.tiles.Tile.RENDER_WIDTH; import jcs.ui.util.ImageUtil; +import org.tinylog.Logger; -public class Block extends AbstractTile implements Tile { +public class Block extends Tile { public static final int BLOCK_WIDTH = DEFAULT_WIDTH * 3; public static final int BLOCK_HEIGHT = DEFAULT_HEIGHT * 3; protected BlockState routeBlockState; - Block(TileBean tileBean) { - super(tileBean); - if (Orientation.EAST.equals(getOrientation()) || Orientation.WEST.equals(getOrientation())) { - this.width = BLOCK_WIDTH; + private static int blockWidth(Orientation orientation) { + if (Orientation.EAST == orientation || Orientation.WEST == orientation) { + return BLOCK_WIDTH; + } else { + return DEFAULT_WIDTH; + } + } + + private static int blockHeight(Orientation orientation) { + if (Orientation.EAST == orientation || Orientation.WEST == orientation) { + return DEFAULT_HEIGHT; + } else { + return BLOCK_HEIGHT; + } + } + + public Block(TileBean tileBean) { + super(tileBean, blockWidth(tileBean.getOrientation()), blockHeight(tileBean.getOrientation())); + setModel(new DefaultTileModel()); + + if (Orientation.EAST == tileBean.getOrientation() || Orientation.WEST == tileBean.getOrientation()) { this.renderWidth = RENDER_WIDTH * 3; - this.height = DEFAULT_HEIGHT; this.renderHeight = RENDER_HEIGHT; } else { - this.width = DEFAULT_WIDTH; this.renderWidth = RENDER_WIDTH; - this.height = BLOCK_HEIGHT; this.renderHeight = RENDER_HEIGHT * 3; } - this.blockBean = tileBean.getBlockBean(); - this.type = tileBean.getType(); } - Block(Orientation orientation, Point center) { + public Block(Orientation orientation, Point center) { this(orientation, center.x, center.y); } - Block(Orientation orientation, int x, int y) { - super(orientation, Direction.CENTER, x, y); + public Block(Orientation orientation, int x, int y) { + this(orientation, x, y, blockWidth(orientation), blockHeight(orientation)); + } + + public Block(Orientation orientation, int x, int y, int width, int height) { + super(TileType.BLOCK, orientation, x, y, width, height); + setModel(new DefaultTileModel()); - if (Orientation.EAST == getOrientation() || Orientation.WEST == getOrientation()) { - this.width = BLOCK_WIDTH; + if (Orientation.EAST == orientation || Orientation.WEST == orientation) { this.renderWidth = RENDER_WIDTH * 3; - this.height = DEFAULT_HEIGHT; this.renderHeight = RENDER_HEIGHT; } else { - this.width = DEFAULT_WIDTH; this.renderWidth = RENDER_WIDTH; - this.height = BLOCK_HEIGHT; this.renderHeight = RENDER_HEIGHT * 3; } - this.type = TileType.BLOCK.getTileType(); } +// Block(TileBean tileBean) { +// super(tileBean); +// if (Orientation.EAST.equals(getOrientation()) || Orientation.WEST.equals(getOrientation())) { +// this.width = BLOCK_WIDTH; +// this.renderWidth = RENDER_WIDTH * 3; +// this.height = DEFAULT_HEIGHT; +// this.renderHeight = RENDER_HEIGHT; +// } else { +// this.width = DEFAULT_WIDTH; +// this.renderWidth = RENDER_WIDTH; +// this.height = BLOCK_HEIGHT; +// this.renderHeight = RENDER_HEIGHT * 3; +// } +// this.blockBean = tileBean.getBlockBean(); +// this.tileType = tileBean.getTileType(); +// this.setLayout(null); +// } +// Block(Orientation orientation, Point center) { +// this(orientation, center.x, center.y); +// } +// Block(Orientation orientation, int x, int y) { +// super(orientation, Direction.CENTER, x, y); +// +// if (Orientation.EAST == getOrientation() || Orientation.WEST == getOrientation()) { +// this.width = BLOCK_WIDTH; +// this.renderWidth = RENDER_WIDTH * 3; +// this.height = DEFAULT_HEIGHT; +// this.renderHeight = RENDER_HEIGHT; +// } else { +// this.width = DEFAULT_WIDTH; +// this.renderWidth = RENDER_WIDTH; +// this.height = BLOCK_HEIGHT; +// this.renderHeight = RENDER_HEIGHT * 3; +// } +// this.tileType = TileType.BLOCK; +// this.setLayout(null); +// } @Override public Set getAltPoints() { - int xx = this.x; - int yy = this.y; + int xx = this.tileX; + int yy = this.tileY; Set alternatives = new HashSet<>(); if (Orientation.EAST.equals(getOrientation()) || Orientation.WEST.equals(getOrientation())) { @@ -291,43 +343,24 @@ public String getIdSuffix(Tile other) { @Override public void rotate() { super.rotate(); + Dimension d; if (Orientation.EAST.equals(getOrientation()) || Orientation.WEST.equals(getOrientation())) { - this.width = DEFAULT_WIDTH * 3; - this.height = DEFAULT_HEIGHT; + d = new Dimension(DEFAULT_WIDTH * 3, DEFAULT_HEIGHT); + //this.width = DEFAULT_WIDTH * 3; + //this.height = DEFAULT_HEIGHT; this.renderWidth = RENDER_WIDTH * 3; this.renderHeight = RENDER_HEIGHT; } else { - this.width = DEFAULT_WIDTH; - this.height = DEFAULT_HEIGHT * 3; + d = new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT * 3); + //this.width = DEFAULT_WIDTH; + //this.height = DEFAULT_HEIGHT * 3; this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT * 3; } - } - - public void setWidth(int width) { - this.width = width; - } - - public void setHeight(int height) { - this.height = height; - } - - public void setRenderWidth(int renderWidth) { - this.renderWidth = renderWidth; - } - - public void setRenderHeight(int renderHeight) { - this.renderHeight = renderHeight; - } - - public void setRenderOffsetX(int renderOffsetX) { - this.renderOffsetX = renderOffsetX; - } - - public void setRenderOffsetY(int renderOffsetY) { - this.renderOffsetY = renderOffsetY; + setSize(d); + setPreferredSize(d); } /** @@ -340,16 +373,11 @@ public void setRenderOffsetY(int renderOffsetY) { * * @return the Color which belong with the current Block State */ - public Color getBlockStateColor() { - if (blockBean != null) { - BlockState blockState = blockBean.getBlockState(); - return getBlockStateColor(blockState); - } else { - return Color.white; - } + Color getBlockStateColor() { + return getBlockStateColor(this.model.getBlockState()); } - public Color getBlockStateColor(BlockState blockState) { + protected Color getBlockStateColor(BlockState blockState) { return switch (blockState) { case GHOST -> new Color(250, 0, 0); @@ -376,21 +404,6 @@ public BlockState getRouteBlockState() { return routeBlockState; } - public BlockState getBlockState() { - if (blockBean != null) { - return blockBean.getBlockState(); - } else { - return BlockState.FREE; - } - } - - public void setBlockState(BlockState blockState) { - if (blockBean == null) { - this.blockBean = new BlockBean((TileBean) this); - } - blockBean.setBlockState(blockState); - } - public static String getDepartureSuffix(Orientation tileOrientation, boolean reverseArrival, LocomotiveBean.Direction direction) { if (LocomotiveBean.Direction.FORWARDS == direction) { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { @@ -545,7 +558,6 @@ private void renderDirectionArrow(Graphics2D g2) { } } } - } private void renderLeftArrow(Graphics2D g2) { @@ -594,18 +606,18 @@ protected void overlayLocImage(Graphics2D g2d) { int h = locImage.getHeight(null); if (null == departureSuffix) { - xx = x - width / 2 + w; + xx = tileX - getWidth() / 2 + w; } else { switch (departureSuffix) { case "+" -> { - xx = x - width / 2 + w - 25; + xx = tileX - getWidth() / 2 + w - 25; } default -> { - xx = x - width / 2 + w + 10; + xx = tileX - getWidth() / 2 + w + 10; } } } - int yy = y - h / 2; + int yy = tileY - h / 2; if (reverseImage) { locImage = ImageUtil.flipVertically(locImage); @@ -619,17 +631,17 @@ protected void overlayLocImage(Graphics2D g2d) { int w = locImage.getWidth(null); int h = locImage.getHeight(null); - int xx = x - w / 2; + int xx = tileX - w / 2; int yy; if (null == departureSuffix) { - yy = y - height / 2 + h; + yy = tileY - getHeight() / 2 + h; } else { switch (departureSuffix) { case "-" -> { - yy = y - height / 2 + h - 25; + yy = tileY - getHeight() / 2 + h - 25; } default -> { - yy = y - height / 2 + h + 10; + yy = tileY - getHeight() / 2 + h + 10; } } } @@ -645,18 +657,18 @@ protected void overlayLocImage(Graphics2D g2d) { int w = locImage.getWidth(null); int h = locImage.getHeight(null); - int xx = x - w / 2; + int xx = tileX - w / 2; int yy; if (null == departureSuffix) { - int minY = y - height / 2 + h; + int minY = tileY - getHeight() / 2 + h; yy = minY; } else { switch (departureSuffix) { case "+" -> { - yy = y - height / 2 + h - 25; + yy = tileY - getHeight() / 2 + h - 25; } default -> { - yy = y - height / 2 + h + 10; + yy = tileY - getHeight() / 2 + h + 10; } } } @@ -672,18 +684,18 @@ protected void overlayLocImage(Graphics2D g2d) { int h = locImage.getHeight(null); if (null == departureSuffix) { - xx = x - width / 2 + w; + xx = tileX - getWidth() / 2 + w; } else { switch (departureSuffix) { case "-" -> { - xx = x - width / 2 + w - 25; + xx = tileX - getWidth() / 2 + w - 25; } default -> { - xx = x - width / 2 + w + 10; + xx = tileX - getWidth() / 2 + w + 10; } } } - int yy = y - h / 2; + int yy = tileY - h / 2; if (reverseImage) { locImage = ImageUtil.flipVertically(locImage); @@ -698,11 +710,10 @@ protected void overlayLocImage(Graphics2D g2d) { * Overridden to overlay a locomotive Icon * * @param g2d The graphics handle - * @param drawOutline */ @Override - public void drawTile(Graphics2D g2d, boolean drawOutline) { - super.drawTile(g2d, drawOutline); + public void drawTile(Graphics2D g2d) { + super.drawTile(g2d); if (getLocImage() != null) { overlayLocImage(g2d); } @@ -714,7 +725,7 @@ public void onTileChange(TileEvent tileEvent) { Color pb = this.backgroundColor; super.onTileChange(tileEvent); if (!pb.equals(backgroundColor)) { - repaintTile(); + repaint(); } } @@ -735,7 +746,7 @@ private Image getLocImage() { public String getBlockText() { String blockText; - if (!drawOutline && getBlockBean() != null && getBlockBean().getDescription() != null) { + if (getBlockBean() != null && getBlockBean().getDescription() != null) { if (blockBean.getLocomotive() != null && blockBean.getLocomotive().getName() != null && BlockState.GHOST != blockBean.getBlockState()) { blockText = getBlockBean().getLocomotive().getName(); } else { @@ -800,4 +811,71 @@ public void drawName(Graphics2D g2d) { g2d.setFont(newFont); } } + + @Override + protected void paintComponent(Graphics g) { + long started = System.currentTimeMillis(); + super.paintComponent(g); + + if (tileOrientation == Orientation.EAST || tileOrientation == Orientation.WEST) { + setBounds(this.tileX - GRID - GRID * 2, this.tileY - GRID, this.getWidth(), this.getHeight()); + } else { + setBounds(this.tileX - GRID, this.tileY - GRID - GRID * 2, this.getWidth(), this.getHeight()); + } + + Graphics2D g2 = (Graphics2D) g.create(); + drawTile(g2); + g2.dispose(); + + g.drawImage(tileImage, 0, 0, null); + + Logger.trace(id + ": W: " + getWidth() + " H: " + getHeight() + " oX: " + renderOffsetX + " oY: " + renderOffsetY); + + long now = System.currentTimeMillis(); + Logger.trace(id + " Duration: " + (now - started) + " ms."); + } + + @Override + protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { + //super.drawCenterPoint(g2d, color, size); + + //A block has 2 alternate points + //1st square + //2nd square holds the centerpoint + //3rd square + double dX1, dX2, dX3, dY1, dY2, dY3; + if (Orientation.EAST == this.tileOrientation || Orientation.WEST == tileOrientation) { + dX1 = (renderWidth / 3 / 2 - size / 2 / 2); + dX2 = (renderWidth / 2 - size / 2); + dX3 = (renderWidth / 3 / 2 + renderWidth / 3 * 2 - size / 2); + dY1 = (renderHeight / 2 - size / 2 / 2); + dY2 = (renderHeight / 2 - size / 2 / 2); + dY3 = (renderHeight / 2 - size / 2 / 2); + } else { + dY1 = (renderWidth / 2 - size / 2 / 2); + + dY2 = (renderWidth / 2 - size / 2 / 2); + + dY3 = (renderWidth / 2 - size / 2 / 2); + + dX1 = (renderHeight / 3 / 2 - size / 2 / 2); + + dX2 = (renderHeight / 2 - size / 2); + + dX3 = (renderHeight / 3 / 2 + renderHeight / 3 * 2 - size / 2); + + } + + g2d.setColor(color); + + g2d.fill(new Ellipse2D.Double(dX1, dY1, size / 2, size / 2)); + g2d.fill(new Ellipse2D.Double(dX2, dY2, size, size)); + g2d.fill(new Ellipse2D.Double(dX3, dY3, size / 2, size / 2)); + + Logger.trace(id + " dX2: " + dX2 + " dY2: " + dY2 + " O: " + tileOrientation + " rW: " + renderWidth + " rH:" + renderHeight); + Logger.trace(id + " dX1: " + dX1 + " dY1: " + dY1); + Logger.trace(id + " dX3: " + dX3 + " dY3: " + dY3); + + } + } diff --git a/src/main/java/jcs/ui/layout/tiles/Cross.java b/src/main/java/jcs/ui/layout/tiles/Cross.java index 691758e8..d5153674 100644 --- a/src/main/java/jcs/ui/layout/tiles/Cross.java +++ b/src/main/java/jcs/ui/layout/tiles/Cross.java @@ -27,14 +27,17 @@ import static jcs.entities.AccessoryBean.AccessoryValue.GREEN; import static jcs.entities.AccessoryBean.AccessoryValue.RED; import jcs.entities.TileBean; +import jcs.entities.TileBean.Direction; +import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; +import jcs.entities.TileBean.TileType; import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; import static jcs.ui.layout.tiles.Tile.GRID; -public class Cross extends Switch implements Tile { +public class Cross extends Switch { public static final int CROSS_WIDTH = DEFAULT_WIDTH * 2; public static final int CROSS_HEIGHT = DEFAULT_HEIGHT * 2; @@ -47,18 +50,38 @@ public class Cross extends Switch implements Tile { public static final Color LIGHT_GREEN = new Color(0, 255, 51); public static final Color DARK_GREEN = new Color(0, 153, 0); - Cross(TileBean tileBean) { - super(tileBean); - setWidthHeightAndOffsets(); + private static int crossWidth(Orientation orientation) { + if (Orientation.EAST == orientation || Orientation.WEST == orientation) { + return DEFAULT_WIDTH * 2; + } else { + return DEFAULT_WIDTH; + } + } + + private static int crossHeight(Orientation orientation) { + if (Orientation.EAST == orientation || Orientation.WEST == orientation) { + return DEFAULT_HEIGHT; + } else { + return DEFAULT_HEIGHT * 2; + } } - Cross(Orientation orientation, Direction direction, int x, int y) { - this(orientation, direction, new Point(x, y)); + public Cross(TileBean tileBean) { + super(tileBean, crossWidth(tileBean.getOrientation()), crossHeight(tileBean.getOrientation())); + setWidthHeightAndOffsets(); } public Cross(Orientation orientation, Direction direction, Point center) { - super(orientation, direction, center); - this.type = TileType.CROSS.getTileType(); + this(orientation, direction, center.x, center.y); + } + + public Cross(Orientation orientation, Direction direction, int x, int y) { + this(orientation, direction, x, y, crossWidth(orientation), crossHeight(orientation)); + } + + public Cross(Orientation orientation, Direction direction, int x, int y, int width, int height) { + super(orientation, direction, x, y, width, height); + this.tileType = TileType.CROSS; setWidthHeightAndOffsets(); } @@ -69,8 +92,8 @@ public Cross(Orientation orientation, Direction direction, Point center) { */ @Override public Set getAltPoints() { - int xx = this.x; - int yy = this.y; + int xx = this.tileX; + int yy = this.tileY; Set alternatives = new HashSet<>(); switch (getOrientation()) { @@ -88,7 +111,7 @@ public Set getAltPoints() { } default -> { //East so default - Point ep = new Point((x + DEFAULT_WIDTH), yy); + Point ep = new Point((tileX + DEFAULT_WIDTH), yy); alternatives.add(ep); } } @@ -225,7 +248,7 @@ public void rotate() { setWidthHeightAndOffsets(); } - void setWidthHeightAndOffsets() { + final void setWidthHeightAndOffsets() { //Reset offsets this.offsetY = 0; this.renderOffsetY = 0; @@ -233,16 +256,16 @@ void setWidthHeightAndOffsets() { this.renderOffsetX = 0; if (isHorizontal()) { - this.width = DEFAULT_WIDTH * 2; - this.height = DEFAULT_HEIGHT; + //this.width = DEFAULT_WIDTH * 2; + //this.height = DEFAULT_HEIGHT; this.renderWidth = RENDER_GRID * 4; this.renderHeight = RENDER_GRID * 2; this.offsetY = 0; this.renderOffsetY = 0; } else { - this.width = DEFAULT_WIDTH; - this.height = DEFAULT_HEIGHT * 2; + //this.width = DEFAULT_WIDTH; + //this.height = DEFAULT_HEIGHT * 2; this.renderWidth = RENDER_GRID * 2; this.renderHeight = RENDER_GRID * 4; diff --git a/src/main/java/jcs/ui/layout/tiles/Crossing.java b/src/main/java/jcs/ui/layout/tiles/Crossing.java index 0c1751ad..cacf54e1 100644 --- a/src/main/java/jcs/ui/layout/tiles/Crossing.java +++ b/src/main/java/jcs/ui/layout/tiles/Crossing.java @@ -22,24 +22,26 @@ import java.util.HashMap; import java.util.Map; import jcs.entities.TileBean; +import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean.TileType; -public class Crossing extends Straight implements Tile { +public class Crossing extends Straight { - Crossing(TileBean tileBean) { + public Crossing(TileBean tileBean) { super(tileBean); - this.width = DEFAULT_WIDTH; - this.height = DEFAULT_HEIGHT; } - Crossing(Orientation orientation, Point center) { + public Crossing(Orientation orientation, Point center) { this(orientation, center.x, center.y); } - Crossing(Orientation orientation, int x, int y) { - super(orientation, x, y); - this.type = TileType.CROSSING.getTileType(); - this.width = DEFAULT_WIDTH; - this.height = DEFAULT_HEIGHT; + public Crossing(Orientation orientation, int x, int y) { + this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); + } + + public Crossing(Orientation orientation, int x, int y, int width, int height) { + super(orientation, x, y, width, height); + this.tileType = TileType.CROSSING; } @Override diff --git a/src/main/java/jcs/ui/layout/tiles/Curved.java b/src/main/java/jcs/ui/layout/tiles/Curved.java index b82d882b..450c8c06 100755 --- a/src/main/java/jcs/ui/layout/tiles/Curved.java +++ b/src/main/java/jcs/ui/layout/tiles/Curved.java @@ -16,6 +16,7 @@ package jcs.ui.layout.tiles; import java.awt.BasicStroke; +import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.util.HashMap; @@ -23,24 +24,31 @@ import java.util.Map; import java.util.Set; import jcs.entities.TileBean; +import jcs.entities.TileBean.Orientation; +import static jcs.entities.TileBean.Orientation.NORTH; +import static jcs.entities.TileBean.Orientation.SOUTH; +import static jcs.entities.TileBean.Orientation.WEST; +import jcs.entities.TileBean.TileType; +import org.tinylog.Logger; -public class Curved extends AbstractTile implements Tile { +public class Curved extends Tile { Curved(TileBean tileBean) { - super(tileBean); - this.width = DEFAULT_WIDTH; - this.height = DEFAULT_HEIGHT; + super(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); + setModel(new DefaultTileModel()); + } + + Curved(Orientation orientation, Point center) { + this(orientation, center.x, center.y); } Curved(Orientation orientation, int x, int y) { - this(orientation, new Point(x, y)); + this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); } - Curved(Orientation orientation, Point center) { - super(orientation, center); - this.width = DEFAULT_WIDTH; - this.height = DEFAULT_HEIGHT; - this.type = TileType.CURVED.getTileType(); + Curved(Orientation orientation, int x, int y, int width, int height) { + super(TileType.CURVED, orientation, x, y, width, height); + setModel(new DefaultTileModel()); } @Override @@ -136,4 +144,21 @@ public void renderTileRoute(Graphics2D g2) { g2.fillPolygon(xPoints, yPoints, xPoints.length); } + @Override + protected void paintComponent(Graphics g) { + long started = System.currentTimeMillis(); + super.paintComponent(g); + + setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); + + Graphics2D g2 = (Graphics2D) g.create(); + drawTile(g2); + g2.dispose(); + + g.drawImage(this.tileImage, 0, 0, null); + + long now = System.currentTimeMillis(); + Logger.trace(this.id + " Duration: " + (now - started) + " ms."); + } + } diff --git a/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java b/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java new file mode 100644 index 00000000..3a60e1a4 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java @@ -0,0 +1,289 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemListener; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.EventListenerList; +import jcs.entities.BlockBean.BlockState; + +/** + * + * @author fransjacobs + */ +@SuppressWarnings("serial") // Same-version serialization only +public class DefaultTileModel implements TileModel { + + protected transient ChangeEvent changeEvent = null; + + /** + * Stores the listeners on this model. + */ + protected EventListenerList listenerList = new EventListenerList(); + + protected boolean selected = false; + protected boolean scaleImage = true; + protected boolean showCenter = false; + protected boolean showRoute = false; + protected boolean showBlockState = false; + protected boolean showLocomotiveImage = false; + protected boolean showAccessoryValue = false; + protected boolean showSignalValue = false; + protected boolean sensorActive = false; + protected boolean showOutline = false; + + protected BlockState blockState; + + public DefaultTileModel() { + + } + + @Override + public boolean isSelected() { + return selected; + } + + @Override + public void setSelected(boolean selected) { + this.selected = selected; + fireStateChanged(); + } + + @Override + public boolean isScaleImage() { + return scaleImage; + } + + @Override + public void setScaleImage(boolean scaleImage) { + this.scaleImage = scaleImage; + fireStateChanged(); + } + + @Override + public boolean isShowCenter() { + return showCenter; + } + + @Override + public void setShowCenter(boolean showCenter) { + this.showCenter = showCenter; + fireStateChanged(); + } + + @Override + public boolean isShowRoute() { + return showRoute; + } + + @Override + public void setShowRoute(boolean showRoute) { + this.showRoute = showRoute; + fireStateChanged(); + } + + @Override + public boolean isShowBlockState() { + return showBlockState; + } + + @Override + public void setShowBlockState(boolean showBlockState) { + this.showBlockState = showBlockState; + fireStateChanged(); + } + + @Override + public boolean isShowLocomotiveImage() { + return showLocomotiveImage; + } + + @Override + public void setShowLocomotiveImage(boolean showLocomotiveImage) { + this.showLocomotiveImage = showLocomotiveImage; + fireStateChanged(); + } + + @Override + public boolean isShowAccessoryValue() { + return showAccessoryValue; + } + + @Override + public void setShowAccessoryValue(boolean showAccessoryValue) { + this.showAccessoryValue = showAccessoryValue; + fireStateChanged(); + } + + @Override + public boolean isShowSignalValue() { + return showSignalValue; + } + + @Override + public void setShowSignalValue(boolean showSignalValue) { + this.showSignalValue = showSignalValue; + fireStateChanged(); + } + + @Override + public boolean isSensorActive() { + return sensorActive; + } + + @Override + public void setSensorActive(boolean sensorActive) { + this.sensorActive = sensorActive; + fireStateChanged(); + } + + @Override + public BlockState getBlockState() { + if (blockState == null) { + blockState = BlockState.FREE; + } + return blockState; + } + + @Override + public void setBlockState(BlockState blockState) { + this.blockState = blockState; + fireStateChanged(); + } + + @Override + public void addChangeListener(ChangeListener l) { + listenerList.add(ChangeListener.class, l); + } + + /** + * {@inheritDoc} + */ + @Override + public void removeChangeListener(ChangeListener l) { + listenerList.remove(ChangeListener.class, l); + } + + /** + * Returns an array of all the change listeners registered on this DefaultButtonModel. + * + * @return all of this model's ChangeListeners or an empty array if no change listeners are currently registered + * + * @see #addChangeListener + * @see #removeChangeListener + * + * @since 1.4 + */ + public ChangeListener[] getChangeListeners() { + return listenerList.getListeners(ChangeListener.class); + } + + /** + * Notifies all listeners that have registered interest for notification on this event type. The event instance is created lazily. + * + * @see EventListenerList + */ + protected void fireStateChanged() { + // Guaranteed to return a non-null array + Object[] listeners = listenerList.getListenerList(); + // Process the listeners last to first, notifying + // those that are interested in this event + for (int i = listeners.length - 2; i >= 0; i -= 2) { + if (listeners[i] == ChangeListener.class) { + // Lazily create the event: + if (changeEvent == null) { + changeEvent = new ChangeEvent(this); + } + ((ChangeListener) listeners[i + 1]).stateChanged(changeEvent); + } + } + } + + /** + * {@inheritDoc} + */ +// @Override +// public void addItemListener(ItemListener l) { +// listenerList.add(ItemListener.class, l); +// } + /** + * {@inheritDoc} + */ +// @Override +// public void removeItemListener(ItemListener l) { +// listenerList.remove(ItemListener.class, l); +// } + /** + * Returns an array of all the item listeners registered on this DefaultButtonModel. + * + * @return all of this model's ItemListeners or an empty array if no item listeners are currently registered + * + * @see #addItemListener + * @see #removeItemListener + * + * @since 1.4 + */ + public ItemListener[] getItemListeners() { + return listenerList.getListeners(ItemListener.class); + } + + @Override + public void addActionListener(ActionListener l) { + listenerList.add(ActionListener.class, l); + } + + @Override + public void removeActionListener(ActionListener l) { + listenerList.remove(ActionListener.class, l); + } + + @Override + public ActionListener[] getActionListeners() { + return listenerList.getListeners(ActionListener.class); + } + + /** + * Notifies all listeners that have registered interest for notification on this event type. + * + * @param e the ActionEvent to deliver to listeners + * @see EventListenerList + */ + protected void fireActionPerformed(ActionEvent e) { + // Guaranteed to return a non-null array + Object[] listeners = listenerList.getListenerList(); + // Process the listeners last to first, notifying + // those that are interested in this event + for (int i = listeners.length - 2; i >= 0; i -= 2) { + if (listeners[i] == ActionListener.class) { + // Lazily create the event: + // if (changeEvent == null) + // changeEvent = new ChangeEvent(this); + ((ActionListener) listeners[i + 1]).actionPerformed(e); + } + } + } + + /** + * Overridden to return null. + */ +// @Override +// public Object[] getSelectedObjects() { +// return null; +// } +} diff --git a/src/main/java/jcs/ui/layout/tiles/End.java b/src/main/java/jcs/ui/layout/tiles/End.java index 8e535bbc..91026af3 100644 --- a/src/main/java/jcs/ui/layout/tiles/End.java +++ b/src/main/java/jcs/ui/layout/tiles/End.java @@ -17,6 +17,7 @@ import java.awt.BasicStroke; import java.awt.Color; +import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.util.HashMap; @@ -24,25 +25,32 @@ import java.util.Map; import java.util.Set; import jcs.entities.TileBean; - -public class End extends AbstractTile implements Tile { - - End(TileBean tileBean) { - super(tileBean); - this.width = DEFAULT_WIDTH; - this.height = DEFAULT_HEIGHT; +import jcs.entities.TileBean.Orientation; +import static jcs.entities.TileBean.Orientation.NORTH; +import static jcs.entities.TileBean.Orientation.SOUTH; +import static jcs.entities.TileBean.Orientation.WEST; +import jcs.entities.TileBean.TileType; +import org.tinylog.Logger; + +public class End extends Tile { + + public End(TileBean tileBean) { + super(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); + setModel(new DefaultTileModel()); } - End(Orientation orientation, Point center) { + public End(Orientation orientation, Point center) { this(orientation, center.x, center.y); + } + public End(Orientation orientation, int x, int y) { + this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); } - End(Orientation orientation, int x, int y) { - super(orientation, x, y); - this.type = TileType.END.getTileType(); - this.width = DEFAULT_WIDTH; - this.height = DEFAULT_HEIGHT; + public End(Orientation orientation, int x, int y, int width, int height) { + super(TileType.END, orientation, x, y, width, height); + + setModel(new DefaultTileModel()); } @Override @@ -123,4 +131,21 @@ public void renderTile(Graphics2D g2) { public void renderTileRoute(Graphics2D g2d) { } + @Override + protected void paintComponent(Graphics g) { + long started = System.currentTimeMillis(); + super.paintComponent(g); + + setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); + + Graphics2D g2 = (Graphics2D) g.create(); + drawTile(g2); + g2.dispose(); + + g.drawImage(this.tileImage, 0, 0, null); + + long now = System.currentTimeMillis(); + Logger.trace(this.id + " Duration: " + (now - started) + " ms."); + } + } diff --git a/src/main/java/jcs/ui/layout/tiles/Sensor.java b/src/main/java/jcs/ui/layout/tiles/Sensor.java index dacc13a4..cb5e9cd0 100644 --- a/src/main/java/jcs/ui/layout/tiles/Sensor.java +++ b/src/main/java/jcs/ui/layout/tiles/Sensor.java @@ -25,30 +25,26 @@ import jcs.commandStation.events.SensorEventListener; import jcs.entities.SensorBean; import jcs.entities.TileBean; +import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean.TileType; public class Sensor extends Straight implements SensorEventListener { - private boolean active; - - Sensor(TileBean tileBean) { + public Sensor(TileBean tileBean) { super(tileBean); } - Sensor(Orientation orientation, int x, int y) { - this(orientation, new Point(x, y)); - } - - Sensor(Orientation orientation, Point center) { - super(orientation, center); - this.type = TileType.SENSOR.getTileType(); + public Sensor(Orientation orientation, Point center) { + this(orientation, center.x, center.y); } - public boolean isActive() { - return this.active; + public Sensor(Orientation orientation, int x, int y) { + this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); } - public void setActive(boolean active) { - this.active = active; + public Sensor(Orientation orientation, int x, int y, int width, int height) { + super(orientation, x, y, width, height); + this.tileType = TileType.SENSOR; } private void renderSensor(Graphics2D g2) { @@ -60,7 +56,7 @@ private void renderSensor(Graphics2D g2) { float radius = 300; float[] dist = {0.0f, 0.6f}; - if (this.active) { + if (model.isSensorActive()) { Color[] colors = {Color.red.brighter(), Color.red.darker()}; RadialGradientPaint foreground = new RadialGradientPaint(c, radius, dist, colors, CycleMethod.REFLECT); g2.setPaint(foreground); @@ -74,31 +70,24 @@ private void renderSensor(Graphics2D g2) { } @Override - public void renderTile(Graphics2D g2) { - Graphics2D g2d = (Graphics2D) g2.create(); - + public void renderTile(Graphics2D g2d) { renderStraight(g2d); - - if (drawRoute) { - renderTileRoute(g2); - } - renderSensor(g2d); - - g2d.dispose(); } @Override public void onSensorChange(SensorEvent event) { SensorBean sensor = event.getSensorBean(); if (sensor.equalsDeviceIdAndContactId(getSensorBean())) { - this.setActive(sensor.isActive()); - repaintTile(); + setActive(sensor.isActive()); + repaint(); } } + //Sensor must also listen to the mouse now it is a component.... + //in UI Delegate TODO! @Override public String toString() { - return this.getClass().getSimpleName() + " {id: " + id + ", orientation: " + getOrientation() + ", direction: " + getDirection() + ", active: " + active + ", center: (" + x + "," + y + ")}"; + return getClass().getSimpleName() + " {id: " + id + ", orientation: " + getOrientation() + ", direction: " + getDirection() + ", active: " + model.isSensorActive() + ", center: (" + tileX + "," + tileY + ")}"; } } diff --git a/src/main/java/jcs/ui/layout/tiles/Signal.java b/src/main/java/jcs/ui/layout/tiles/Signal.java index e9c0412f..1b7a5b49 100644 --- a/src/main/java/jcs/ui/layout/tiles/Signal.java +++ b/src/main/java/jcs/ui/layout/tiles/Signal.java @@ -22,7 +22,6 @@ import java.awt.Polygon; import jcs.commandStation.events.AccessoryEvent; import jcs.commandStation.events.AccessoryEventListener; -import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.SignalType; import static jcs.entities.AccessoryBean.SignalType.HP012; import static jcs.entities.AccessoryBean.SignalType.HP012SH1; @@ -33,19 +32,14 @@ import static jcs.entities.AccessoryBean.SignalValue.Hp1; import static jcs.entities.AccessoryBean.SignalValue.Hp2; import jcs.entities.TileBean; +import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean.TileType; import static jcs.ui.layout.tiles.Tile.RENDER_GRID; -public class Signal extends Straight implements Tile, AccessoryEventListener { - - private SignalValue signalValue; - private SignalType signalType; +public class Signal extends Straight implements AccessoryEventListener { Signal(TileBean tileBean) { super(tileBean); - if (tileBean.getAccessoryBean() != null) { - AccessoryBean ab = tileBean.getAccessoryBean(); - this.signalType = SignalType.getSignalType(ab.getType()); - } } Signal(Orientation orientation, int x, int y, SignalType signalType) { @@ -58,36 +52,9 @@ public class Signal extends Straight implements Tile, AccessoryEventListener { Signal(Orientation orientation, Point center, SignalType signalType) { super(orientation, center); + this.tileType = TileType.SIGNAL; this.signalType = signalType; this.signalValue = SignalValue.OFF; - this.type = TileType.SIGNAL.getTileType(); - } - - public SignalValue getSignalValue() { - return signalValue; - } - - @Override - public SignalType getSignalType() { - return signalType; - } - - public void setSignalValue(SignalValue signalValue) { - this.signalValue = signalValue; - } - - @Override - public void setAccessoryBean(AccessoryBean accessoryBean) { - this.accessoryBean = accessoryBean; - if (accessoryBean != null) { - this.accessoryId = accessoryBean.getId(); - this.signalValue = accessoryBean.getSignalValue(); - this.signalType = SignalType.getSignalType(accessoryBean.getType()); - } else { - this.accessoryId = null; - this.signalType = SignalType.NONE; - this.signalValue = SignalValue.OFF; - } } /** @@ -364,18 +331,14 @@ public void renderTile(Graphics2D g2) { renderSignal2(g2d); } - if (drawRoute) { - renderTileRoute(g2); - } - g2d.dispose(); } + //TODO move to UI delegate @Override public void onAccessoryChange(AccessoryEvent event) { - if (this.getAccessoryBean() != null && event.isEventFor(accessoryBean)) { - this.setSignalValue(event.getAccessoryBean().getSignalValue()); - repaintTile(); + if (getAccessoryBean() != null && event.isEventFor(accessoryBean)) { + setSignalValue(event.getAccessoryBean().getSignalValue()); } } } diff --git a/src/main/java/jcs/ui/layout/tiles/Straight.java b/src/main/java/jcs/ui/layout/tiles/Straight.java index db1646a0..6f8b3de6 100755 --- a/src/main/java/jcs/ui/layout/tiles/Straight.java +++ b/src/main/java/jcs/ui/layout/tiles/Straight.java @@ -16,6 +16,7 @@ package jcs.ui.layout.tiles; import java.awt.BasicStroke; +import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.util.HashMap; @@ -23,24 +24,28 @@ import java.util.Map; import java.util.Set; import jcs.entities.TileBean; +import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean.TileType; +import org.tinylog.Logger; -public class Straight extends AbstractTile implements Tile { +public class Straight extends Tile { - Straight(TileBean tileBean) { - super(tileBean); - this.width = DEFAULT_WIDTH; - this.height = DEFAULT_HEIGHT; + public Straight(TileBean tileBean) { + super(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); + setModel(new DefaultTileModel()); } - Straight(Orientation orientation, Point center) { + public Straight(Orientation orientation, Point center) { this(orientation, center.x, center.y); } - Straight(Orientation orientation, int x, int y) { - super(orientation, x, y); - this.type = TileType.STRAIGHT.getTileType(); - this.width = DEFAULT_WIDTH; - this.height = DEFAULT_HEIGHT; + public Straight(Orientation orientation, int x, int y) { + this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); + } + + public Straight(Orientation orientation, int x, int y, int width, int height) { + super(TileType.STRAIGHT, orientation, x, y, width, height); + setModel(new DefaultTileModel()); } @Override @@ -124,4 +129,21 @@ public void renderTile(Graphics2D g2) { renderStraight(g2); } + @Override + protected void paintComponent(Graphics g) { + long started = System.currentTimeMillis(); + super.paintComponent(g); + + setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); + + Graphics2D g2 = (Graphics2D) g.create(); + drawTile(g2); + g2.dispose(); + + g.drawImage(this.tileImage, 0, 0, null); + + long now = System.currentTimeMillis(); + Logger.trace(this.id + " Duration: " + (now - started) + " ms."); + } + } diff --git a/src/main/java/jcs/ui/layout/tiles/StraightDirection.java b/src/main/java/jcs/ui/layout/tiles/StraightDirection.java index fc5cb964..df3fbd01 100644 --- a/src/main/java/jcs/ui/layout/tiles/StraightDirection.java +++ b/src/main/java/jcs/ui/layout/tiles/StraightDirection.java @@ -21,20 +21,23 @@ import java.awt.Point; import java.util.Collection; import jcs.entities.TileBean; +import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean.TileType; public class StraightDirection extends Straight { - StraightDirection(TileBean tileBean) { + public StraightDirection(TileBean tileBean) { super(tileBean); + this.tileType = TileType.STRAIGHT_DIR; } - StraightDirection(Orientation orientation, int x, int y) { + public StraightDirection(Orientation orientation, int x, int y) { this(orientation, new Point(x, y)); } - StraightDirection(Orientation orientation, Point center) { + public StraightDirection(Orientation orientation, Point center) { super(orientation, center); - this.type = TileType.STRAIGHT_DIR.getTileType(); + this.tileType = TileType.STRAIGHT_DIR; } @Override @@ -71,18 +74,9 @@ private void renderDirectionArrow(Graphics2D g2) { } @Override - public void renderTile(Graphics2D g2) { - Graphics2D g2d = (Graphics2D) g2.create(); - + public void renderTile(Graphics2D g2d) { renderStraight(g2d); - renderDirectionArrow(g2d); - - if (drawRoute) { - renderTileRoute(g2); - } - - g2d.dispose(); } } diff --git a/src/main/java/jcs/ui/layout/tiles/Switch.java b/src/main/java/jcs/ui/layout/tiles/Switch.java index 3385847f..2a099a59 100644 --- a/src/main/java/jcs/ui/layout/tiles/Switch.java +++ b/src/main/java/jcs/ui/layout/tiles/Switch.java @@ -17,6 +17,7 @@ import java.awt.BasicStroke; import java.awt.Color; +import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.util.HashMap; @@ -29,30 +30,39 @@ import static jcs.entities.AccessoryBean.AccessoryValue.GREEN; import static jcs.entities.AccessoryBean.AccessoryValue.RED; import jcs.entities.TileBean; +import jcs.entities.TileBean.Direction; import static jcs.entities.TileBean.Direction.LEFT; import static jcs.entities.TileBean.Direction.RIGHT; +import jcs.entities.TileBean.Orientation; +import static jcs.entities.TileBean.Orientation.NORTH; +import static jcs.entities.TileBean.Orientation.SOUTH; +import static jcs.entities.TileBean.Orientation.WEST; +import jcs.entities.TileBean.TileType; +import org.tinylog.Logger; -public class Switch extends AbstractTile implements Tile, AccessoryEventListener { +public class Switch extends Tile implements AccessoryEventListener { - protected AccessoryValue accessoryValue; - protected AccessoryValue routeValue; - protected Color routeColor; + public Switch(TileBean tileBean) { + this(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); + } + + protected Switch(TileBean tileBean, int width, int height) { + super(tileBean, width, height); + setModel(new DefaultTileModel()); + } - Switch(TileBean tileBean) { - super(tileBean); - this.width = DEFAULT_WIDTH; - this.height = DEFAULT_HEIGHT; + public Switch(Orientation orientation, Direction direction, Point center) { + this(orientation, direction, center.x, center.y); } - Switch(Orientation orientation, Direction direction, int x, int y) { - this(orientation, direction, new Point(x, y)); + public Switch(Orientation orientation, Direction direction, int x, int y) { + this(orientation, direction, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); } - Switch(Orientation orientation, Direction direction, Point center) { - super(orientation, direction, center.x, center.y); - this.width = DEFAULT_WIDTH; - this.height = DEFAULT_HEIGHT; - this.type = TileType.SWITCH.getTileType(); + public Switch(Orientation orientation, Direction direction, int x, int y, int width, int height) { + super(TileType.SWITCH, orientation, direction, x, y, width, height); + + setModel(new DefaultTileModel()); } @Override @@ -162,30 +172,6 @@ public Set getAllPoints() { return aps; } - public AccessoryValue getAccessoryValue() { - if (this.accessoryValue == null) { - return AccessoryValue.OFF; - } else { - return accessoryValue; - } - } - - public void setValue(AccessoryValue value) { - this.accessoryValue = value; - } - - public AccessoryValue getRouteValue() { - if (routeValue == null) { - return AccessoryValue.OFF; - } else { - return routeValue; - } - } - - public void setRouteValue(AccessoryValue value) { - this.routeValue = value; - } - protected void renderStraight(Graphics2D g2, Color color) { int xx, yy, w, h; xx = 0; @@ -284,9 +270,8 @@ public void renderTileRoute(Graphics2D g2) { @Override public void onAccessoryChange(AccessoryEvent event) { - if (this.getAccessoryBean() != null && event.isEventFor(accessoryBean)) { - setValue(event.getAccessoryBean().getAccessoryValue()); - repaintTile(); + if (getAccessoryBean() != null && event.isEventFor(accessoryBean)) { + setAccessoryValue(event.getAccessoryBean().getAccessoryValue()); } } @@ -355,4 +340,21 @@ public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { return AccessoryValue.OFF; } } + + @Override + protected void paintComponent(Graphics g) { + long started = System.currentTimeMillis(); + super.paintComponent(g); + + setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); + + Graphics2D g2 = (Graphics2D) g.create(); + drawTile(g2); + g2.dispose(); + + g.drawImage(this.tileImage, 0, 0, null); + + long now = System.currentTimeMillis(); + Logger.trace(this.id + " Duration: " + (now - started) + " ms."); + } } diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java old mode 100644 new mode 100755 index 3de8030e..5274714b --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Frans Jacobs. + * Copyright 2024 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,23 +16,66 @@ package jcs.ui.layout.tiles; import java.awt.Color; +import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.Point; -import java.awt.Shape; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.geom.AffineTransform; +import java.awt.geom.Ellipse2D; +import java.awt.geom.PathIterator; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; import java.beans.PropertyChangeListener; +import java.io.Serializable; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Set; +import javax.swing.JComponent; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.AccessoryValue; +import jcs.entities.AccessoryBean.SignalType; +import jcs.entities.BlockBean; +import jcs.entities.BlockBean.BlockState; +import jcs.entities.SensorBean; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import jcs.entities.TileBean.TileType; +import jcs.ui.layout.LayoutUtil; +import jcs.ui.layout.events.TileEvent; +import jcs.ui.layout.events.TileEventListener; +import org.imgscalr.Scalr; +import org.imgscalr.Scalr.Method; +import org.imgscalr.Scalr.Mode; +import org.tinylog.Logger; /** - * @author frans + * Basic graphic element to display a track, turnout, etc on the screen.
+ * By default the drawing of a Tile is Horizontal from L to R or West to East.
+ * The default orientation is East. + * + *

+ * The default size of a Tile is 40 tileX 40 pixels.
+ * The center point of a Tile is stored and always snapped to the nearest grid point.
+ * The basic grid is 20x 20 pixels.
+ * + *

+ * A Tile can be rotated (always clockwise).
+ * Rotation will change the orientation from East -> South -> West -> North -> East.
+ * + *

+ * A Tile is rendered to a Buffered Image to speed up the display */ -public interface Tile extends Shape { +public abstract class Tile extends JComponent implements TileEventListener { //, ItemSelectable { public static final int GRID = 20; public static final int DEFAULT_WIDTH = GRID * 2; @@ -45,177 +88,1158 @@ public interface Tile extends Shape { public static final Color DEFAULT_BACKGROUND_COLOR = Color.white; public static final Color DEFAULT_TRACK_COLOR = Color.lightGray; public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.blue; + public static final Color DEFAULT_SELECTED_COLOR = Color.yellow; - boolean isDrawRoute(); - - void setDrawRoute(boolean drawRoute); + public static final String MODEL_CHANGED_PROPERTY = "model"; + public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled"; - Color getTrackColor(); - - void setTrackColor(Color trackColor); + /** + * The data model that determines the button's state. + */ + protected TileModel model = null; - Color getTrackRouteColor(); + protected String id; + protected Integer tileX; + protected Integer tileY; - void setTrackRouteColor(Color trackRouteColor); + protected int renderWidth; + protected int renderHeight; - Orientation getIncomingSide(); + protected Orientation tileOrientation; + protected Direction tileDirection; - void setIncomingSide(Orientation incomingSide); + protected TileType tileType; + protected String accessoryId; + protected String sensorId; - Color getBackgroundColor(); + protected AccessoryValue accessoryValue; + protected AccessoryValue routeValue; - void setBackgroundColor(Color backgroundColor); + protected SignalType signalType; + protected AccessoryBean.SignalValue signalValue; - String getId(); + protected AccessoryBean accessoryBean; + protected SensorBean sensorBean; + protected BlockBean blockBean; - void setId(String id); + protected List neighbours; - //String getImageKey(); - - BufferedImage getTileImage(); + protected int offsetX = 0; + protected int offsetY = 0; - void drawTile(Graphics2D g2d, boolean drawOutline); + protected int renderOffsetX = 0; + protected int renderOffsetY = 0; - void renderTile(Graphics2D g2d); + protected Color selectedColor; + protected Color trackColor; + protected Color trackRouteColor; + protected Orientation incomingSide; - void renderTileRoute(Graphics2D g2d); + protected Color backgroundColor; + protected boolean drawName = true; - void drawName(Graphics2D g2); + protected BufferedImage tileImage; - void drawCenterPoint(Graphics2D g2d); + protected PropertyChangeListener propertyChangeListener; - void drawCenterPoint(Graphics2D g2, Color color); + protected ChangeListener changeListener = null; + protected ActionListener actionListener = null; + //protected ItemListener itemListener = null; - void drawCenterPoint(Graphics2D g2d, Color color, double size); + protected transient ChangeEvent changeEvent; - void drawBounds(Graphics2D g2d); + private Handler handler; - void rotate(); + protected Tile(TileType tileType, Point center) { + this(tileType, Orientation.EAST, Direction.CENTER, center.x, center.y, DEFAULT_WIDTH, DEFAULT_HEIGHT); + } + + protected Tile(TileType tileType, Orientation orientation, Point center, int width, int height) { + this(tileType, orientation, Direction.CENTER, center.x, center.y, width, height); + } + + protected Tile(TileType tileType, Orientation orientation, int x, int y, int width, int height) { + this(tileType, orientation, Direction.CENTER, x, y, width, height); + } + + protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { + this(tileType, orientation, direction, x, y, width, height, null, null); + } + + protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height, Color backgroundColor, Color selectedColor) { + this.setLayout(null); + this.tileType = tileType; + + this.tileOrientation = orientation; + this.tileDirection = direction; + + this.tileX = x; + this.tileY = y; + + Dimension d = new Dimension(width, height); + this.setSize(d); + this.setPreferredSize(d); + + this.renderWidth = RENDER_WIDTH; + this.renderHeight = RENDER_HEIGHT; + + this.trackColor = DEFAULT_TRACK_COLOR; + this.backgroundColor = backgroundColor; + this.selectedColor = selectedColor; + + if (this.backgroundColor == null) { + this.backgroundColor = DEFAULT_BACKGROUND_COLOR; + } + if (this.selectedColor == null) { + this.selectedColor = DEFAULT_SELECTED_COLOR; + } + } + + protected Tile(Object tileBean) { + this(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); + } + + protected Tile(Object tileBean, int width, int height) { + copyInto(tileBean); + setLayout(null); + Dimension d = new Dimension(width, height); + this.setSize(d); + this.setPreferredSize(d); + + this.trackColor = DEFAULT_TRACK_COLOR; + this.backgroundColor = DEFAULT_BACKGROUND_COLOR; + this.selectedColor = DEFAULT_SELECTED_COLOR; + this.renderWidth = RENDER_WIDTH; + this.renderHeight = RENDER_HEIGHT; + } + + private void copyInto(Object object) { + if (object instanceof TileBean other) { + this.id = other.getId(); + this.tileType = other.getTileType(); + this.tileOrientation = other.getOrientation(); + this.tileOrientation = other.getOrientation(); + this.tileDirection = other.getDirection(); + this.tileDirection = other.getDirection(); + this.tileX = other.getX(); + this.tileY = other.getY(); + + this.signalType = other.getSignalType(); + this.accessoryId = other.getAccessoryId(); + this.sensorId = other.getSensorId(); + this.accessoryBean = other.getAccessoryBean(); + this.sensorBean = other.getSensorBean(); + this.blockBean = other.getBlockBean(); + + if (other.getAccessoryBean() != null) { + AccessoryBean ab = other.getAccessoryBean(); + this.signalType = SignalType.getSignalType(ab.getType()); + } + + } + + if (object instanceof Tile tile) { + this.renderWidth = tile.renderWidth; + this.renderHeight = tile.renderHeight; + } + + } + + public TileBean getTileBean() { + TileBean tb = new TileBean(); + tb.setId(this.id); + tb.setX(this.tileX); + tb.setY(this.tileY); + tb.setTileType(this.tileType); + tb.setTileOrientation(this.tileOrientation.getOrientation()); + tb.setTileDirection(this.tileDirection.getDirection()); + tb.setSignalType(this.signalType); + tb.setAccessoryId(this.accessoryId); + tb.setSensorId(this.sensorId); + tb.setAccessoryBean(this.accessoryBean); + tb.setSensorBean(this.sensorBean); + tb.setBlockBean(this.blockBean); + + return tb; + } + + public boolean isSelected() { + return model.isSelected(); + } + + public void setSelected(boolean b) { + //boolean oldValue = isSelected(); + model.setSelected(b); + } + + @Override + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public SignalType getSignalType() { + return this.signalType; + } + + public void setSignalType(SignalType signalType) { + this.signalType = signalType; + } + + public Integer getTileX() { + return tileX; + } + + public void setTileX(Integer x) { + this.tileX = x; + } + + public Integer getTileY() { + return tileY; + } + + public void setTileY(Integer y) { + this.tileY = y; + } + + public Point getCenter() { + return new Point(this.tileX, this.tileY); + } + + public void setCenter(Point center) { + this.tileX = center.x; + this.tileY = center.y; + } + + public Orientation getOrientation() { + return tileOrientation; + } + + public void setOrientation(Orientation orientation) { + this.tileOrientation = orientation; + } + + public Direction getDirection() { + return tileDirection; + } + + public void setDirection(Direction direction) { + this.tileDirection = direction; + } + + public String getAccessoryId() { + return accessoryId; + } + + public void setAccessoryId(String accessoryId) { + this.accessoryId = accessoryId; + } + + public String getSensorId() { + return sensorId; + } + + public void setSensorId(String sensorId) { + this.sensorId = sensorId; + } + + public boolean isActive() { + return model.isSensorActive(); + } + + public void setActive(boolean active) { + this.model.setSensorActive(active); + } + + public BlockState getBlockState() { + return this.model.getBlockState(); + } + + public void setBlockState(BlockState blockState) { + this.model.setBlockState(blockState); + } + + public AccessoryBean getAccessoryBean() { + return accessoryBean; + } + + public void setAccessoryBean(AccessoryBean accessoryBean) { + this.accessoryBean = accessoryBean; + + if (accessoryBean != null) { + this.accessoryId = accessoryBean.getId(); + this.signalValue = accessoryBean.getSignalValue(); + this.signalType = SignalType.getSignalType(accessoryBean.getType()); + } else { + this.accessoryId = null; + this.signalType = SignalType.NONE; + this.signalValue = AccessoryBean.SignalValue.OFF; + } + } + + public AccessoryValue getAccessoryValue() { + if (this.accessoryValue == null) { + return AccessoryValue.OFF; + } else { + return accessoryValue; + } + } + + public void setAccessoryValue(AccessoryValue value) { + this.accessoryValue = value; + repaint(); + } + + public AccessoryValue getRouteValue() { + if (routeValue == null) { + return AccessoryValue.OFF; + } else { + return routeValue; + } + } + + public void setRouteValue(AccessoryValue value) { + this.routeValue = value; + repaint(); + } + + public AccessoryBean.SignalValue getSignalValue() { + return signalValue; + } + + public void setSignalValue(AccessoryBean.SignalValue signalValue) { + this.signalValue = signalValue; + this.repaint(); + } + + public SensorBean getSensorBean() { + return sensorBean; + } + + public void setSensorBean(SensorBean sensorBean) { + this.sensorBean = sensorBean; + } + + public BlockBean getBlockBean() { + return blockBean; + } + + public void setBlockBean(BlockBean blockBean) { + this.blockBean = blockBean; + } + + public void setRenderWidth(int renderWidth) { + this.renderWidth = renderWidth; + } + + public void setRenderHeight(int renderHeight) { + this.renderHeight = renderHeight; + } + + public int getRenderOffsetX() { + return renderOffsetX; + } + + public void setRenderOffsetX(int renderOffsetX) { + this.renderOffsetX = renderOffsetX; + } + + public int getRenderOffsetY() { + return renderOffsetY; + } + + public void setRenderOffsetY(int renderOffsetY) { + this.renderOffsetY = renderOffsetY; + } + + public TileBean.TileType getTileType() { + return this.tileType; + } + + public final void setTileType(TileType tileType) { + this.tileType = tileType; + } + + public Color getTrackColor() { + return trackColor; + } + + public final void setTrackColor(Color trackColor) { + this.trackColor = trackColor; + } + + public Color getTrackRouteColor() { + return trackRouteColor; + } + + public void setTrackRouteColor(Color trackRouteColor) { + this.trackRouteColor = trackRouteColor; + } + + public Color getSelectedColor() { + return selectedColor; + } + + public void setSelectedColor(Color selectedColor) { + this.selectedColor = selectedColor; + } - void flipHorizontal(); + public Orientation getIncomingSide() { + return incomingSide; + } - void flipVertical(); + public void setIncomingSide(Orientation incomingSide) { + this.incomingSide = incomingSide; + } - void move(int newX, int newY); + public Color getBackgroundColor() { + return backgroundColor; + } - TileBean.Orientation getOrientation(); + public void setBackgroundColor(Color backgroundColor) { + this.backgroundColor = backgroundColor; + } - void setOrientation(TileBean.Orientation orientation); + public boolean isDrawRoute() { + return this.model.isShowRoute(); + } - Direction getDirection(); + public void setDrawRoute(boolean drawRoute) { + this.model.setShowRoute(drawRoute); + } - void setDirection(Direction direction); + public int getRenderWidth() { + return renderWidth; + } - Point getCenter(); + public int getRenderHeight() { + return renderHeight; + } - void setCenter(Point center); + abstract void renderTile(Graphics2D g2d); - /** - * @return a Set of alternative points in case the tile is not a square - */ - Set getAltPoints(); + abstract void renderTileRoute(Graphics2D g2d); /** - * @return All points relevant for the Object on the Canvas - */ - Set getAllPoints(); - - int getOffsetX(); - - void setOffsetX(int offsetX); - - int getOffsetY(); - - void setOffsetY(int offsetY); - - int getHeight(); - - int getWidth(); - - /** - * @return the X (pixel) coordinate of the center of the tile + * Draw the Tile + * + * @param g2d The graphics handle */ - int getCenterX(); + //@Override + public void drawTile(Graphics2D g2d) { + // by default and image is rendered in the EAST orientation + Orientation o = getOrientation(); + if (o == null) { + o = Orientation.EAST; + } + + tileImage = createImage(); + Graphics2D g2di = tileImage.createGraphics(); + + //Avoid errors + if (model.isShowRoute() && incomingSide == null) { + incomingSide = getOrientation(); + } + + if (model.isSelected()) { + g2di.setBackground(selectedColor); + } else { + g2di.setBackground(backgroundColor); + } + + g2di.clearRect(0, 0, renderWidth, renderHeight); + int ox = 0, oy = 0; + + AffineTransform trans = new AffineTransform(); + switch (o) { + case SOUTH -> { + trans.rotate(Math.PI / 2, renderWidth / 2, renderHeight / 2); + ox = (renderHeight - renderWidth) / 2; + oy = (renderWidth - renderHeight) / 2; + trans.translate(-ox, -oy); + } + case WEST -> { + trans.rotate(Math.PI, renderWidth / 2, renderHeight / 2); + trans.translate(ox, oy); + } + case NORTH -> { + trans.rotate(-Math.PI / 2, renderWidth / 2, renderHeight / 2); + ox = (renderHeight - renderWidth) / 2; + oy = (renderWidth - renderHeight) / 2; + trans.translate(-ox, -oy); + } + default -> { + //trans.rotate(0.0, this.renderWidth / 2, this.renderHeight / 2); + //trans.translate(ox, oy); + } + } + + g2di.setTransform(trans); + + renderTile(g2di); + + if (model.isShowRoute()) { + renderTileRoute(g2di); + } + + if (model.isShowCenter()) { + drawCenterPoint(g2di); + } + + // Scale the image back... + if (this.model.isScaleImage()) { + tileImage = Scalr.resize(tileImage, Method.AUTOMATIC, Mode.FIT_EXACT, getWidth(), getHeight(), Scalr.OP_ANTIALIAS); + } + + g2di.dispose(); + +// int oxx, oyy; +// if (scaleImage) { +// oxx = offsetX; +// oyy = offsetY; +// } else { +// oxx = renderOffsetX; +// oyy = renderOffsetY; +// } + //g2d.drawImage(tileImage, (tileX - tileImage.getWidth() / 2) + oxx, (tileY - tileImage.getHeight() / 2) + oyy, null); + } + + public BufferedImage getTileImage() { + return tileImage; + } /** - * @return then Y (pixel) coordinate of the center of the tile + * Render a tile image Always starts at (0,0) used the default width and height + * + * @param g2 the Graphic context */ - int getCenterY(); + public void drawName(Graphics2D g2) { + } - TileBean getTileBean(); + protected void drawCenterPoint(Graphics2D g2d) { + drawCenterPoint(g2d, Color.magenta); + } - boolean isDrawOutline(); + protected void drawCenterPoint(Graphics2D g2, Color color) { + drawCenterPoint(g2, color, 60); + } - void setDrawOutline(boolean drawOutline); + protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { + double dX = (renderWidth / 2 - size / 2); + double dY = (renderHeight / 2 - size / 2); - TileType getTileType(); - - void setPropertyChangeListener(PropertyChangeListener listener); - - String xyToString(); + g2d.setColor(color); + g2d.fill(new Ellipse2D.Double(dX, dY, size, size)); + } /** - * @return the X number of the grid square (grid is 40 x 40 pix) + * Rotate the tile clockwise 90 deg */ - int getGridX(); + public void rotate() { + rotate(true); + } /** - * @return the Y number of the grid square (grid is 40 x 40 pix) + * Rotate the tile clockwise 90 deg */ - int getGridY(); + void rotate(boolean repaint) { + + switch (getOrientation()) { + case EAST -> + setOrientation(Orientation.SOUTH); + case SOUTH -> + setOrientation(Orientation.WEST); + case WEST -> + setOrientation(Orientation.NORTH); + default -> + setOrientation(Orientation.EAST); + } + if (repaint) { + repaint(); + } + } + + public void flipHorizontal() { + if (Orientation.NORTH.equals(getOrientation()) || Orientation.SOUTH.equals(getOrientation())) { + rotate(false); + rotate(true); + } + } + + public void flipVertical() { + if (Orientation.EAST.equals(getOrientation()) || Orientation.WEST.equals(getOrientation())) { + rotate(false); + rotate(true); + } + } + + @Override + public void move(int newX, int newY) { + Point cs = LayoutUtil.snapToGrid(newX, newY); + setCenter(cs); + } + + protected static void drawRotate(Graphics2D g2d, double x, double y, int angle, String text) { + g2d.translate((float) x, (float) y); + g2d.rotate(Math.toRadians(angle)); + g2d.drawString(text, 0, 0); + g2d.rotate(-Math.toRadians(angle)); + g2d.translate(-x, -y); + } + + public static BufferedImage flipHorizontally(BufferedImage source) { + BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); + + AffineTransform flip = AffineTransform.getScaleInstance(1, -1); + flip.translate(0, -source.getHeight()); + AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); + + op.filter(source, output); + + return output; + } + + public static BufferedImage flipVertically(BufferedImage source) { + BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); + + AffineTransform flip = AffineTransform.getScaleInstance(-1, 1); + flip.translate(-source.getWidth(), 0); + AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); + + op.filter(source, output); + + return output; + } + + public Set getAltPoints() { + return Collections.EMPTY_SET; + } + + public final int getOffsetX() { + return offsetX; + } + + public void setOffsetX(int offsetX) { + this.offsetX = offsetX; + } + + public final int getOffsetY() { + return offsetY; + } + + public void setOffsetY(int offsetY) { + this.offsetY = offsetY; + } + + protected BufferedImage createImage() { + return new BufferedImage(renderWidth, renderHeight, BufferedImage.TYPE_INT_RGB); + } + + public int getCenterX() { + if (this.tileX > 0) { + return this.tileX; + } else { + return GRID; + } + } + + public int getCenterY() { + if (this.tileY > 0) { + return this.tileY; + } else { + return GRID; + } + } + + public boolean isDrawName() { + return drawName; + } + + public void setDrawName(boolean drawName) { + this.drawName = drawName; + } + + public boolean isScaleImage() { + return model.isScaleImage(); + } + + public void setScaleImage(boolean scaleImage) { + Dimension d; + if (scaleImage) { + d = new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); + } else { + d = new Dimension(renderWidth, renderHeight); + } + + setSize(d); + setPreferredSize(d); + + model.setScaleImage(scaleImage); + } + + public boolean isDrawCenterPoint() { + return model.isShowCenter(); + } + + public void setDrawCenterPoint(boolean drawCenterPoint) { + model.setShowCenter(drawCenterPoint); + } + + @Override + public String toString() { + return this.getClass().getSimpleName() + + " {id: " + + this.id + + ", orientation: " + + getOrientation() + + ", direction: " + + getDirection() + + ", center: " + + xyToString() + + "}"; + } + + @Override + public Rectangle getBounds() { + int w, h, cx, cy; + //TODO: Check this may by the componet does this already + if (this.getWidth() > 0 & this.getHeight() > 0) { + //if (this.width > 0 & this.height > 0) { + //w = this.width; + w = this.getPreferredSize().width; + //h = this.height; + h = this.getPreferredSize().height; + } else { + w = DEFAULT_WIDTH; + h = DEFAULT_HEIGHT; + } + + if (this.tileX > 0 && this.tileY > 0) { + cx = this.tileX + this.offsetX; + cy = this.tileY + this.offsetY; + } else { + cx = w / 2; + cy = h / 2; + } + + int ltx = cx - w / 2; + int lty = cy - h / 2; + return new Rectangle(ltx, lty, w, h); + } + + public Rectangle2D getBounds2D() { + return getBounds().getBounds2D(); + } + + public boolean contains(double x, double y) { + int w, h, cx, cy, tlx, tly; + if (this.getWidth() > 0 & this.getHeight() > 0) { + //if (this.width > 0 & this.height > 0) { +// w = this.width; +// h = this.height; + w = this.getPreferredSize().width; + h = this.getPreferredSize().height; + + } else { + w = DEFAULT_WIDTH; + h = DEFAULT_HEIGHT; + } + + if (this.getWidth() > 0 & this.getHeight() > 0) { + //if (this.width > 0 & this.height > 0) { + cx = this.tileX; + cy = this.tileY; + } else { + cx = w / 2; + cy = h / 2; + } + + // top left dX and dY + tlx = cx - w / 2; + tly = cy - h / 2; + + // Check if X and Y range is ok + return !(x < tlx || x > (tlx + w) || y < tly || y > (tly + h)); + } + + public String xyToString() { + return "(" + this.tileX + "," + this.tileY + ")"; + } + + public boolean contains(Point2D p) { + return this.contains(p.getX(), p.getY()); + } + + public boolean intersects(double x, double y, double w, double h) { + return getBounds().intersects(x, y, w, h); + } + + public boolean intersects(Rectangle2D r2d) { + return getBounds().intersects(r2d); + } + + public boolean contains(double x, double y, double w, double h) { + return getBounds().contains(x, y, w, h); + } + + public boolean contains(Rectangle2D r2d) { + return getBounds().contains(r2d); + } + + public PathIterator getPathIterator(AffineTransform at) { + return getBounds().getPathIterator(at); + } + + public PathIterator getPathIterator(AffineTransform at, double flatness) { + return getBounds().getPathIterator(at, flatness); + } + + @Deprecated + public PropertyChangeListener getPropertyChangeListener() { + return this.propertyChangeListener; + } + + @Deprecated + public void setPropertyChangeListener(PropertyChangeListener propertyChangeListener) { + this.propertyChangeListener = propertyChangeListener; + } + + @Deprecated + public void repaintTile() { +// if (this.propertyChangeListener != null) { +// this.propertyChangeListener.propertyChange(new PropertyChangeEvent(this, "repaintTile", this, this)); +// } + } + + @Override + @Deprecated + public void onTileChange(TileEvent tileEvent) { + Logger.warn("Deprecated! " + tileEvent.getTileId()); + if (tileEvent.isEventFor(this)) { + boolean drawRoute = tileEvent.isShowRoute(); + setIncomingSide(tileEvent.getIncomingSide()); + + if (isJunction()) { + // setRouteValue(tileEvent.getRouteState()); + } + + if (tileEvent.getBlockBean() != null) { + this.setBlockBean(tileEvent.getBlockBean()); + } + + if (tileEvent.getTileBean() != null) { + TileBean other = tileEvent.getTileBean(); + this.copyInto(other); + } + + if (isBlock()) { + // ((Block) this).setRouteBlockState(tileEvent.getBlockState()); + if (!drawRoute) { + // ((Block) this).setRouteBlockState(null); + } + } + + setBackgroundColor(tileEvent.getBackgroundColor()); + setTrackColor(tileEvent.getTrackColor()); + setTrackRouteColor(tileEvent.getTrackRouteColor()); + +// if (tileEvent.getBlockBean() != null) { +// setBlockBean(tileEvent.getBlockBean()); +// } +// repaintTile(); + } + } + + public int getGridX() { + return (getCenterX() - Tile.GRID) / (Tile.GRID * 2); + } + + public int getGridY() { + return (getCenterY() - Tile.GRID) / (Tile.GRID * 2); + } /** * The main route of the tile is horizontal * * @return true when main route goes from East to West or vv */ - boolean isHorizontal(); + public boolean isHorizontal() { + return (Orientation.EAST == getOrientation() || Orientation.WEST == getOrientation()) && TileType.CURVED != getTileType(); + } /** * The main route of the tile is vertical * * @return true when main route goes from North to South or vv */ - boolean isVertical(); + public boolean isVertical() { + return (Orientation.NORTH == getOrientation() || Orientation.SOUTH == getOrientation()) && TileType.CURVED != getTileType(); + } + + public boolean isJunction() { + return false; + } + + public boolean isBlock() { + return false; + } + + public boolean isDirectional() { + return false; + } /** * The main route of the tile is diagonal * * @return true when main route goes from North to East or West to South and vv */ - boolean isDiagonal(); + public boolean isDiagonal() { + return TileType.CURVED == getTileType(); + } - boolean isJunction(); + public boolean isCrossing() { + return TileType.CROSSING == getTileType(); + } - boolean isBlock(); + public List getNeighbours() { + return this.neighbours; + } - boolean isDirectional(); + public void setNeighbours(List neighbours) { + this.neighbours = neighbours; + } - boolean isCrossing(); + public String getIdSuffix(Tile other) { + return ""; + } - Map getNeighborPoints(); + public Map getNeighborOrientations() { + Map edgeOrientations = new HashMap<>(); - Map getNeighborOrientations(); + Map neighborPoints = getNeighborPoints(); - Map getEdgePoints(); + for (Orientation o : Orientation.values()) { + edgeOrientations.put(neighborPoints.get(o), o); + } + return edgeOrientations; + } - Map getEdgeOrientations(); + public Map getEdgeOrientations() { + Map edgeOrientations = new HashMap<>(); - AccessoryValue accessoryValueForRoute(Orientation from, Orientation to); + Map edgeConnections = getEdgePoints(); - /** - * @param other a tile to check with this tile - * @return true when the other tile is adjacent to this and the "tracks" connect - */ - boolean isAdjacent(Tile other); + for (Orientation o : Orientation.values()) { + edgeOrientations.put(edgeConnections.get(o), o); + } + return edgeOrientations; + } + + public boolean isAdjacent(Tile other) { + boolean adjacent = false; - String getIdSuffix(Tile other); + if (other != null) { + Collection thisEdgePoints = getEdgePoints().values(); + Collection otherEdgePoints = other.getEdgePoints().values(); + + for (Point p : thisEdgePoints) { + adjacent = otherEdgePoints.contains(p); + if (adjacent) { + break; + } + } + } + + return adjacent; + } /** - * When the tile has a specific direction a train may travel then this method will indicate whether the other tile is in on the side where the arrow is pointing to + * When the tile has a specific direction a train may travel,
+ * then this method will indicate whether the other tile is in on the side where the arrow is pointing to. * * @param other A Tile * @return true where other is on the side of this tile where the arrow points to */ - boolean isArrowDirection(Tile other); + public boolean isArrowDirection(Tile other) { + return true; + } + + public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { + return AccessoryValue.OFF; + } + + @Deprecated + protected StringBuilder getImageKeyBuilder() { + StringBuilder sb = new StringBuilder(); + //sb.append(id); + sb.append(this.tileType); + sb.append("~"); + sb.append(getOrientation().getOrientation()); + sb.append("~"); + sb.append(getDirection().getDirection()); + //sb.append("~"); + //sb.append(isDrawOutline() ? "y" : "n"); + sb.append("~"); + int r = backgroundColor.getRed(); + int g = backgroundColor.getGreen(); + int b = backgroundColor.getBlue(); + sb.append("#"); + sb.append(r); + sb.append("#"); + sb.append(g); + sb.append("#"); + sb.append(b); + sb.append("~"); + r = trackColor.getRed(); + g = trackColor.getGreen(); + b = trackColor.getBlue(); + sb.append("#"); + sb.append(r); + sb.append("#"); + sb.append(g); + sb.append("#"); + sb.append(b); + sb.append("~"); + sb.append(isDrawRoute() ? "y" : "n"); + if (isDrawRoute()) { + if (incomingSide != null) { + sb.append("~"); + sb.append(incomingSide.getOrientation()); + } + sb.append("~"); + r = trackRouteColor.getRed(); + g = trackRouteColor.getGreen(); + b = trackRouteColor.getBlue(); + sb.append("#"); + sb.append(r); + sb.append("#"); + sb.append(g); + sb.append("#"); + sb.append(b); + } + + //sb.append("~"); + //Tile specific properties + //AccessoryValue + //SignalType + //SignalValue + //active; + //Logger.trace(sb); + return sb; + } + + public abstract Map getNeighborPoints(); + + public abstract Map getEdgePoints(); + + public abstract Set getAllPoints(); + + public TileModel getModel() { + return model; + } + + public void setModel(TileModel newModel) { + TileModel oldModel = getModel(); + + if (oldModel != null) { + oldModel.removeChangeListener(changeListener); + oldModel.removeActionListener(actionListener); + changeListener = null; + actionListener = null; + } + + model = newModel; + + if (newModel != null) { + changeListener = createChangeListener(); + actionListener = createActionListener(); + + newModel.addChangeListener(changeListener); + newModel.addActionListener(actionListener); + } + + firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel); + if (newModel != oldModel) { + revalidate(); + repaint(); + } + } + +// public TileUI getUI() { +// return (TileUI) ui; +// } +// public void setUI(TileUI ui) { +// super.setUI(ui); +// } + @Override + public void updateUI() { + } + + protected ChangeListener createChangeListener() { + return getHandler(); + } + + protected ActionListener createActionListener() { + return getHandler(); + } + + private Handler getHandler() { + if (handler == null) { + handler = new Handler(); + } + return handler; + } + + class Handler implements ActionListener, ChangeListener, Serializable { + + @Override + public void stateChanged(ChangeEvent e) { + Object source = e.getSource(); + + fireStateChanged(); + repaint(); + } + + @Override + public void actionPerformed(ActionEvent event) { + fireActionPerformed(event); + } + } + + protected void fireStateChanged() { + Object[] listeners = listenerList.getListenerList(); + //reverse order + for (int i = listeners.length - 2; i >= 0; i -= 2) { + if (listeners[i] == ChangeListener.class) { + // Lazily create the event: + if (changeEvent == null) { + changeEvent = new ChangeEvent(this); + } + ((ChangeListener) listeners[i + 1]).stateChanged(changeEvent); + } + } + } + + protected void fireActionPerformed(ActionEvent event) { + Object[] listeners = listenerList.getListenerList(); + ActionEvent e = null; + // reverse + for (int i = listeners.length - 2; i >= 0; i -= 2) { + if (listeners[i] == ActionListener.class) { + // Lazily create the event: + if (e == null) { + String actionCommand = event.getActionCommand(); + //if(actionCommand == null) { + // actionCommand = getActionCommand(); + //} + e = new ActionEvent(Tile.this, ActionEvent.ACTION_PERFORMED, actionCommand, event.getWhen(), event.getModifiers()); + } + ((ActionListener) listeners[i + 1]).actionPerformed(e); + } + } + } + } diff --git a/src/main/java/jcs/ui/layout/tiles/Tile1.java b/src/main/java/jcs/ui/layout/tiles/Tile1.java new file mode 100644 index 00000000..b01cb9be --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/Tile1.java @@ -0,0 +1,221 @@ +/* + * Copyright 2023 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Shape; +import java.awt.image.BufferedImage; +import java.beans.PropertyChangeListener; +import java.util.Map; +import java.util.Set; +import jcs.entities.AccessoryBean.AccessoryValue; +import jcs.entities.TileBean; +import jcs.entities.TileBean.Direction; +import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean.TileType; + +/** + * @author frans + */ +public interface Tile1 extends Shape { + + public static final int GRID = 20; + public static final int DEFAULT_WIDTH = GRID * 2; + public static final int DEFAULT_HEIGHT = GRID * 2; + + static final int RENDER_GRID = GRID * 10; + static final int RENDER_WIDTH = RENDER_GRID * 2; + static final int RENDER_HEIGHT = RENDER_GRID * 2; + + public static final Color DEFAULT_BACKGROUND_COLOR = Color.white; + public static final Color DEFAULT_TRACK_COLOR = Color.lightGray; + public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.blue; + + boolean isDrawRoute(); + + void setDrawRoute(boolean drawRoute); + + Color getTrackColor(); + + void setTrackColor(Color trackColor); + + Color getTrackRouteColor(); + + void setTrackRouteColor(Color trackRouteColor); + + Orientation getIncomingSide(); + + void setIncomingSide(Orientation incomingSide); + + Color getBackgroundColor(); + + void setBackgroundColor(Color backgroundColor); + + String getId(); + + void setId(String id); + + //String getImageKey(); + + BufferedImage getTileImage(); + + void drawTile(Graphics2D g2d, boolean drawOutline); + + void renderTile(Graphics2D g2d); + + void renderTileRoute(Graphics2D g2d); + + void drawName(Graphics2D g2); + + void drawCenterPoint(Graphics2D g2d); + + void drawCenterPoint(Graphics2D g2, Color color); + + void drawCenterPoint(Graphics2D g2d, Color color, double size); + + void drawBounds(Graphics2D g2d); + + void rotate(); + + void flipHorizontal(); + + void flipVertical(); + + void move(int newX, int newY); + + TileBean.Orientation getOrientation(); + + void setOrientation(TileBean.Orientation orientation); + + Direction getDirection(); + + void setDirection(Direction direction); + + Point getCenter(); + + void setCenter(Point center); + + /** + * @return a Set of alternative points in case the tile is not a square + */ + Set getAltPoints(); + + /** + * @return All points relevant for the Object on the Canvas + */ + Set getAllPoints(); + + int getOffsetX(); + + void setOffsetX(int offsetX); + + int getOffsetY(); + + void setOffsetY(int offsetY); + + int getHeight(); + + int getWidth(); + + /** + * @return the X (pixel) coordinate of the center of the tile + */ + int getCenterX(); + + /** + * @return then Y (pixel) coordinate of the center of the tile + */ + int getCenterY(); + + TileBean getTileBean(); + + boolean isDrawOutline(); + + void setDrawOutline(boolean drawOutline); + + TileType getTileType(); + + void setPropertyChangeListener(PropertyChangeListener listener); + + String xyToString(); + + /** + * @return the X number of the grid square (grid is 40 x 40 pix) + */ + int getGridX(); + + /** + * @return the Y number of the grid square (grid is 40 x 40 pix) + */ + int getGridY(); + + /** + * The main route of the tile is horizontal + * + * @return true when main route goes from East to West or vv + */ + boolean isHorizontal(); + + /** + * The main route of the tile is vertical + * + * @return true when main route goes from North to South or vv + */ + boolean isVertical(); + + /** + * The main route of the tile is diagonal + * + * @return true when main route goes from North to East or West to South and vv + */ + boolean isDiagonal(); + + boolean isJunction(); + + boolean isBlock(); + + boolean isDirectional(); + + boolean isCrossing(); + + Map getNeighborPoints(); + + Map getNeighborOrientations(); + + Map getEdgePoints(); + + Map getEdgeOrientations(); + + AccessoryValue accessoryValueForRoute(Orientation from, Orientation to); + + /** + * @param other a tile to check with this tile + * @return true when the other tile is adjacent to this and the "tracks" connect + */ + boolean isAdjacent(Tile1 other); + + String getIdSuffix(Tile1 other); + + /** + * When the tile has a specific direction a train may travel then this method will indicate whether the other tile is in on the side where the arrow is pointing to + * + * @param other A Tile + * @return true where other is on the side of this tile where the arrow points to + */ + boolean isArrowDirection(Tile1 other); +} diff --git a/src/main/java/jcs/ui/layout/tiles/TileFactory.java b/src/main/java/jcs/ui/layout/tiles/TileFactory.java index 6baece4f..203796ba 100755 --- a/src/main/java/jcs/ui/layout/tiles/TileFactory.java +++ b/src/main/java/jcs/ui/layout/tiles/TileFactory.java @@ -16,27 +16,16 @@ package jcs.ui.layout.tiles; import java.awt.Point; -import java.awt.event.MouseEvent; -import java.beans.PropertyChangeListener; -import java.util.HashMap; -import java.util.HashSet; import java.util.LinkedList; import java.util.List; -import java.util.Map; -import java.util.Set; import jcs.JCS; import jcs.commandStation.events.AccessoryEventListener; import jcs.commandStation.events.SensorEventListener; import jcs.entities.AccessoryBean; -import jcs.entities.AccessoryBean.AccessoryValue; -import jcs.entities.AccessoryBean.SignalValue; import jcs.entities.SensorBean; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; -import static jcs.entities.TileBean.Orientation.EAST; -import static jcs.entities.TileBean.Orientation.SOUTH; -import static jcs.entities.TileBean.Orientation.WEST; import static jcs.entities.TileBean.TileType.BLOCK; import static jcs.entities.TileBean.TileType.CROSS; import static jcs.entities.TileBean.TileType.CROSSING; @@ -47,11 +36,6 @@ import static jcs.entities.TileBean.TileType.STRAIGHT; import static jcs.entities.TileBean.TileType.STRAIGHT_DIR; import static jcs.entities.TileBean.TileType.SWITCH; -import jcs.persistence.PersistenceFactory; -import jcs.ui.layout.LayoutCanvas; -import jcs.ui.layout.LayoutUtil; -import jcs.ui.layout.events.TileEvent; -import jcs.ui.layout.events.TileEventListener; import org.tinylog.Logger; /** @@ -73,14 +57,11 @@ public class TileFactory { private static int straightDirectionIdSeq; private static int endIdSeq; - private static final Map tileEventListeners = new HashMap<>(); - - private static boolean drawOutline; - private static boolean showValues; - - public static final Map tiles = new HashMap<>(); - public static final Map altTiles = new HashMap<>(); - + //private static final Map tileEventListeners = new HashMap<>(); +// private static boolean drawOutline; +// private static boolean showValues; +// public static final Map tiles = new HashMap<>(); +// public static final Map altTiles = new HashMap<>(); private TileFactory() { } @@ -153,16 +134,16 @@ public static Tile createTile(String tileId) { } public static Tile createTile(TileBean tileBean) { - return createTile(tileBean, false, false); + return createTile(tileBean, false); } - public static Tile createTile(TileBean tileBean, boolean drawOutline, boolean showValues) { + public static Tile createTile(TileBean tileBean, boolean showValues) { if (tileBean == null) { return null; } TileBean.TileType tileType = tileBean.getTileType(); - AbstractTile tile = null; + Tile tile = null; switch (tileType) { case STRAIGHT -> { tile = new Straight(tileBean); @@ -182,7 +163,7 @@ public static Tile createTile(TileBean tileBean, boolean drawOutline, boolean sh switchIdSeq = maxIdSeq(switchIdSeq, nextIdSeq(tileBean.getId())); if (showValues && tileBean.getAccessoryBean() != null) { - ((Switch) tile).setValue((tileBean.getAccessoryBean()).getAccessoryValue()); + tile.setAccessoryValue((tileBean.getAccessoryBean()).getAccessoryValue()); } JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); } @@ -192,7 +173,7 @@ public static Tile createTile(TileBean tileBean, boolean drawOutline, boolean sh crossIdSeq = maxIdSeq(crossIdSeq, nextIdSeq(tileBean.getId())); if (showValues && tileBean.getAccessoryBean() != null) { - ((Switch) tile).setValue((tileBean.getAccessoryBean()).getAccessoryValue()); + tile.setAccessoryValue((tileBean.getAccessoryBean()).getAccessoryValue()); } JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); } @@ -232,12 +213,10 @@ public static Tile createTile(TileBean tileBean, boolean drawOutline, boolean sh Logger.warn("Unknown Tile Type " + tileType); } - if (tile != null) { - tile.setDrawOutline(drawOutline); - } - - addTileEventListener((TileEventListener) tile); - +// if (tile != null) { +// tile.setDrawOutline(drawOutline); +// } +// addTileEventListener((TileEventListener) tile); return (Tile) tile; } @@ -296,11 +275,11 @@ public static Tile createTile(TileBean.TileType tileType, Orientation orientatio } if (tile != null) { - tile.setDrawOutline(drawOutline); + //tile.setDrawOutline(drawOutline); tile.setId(nextTileId(tileType)); } - addTileEventListener((TileEventListener) tile); +// addTileEventListener((TileEventListener) tile); return (Tile) tile; } @@ -308,350 +287,10 @@ public static List toTiles(List tileBeans, boolean drawOutline, List tileList = new LinkedList<>(); for (TileBean tileBean : tileBeans) { - Tile tile = createTile(tileBean, drawOutline, showValues); + Tile tile = createTile(tileBean, showValues); tileList.add(tile); } return tileList; } - private static void addTileEventListener(TileEventListener listener) { - String key = listener.getId(); - tileEventListeners.put(key, listener); - } - - public static void removeTileEventListener(Tile tile) { - if (tile instanceof TileEventListener tileEventListener) { - removeTileEventListener(tileEventListener); - } - } - - public static void removeTileEventListener(TileEventListener listener) { - String key = listener.getId(); - tileEventListeners.remove(key, listener); - } - - public static void fireTileEventListener(TileEvent tileEvent) { - String key = tileEvent.getTileId(); - TileEventListener listener = tileEventListeners.get(key); - if (listener != null) { - listener.onTileChange(tileEvent); - } else { - //Logger.trace("Tile " + key + " not available"); - } - } - - public static void fireAllTileEventListeners(TileEvent tileEvent) { - for (TileEventListener listener : tileEventListeners.values()) { - listener.onTileChange(tileEvent); - } - } - - public static void setPropertyListener(PropertyChangeListener propertyChangeListener) { - for (Tile tile : tiles.values()) { - tile.setPropertyChangeListener(propertyChangeListener); - } - } - - public static void setDrawOutline(boolean drawOutline) { - TileFactory.drawOutline = drawOutline; - - for (Tile tile : tiles.values()) { - tile.setDrawOutline(drawOutline); - } - } - - public static void setShowValues(boolean showValues) { - TileFactory.showValues = showValues; - - for (Tile tile : tiles.values()) { - TileBean.TileType tileType = tile.getTileType(); - //AbstractTile tile = null; - switch (tileType) { - case SWITCH -> { - if (showValues && ((AbstractTile) tile).getAccessoryBean() != null) { - ((Switch) tile).setValue((((AbstractTile) tile).getAccessoryBean()).getAccessoryValue()); - } else { - ((Switch) tile).setValue(AccessoryValue.OFF); - } - } - case CROSS -> { - if (showValues && ((AbstractTile) tile).getAccessoryBean() != null) { - ((Switch) tile).setValue((((AbstractTile) tile).getAccessoryBean()).getAccessoryValue()); - } else { - ((Switch) tile).setValue(AccessoryValue.OFF); - } - } - case SIGNAL -> { - if (showValues && ((AbstractTile) tile).getAccessoryBean() != null) { - ((Signal) tile).setSignalValue(((AccessoryBean) ((AbstractTile) tile).getAccessoryBean()).getSignalValue()); - } else { - ((Signal) tile).setSignalValue(SignalValue.OFF); - } - } - case SENSOR -> { - if (showValues && ((AbstractTile) tile).getSensorBean() != null) { - ((Sensor) tile).setActive(((SensorBean) ((AbstractTile) tile).getSensorBean()).isActive()); - } else { - ((Sensor) tile).setActive(false); - } - } - case BLOCK -> { - } - } - } - } - - public static void loadTiles() { - List tileBeans = PersistenceFactory.getService().getTileBeans(); - - altTiles.clear(); - tiles.clear(); - - for (TileBean tb : tileBeans) { - Tile tile = createTile(tb, drawOutline, showValues); - //tile.setPropertyChangeListener(this); - tiles.put(tile.getCenter(), tile); - - //Alternative point(s) to be able to find all points - if (!tile.getAltPoints().isEmpty()) { - Set alt = tile.getAltPoints(); - for (Point ap : alt) { - altTiles.put(ap, tile); - } - } - } - Logger.trace("Loaded " + tiles.size() + " Tiles..."); - - } - - public static void addTile(Tile tile) { - tiles.put(tile.getCenter(), tile); - //Alternative point(s) to be able to find all points - if (!tile.getAltPoints().isEmpty()) { - Set alt = tile.getAltPoints(); - for (Point ap : alt) { - altTiles.put(ap, tile); - } - } - - if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { - saveTile(tile); - } - } - - public void removeTiles(Set pointsToRemove) { - for (Point p : pointsToRemove) { - Tile removed = tiles.remove(p); - - if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { - deleteTile(removed); - } - - if (removed != null && removed.getAllPoints() != null) { - Set rps = removed.getAltPoints(); - //Also remove alt points - for (Point ap : rps) { - altTiles.remove(ap); - } - - } - } - } - - private void deleteTile(final Tile tile) { - if (tile != null) { - TileBean tb = tile.getTileBean(); - PersistenceFactory.getService().remove(tb); - } - } - - private static void saveTile(final Tile tile) { - if (tile != null) { - TileBean tb = tile.getTileBean(); - PersistenceFactory.getService().persist(tb); - } - } - - public static void saveTiles() { - List beans = new LinkedList<>(); - - for (Tile tile : tiles.values()) { - saveTile(tile); - } - } - - public static Tile findTile(Point cp) { - Tile result = tiles.get(cp); - if (result == null) { - result = altTiles.get(cp); - if (result != null) { - } - } - return result; - } - - public static boolean checkTileOccupation(Tile tile) { - Set tilePoints = tile.getAllPoints(); - for (Point p : tilePoints) { - if (tiles.containsKey(p) || altTiles.containsKey(p)) { - //The is a match, check if it is an other tile - Tile mt = findTile(p); - if (tile.getId().equals(mt.getId())) { - //same tile continue - } else { - //Other tile so really occupied - return true; - } - } - } - return false; - } - - public static Point checkAvailable(Point newPoint, Orientation orientation) { - if (tiles.containsKey(newPoint)) { - Tile et = tiles.get(newPoint); - Logger.trace("@ " + newPoint + " is allready occcupied by: " + et + "..."); - //Search for the nearest avalaible free point - //first get the Center point of the tile which is occuping this slot - // show warning! - Point ecp = et.getCenter(); - - int w = et.getWidth(); - int h = et.getHeight(); - - Point np; - np = switch (orientation) { - case EAST -> - new Point(ecp.x + w, ecp.y); - case WEST -> - new Point(newPoint.x - w, ecp.y); - case SOUTH -> - new Point(ecp.x, newPoint.y + h); - default -> - new Point(ecp.x, newPoint.y - h); - }; - - Logger.trace("Alternative CP: " + np); - // recursive check - return checkAvailable(np, orientation); - } else { - Logger.trace("@ " + newPoint + " is not yet used..."); - - return newPoint; - } - } - - public static void rotateTile(Set centerPoints) { - for (Point p : centerPoints) { - if (tiles.containsKey(p)) { - Tile t = tiles.get(p); - //Remove the alternative or extra points... - for (Point ep : t.getAltPoints()) { - altTiles.remove(ep); - } - - t.rotate(); - - //update - tiles.put(p, t); - for (Point ep : t.getAltPoints()) { - altTiles.put(ep, t); - } - - if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { - saveTile(t); - } - } - } - } - - public static void flipHorizontal(Set points) { - flipTile(points, true); - } - - public static void flipVertical(Set points) { - flipTile(points, false); - } - - private static void flipTile(Set points, boolean horizontal) { - for (Point p : points) { - if (tiles.containsKey(p)) { - Tile t = tiles.get(p); - //Remove the alternative or extra points... - for (Point ep : t.getAltPoints()) { - altTiles.remove(ep); - } - - if (horizontal) { - t.flipHorizontal(); - } else { - t.flipVertical(); - } - //Update - tiles.put(p, t); - for (Point ep : t.getAltPoints()) { - altTiles.put(ep, t); - } - - if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { - saveTile(t); - } - } - } - } - - public static void moveTile(Point snapPoint, Tile tile) { - Point tp = tile.getCenter(); - if (!tp.equals(snapPoint)) { - //Check if new position is free - boolean canMove = true; - if (tiles.containsKey(snapPoint) || altTiles.containsKey(snapPoint)) { - Tile t = findTile(snapPoint); - if (tile.getId().equals(t.getId())) { - //same tile so we can move - canMove = true; - } else { - Logger.trace("Position " + snapPoint + " is occupied with tile: " + t + ", can't move tile " + tile.getId()); - canMove = false; - } - - if (canMove) { - //Remove the original tile center from the tiles - Tile movingTile = tiles.remove(tp); - if (movingTile != null) { - //Also remove from the alt points - Point oldCenter = movingTile.getCenter(); - Set oldAltPoints = movingTile.getAltPoints(); - //Logger.trace("Removing " + oldAltPoints.size() + " alt tile points"); - for (Point ep : oldAltPoints) { - altTiles.remove(ep); - tiles.remove(ep); - } - - //Set the new center position - movingTile.setCenter(snapPoint); - //Check again, needed for tiles which are longer then 1 square, like a block - if (!checkTileOccupation(movingTile)) { - Logger.trace("Moved Tile " + movingTile.getId() + " from " + tp + " to " + snapPoint + "..."); - tiles.put(snapPoint, movingTile); - for (Point ep : movingTile.getAltPoints()) { - altTiles.put(ep, movingTile); - } - } else { - //Do not move Tile, put back where it was - movingTile.setCenter(oldCenter); - tiles.put(oldCenter, movingTile); - for (Point ep : movingTile.getAltPoints()) { - altTiles.put(ep, movingTile); - } - } - - if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { - saveTile(movingTile); - } - } - } - } - } - } } diff --git a/src/main/java/jcs/ui/layout/tiles/TileModel.java b/src/main/java/jcs/ui/layout/tiles/TileModel.java new file mode 100644 index 00000000..b9f59c2a --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/TileModel.java @@ -0,0 +1,85 @@ +/* + * Copyright 2025 fransjacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles; + +import java.awt.event.ActionListener; +import java.io.Serializable; +import javax.swing.event.ChangeListener; +import jcs.entities.BlockBean; + +/** + * + * @author fransjacobs + */ +public interface TileModel extends Serializable { + + boolean isSelected(); + + public void setSelected(boolean selected); + + boolean isScaleImage(); + + public void setScaleImage(boolean scaleImage); + + boolean isShowCenter(); + + public void setShowCenter(boolean showCenter); + + boolean isShowRoute(); + + public void setShowRoute(boolean showRoute); + + boolean isShowBlockState(); + + public void setShowBlockState(boolean showBlockState); + + boolean isShowLocomotiveImage(); + + public void setShowLocomotiveImage(boolean showLocomotiveImage); + + boolean isShowAccessoryValue(); + + public void setShowAccessoryValue(boolean showAccessoryValue); + + boolean isShowSignalValue(); + + public void setShowSignalValue(boolean showSignalValue); + + boolean isSensorActive(); + + public void setSensorActive(boolean active); + + BlockBean.BlockState getBlockState(); + + public void setBlockState(BlockBean.BlockState blockState); + + //boolean isShowOutline(); + //public void setShowOutline(boolean showOutline); + //@Override + //void addItemListener(ItemListener l); + //@Override + //void removeItemListener(ItemListener l); + void addChangeListener(ChangeListener l); + + void removeChangeListener(ChangeListener l); + + void addActionListener(ActionListener l); + + void removeActionListener(ActionListener l); + + ActionListener[] getActionListeners(); + +} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/AlphaButtonPolicy.java b/src/main/java/jcs/ui/layout/tiles/sandbox/AlphaButtonPolicy.java new file mode 100755 index 00000000..16e7832a --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/sandbox/AlphaButtonPolicy.java @@ -0,0 +1,91 @@ +// AlphaButtonPolicy.java +// A custom focus traversal policy that uses alphabetical ordering of button +// labels to determine "next" and "previous" buttons for keyboard traversal. +// +package jcs.ui.layout.tiles.sandbox; + +import java.awt.*; +import java.util.*; +import javax.swing.*; + +public class AlphaButtonPolicy extends FocusTraversalPolicy { + + private SortedMap getSortedButtons(Container focusCycleRoot) { + if (focusCycleRoot == null) { + throw new IllegalArgumentException("focusCycleRoot can't be null"); + } + SortedMap result = new TreeMap(); // Will sort all buttons by text. + sortRecursive(result, focusCycleRoot); + return result; + } + + private void sortRecursive(Map buttons, Container container) { + for (int i = 0; i < container.getComponentCount(); i++) { + Component c = container.getComponent(i); + if (c instanceof JButton) { // Found another button to sort. + buttons.put(((JButton) c).getText(), c); + } + if (c instanceof Container) { // Found a container to search. + sortRecursive(buttons, (Container) c); + } + } + } + + // The rest of the code implements the FocusTraversalPolicy interface. + public Component getFirstComponent(Container focusCycleRoot) { + SortedMap buttons = getSortedButtons(focusCycleRoot); + if (buttons.isEmpty()) { + return null; + } + return (Component) buttons.get(buttons.firstKey()); + } + + public Component getLastComponent(Container focusCycleRoot) { + SortedMap buttons = getSortedButtons(focusCycleRoot); + if (buttons.isEmpty()) { + return null; + } + return (Component) buttons.get(buttons.lastKey()); + } + + public Component getDefaultComponent(Container focusCycleRoot) { + return getFirstComponent(focusCycleRoot); + } + + public Component getComponentAfter(Container focusCycleRoot, + Component aComponent) { + if (!(aComponent instanceof JButton)) { + return null; + } + SortedMap buttons = getSortedButtons(focusCycleRoot); + // Find all buttons after the current one. + String nextName = ((JButton) aComponent).getText() + "\0"; + SortedMap nextButtons = buttons.tailMap(nextName); + if (nextButtons.isEmpty()) { // Wrapped back to beginning + if (!buttons.isEmpty()) { + return (Component) buttons.get(buttons.firstKey()); + } + return null; // Degenerate case of no buttons. + } + return (Component) nextButtons.get(nextButtons.firstKey()); + } + + public Component getComponentBefore(Container focusCycleRoot, + Component aComponent) { + if (!(aComponent instanceof JButton)) { + return null; + } + + SortedMap buttons = getSortedButtons(focusCycleRoot); + SortedMap prevButtons + = // Find all buttons before this one. + buttons.headMap(((JButton) aComponent).getText()); + if (prevButtons.isEmpty()) { // Wrapped back to end. + if (!buttons.isEmpty()) { + return (Component) buttons.get(buttons.lastKey()); + } + return null; // Degenerate case of no buttons. + } + return (Component) prevButtons.get(prevButtons.lastKey()); + } +} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/BasicJogShuttleUI.java b/src/main/java/jcs/ui/layout/tiles/sandbox/BasicJogShuttleUI.java new file mode 100755 index 00000000..77154263 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/sandbox/BasicJogShuttleUI.java @@ -0,0 +1,156 @@ +// BasicJogShuttleUI.java +// A UI class for our custom JogShuttle component. +// +package jcs.ui.layout.tiles.sandbox; + +import java.awt.*; +import java.awt.event.*; + +import javax.swing.*; +import javax.swing.plaf.*; + +public class BasicJogShuttleUI extends JogShuttleUI + implements MouseListener, MouseMotionListener { + + private static final int KNOB_DISPLACEMENT = 3; + private static final int FINGER_SLOT_DISPLACEMENT = 15; + + private double lastAngle; // Used to track mouse drags. + + public static ComponentUI createUI(JComponent c) { + return new BasicJogShuttleUI(); + } + + public void installUI(JComponent c) { + JogShuttle shuttle = (JogShuttle) c; + shuttle.addMouseListener(this); + shuttle.addMouseMotionListener(this); + } + + public void uninstallUI(JComponent c) { + JogShuttle shuttle = (JogShuttle) c; + shuttle.removeMouseListener(this); + shuttle.removeMouseMotionListener(this); + } + + public void paint(Graphics g, JComponent c) { + // We don't want to paint inside the insets or borders. + Insets insets = c.getInsets(); + g.translate(insets.left, insets.top); + int width = c.getWidth() - insets.left - insets.right; + int height = c.getHeight() - insets.top - insets.bottom; + + // Draw the outside circle. + g.setColor(c.getForeground()); + g.fillOval(0, 0, width, height); + + Insets d = ((JogShuttle) c).getDialInsets(); + int value = ((JogShuttle) c).getValue(); + int valuePerRevolution = ((JogShuttle) c).getValuePerRevolution(); + + // Draw the edge of the dial. + g.setColor(Color.darkGray); + g.fillOval(d.left, d.top, width - (d.right * 2), height - (d.bottom * 2)); + + // Draw the inside of the dial. + g.setColor(Color.gray); + g.fillOval(d.left + KNOB_DISPLACEMENT, + d.top + KNOB_DISPLACEMENT, + width - (d.right + d.left) - KNOB_DISPLACEMENT * 2, + height - (d.bottom + d.top) - KNOB_DISPLACEMENT * 2); + + // Draw the finger slot. + drawFingerSlot(g, c, value, width, height, valuePerRevolution, + FINGER_SLOT_DISPLACEMENT - 1, + (double) (width / 2) - d.right - FINGER_SLOT_DISPLACEMENT, + (double) (height / 2) - d.bottom - FINGER_SLOT_DISPLACEMENT); + + g.translate(-insets.left, -insets.top); + } + + private void drawFingerSlot(Graphics g, JComponent c, int value, + int width, int height, int valuePerRevolution, int size, + double xradius, double yradius) { + + int currentPosition = value % valuePerRevolution; + + // Obtain the current angle in radians. + double angle = ((double) currentPosition / valuePerRevolution) + * java.lang.Math.PI * 2; + + // Obtain the X and Y coordinates of the finger slot, with the + // minimum value at twelve o'clock. + angle -= (java.lang.Math.PI / 2); + int xPosition = (int) (xradius * java.lang.Math.sin(angle)); + int yPosition = (int) (yradius * java.lang.Math.cos(angle)); + xPosition = (width / 2) - xPosition; + yPosition = (height / 2) + yPosition; + + // Draw the finger slot with a crescent shadow on the top left. + g.setColor(Color.darkGray); + g.fillOval(xPosition - (size / 2), yPosition - (size / 2), size, size); + g.setColor(Color.lightGray); + g.fillOval(xPosition - (size / 2) + 1, yPosition - (size / 2) + 1, + size - 1, size - 1); + + } + + // Figure out angle at which a mouse event occurred with respect to the + // center of the component for intuitive dial dragging. + protected double calculateAngle(MouseEvent e) { + int x = e.getX() - ((JComponent) e.getSource()).getWidth() / 2; + int y = -e.getY() + ((JComponent) e.getSource()).getHeight() / 2; + if (x == 0) { // Handle case where math would blow up. + if (y == 0) { + return lastAngle; // Can't tell... + } + if (y > 0) { + return Math.PI / 2; + } + return -Math.PI / 2; + } + return Math.atan((double) y / (double) x); + } + + public void mousePressed(MouseEvent e) { + lastAngle = calculateAngle(e); + } + + public void mouseReleased(MouseEvent e) { + } + + public void mouseClicked(MouseEvent e) { + } + + public void mouseEntered(MouseEvent e) { + } + + public void mouseExited(MouseEvent e) { + } + + // Figure out the change in angle over which the user has dragged, + // expressed as a fraction of a revolution. + public double angleDragged(MouseEvent e) { + double newAngle = calculateAngle(e); + double change = (lastAngle - newAngle) / Math.PI; + if (Math.abs(change) > 0.5) { // Handle crossing origin. + if (change < 0.0) { + change += 1.0; + } else { + change -= 1.0; + } + } + + lastAngle = newAngle; + return change; + } + + public void mouseDragged(MouseEvent e) { + JogShuttle theShuttle = (JogShuttle) e.getComponent(); + theShuttle.setValue(theShuttle.getValue() + + (int) (angleDragged(e) * theShuttle.getValuePerRevolution())); + } + + public void mouseMoved(MouseEvent e) { + } +} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/FocusExample.java b/src/main/java/jcs/ui/layout/tiles/sandbox/FocusExample.java new file mode 100755 index 00000000..e27171f1 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/sandbox/FocusExample.java @@ -0,0 +1,86 @@ +// FocusExample.java +// An example of focus traversal using the keyboard to navigate through a +// small set of buttons. +// +package jcs.ui.layout.tiles.sandbox; + +import java.awt.*; +import java.awt.event.*; + +import javax.swing.*; + +public class FocusExample extends JFrame { + + public FocusExample() { + + super("Focus Example"); + setDefaultCloseOperation(EXIT_ON_CLOSE); + MyPanel mypanel = new MyPanel(); + + JButton button1 = new JButton("One"); + JButton button2 = new JButton("Two"); + JButton button3 = new JButton("Three"); + JButton button4 = new JButton("Four"); + JButton button5 = new MyButton("Five*"); + JButton button6 = new MyButton("Six*"); + JButton button7 = new JButton("Seven"); + + mypanel.add(button2); + mypanel.add(button3); + + JInternalFrame frame1 = new JInternalFrame("Internal Frame 1", + true, true, true, true); + + frame1.setBackground(Color.lightGray); + frame1.getContentPane().setLayout(new GridLayout(2, 3)); + frame1.setSize(300, 200); + + frame1.getContentPane().add(button1); + frame1.getContentPane().add(mypanel); + frame1.getContentPane().add(button4); + frame1.getContentPane().add(button5); + frame1.getContentPane().add(button6); + frame1.getContentPane().add(button7); + + JDesktopPane desktop = new JDesktopPane(); + desktop.add(frame1, new Integer(1)); + desktop.setOpaque(true); + + // Now set up the user interface window. + Container contentPane = getContentPane(); + contentPane.add(desktop, BorderLayout.CENTER); + setSize(new Dimension(400, 300)); + frame1.setVisible(true); + setVisible(true); + } + + public static void main(String[] args) { + new FocusExample(); + } + + class MyButton extends JButton { + + public MyButton(String s) { + super(s); + } + + public boolean isFocusable() { + return false; + } + } + + class MyPanel extends JPanel { + + public MyPanel() { + super(true); + java.util.Set upKeys = new java.util.HashSet(1); + upKeys.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_UP, 0)); + setFocusTraversalKeys(KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, + upKeys); + } + + public boolean isFocusCycleRoot() { + return true; + } + } +} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/FocusTraversalExample.java b/src/main/java/jcs/ui/layout/tiles/sandbox/FocusTraversalExample.java new file mode 100755 index 00000000..39fdbec1 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/sandbox/FocusTraversalExample.java @@ -0,0 +1,38 @@ +//FocusTraversalExample.java +// Similar to the FocusExample, this class uses the custom AlphaButtonPolicy +// focus traversal policy to navigate another small set of buttons. +// +package jcs.ui.layout.tiles.sandbox; + +import java.awt.*; +import javax.swing.*; + +public class FocusTraversalExample extends JPanel { + + public FocusTraversalExample() { + setLayout(new GridLayout(6, 1)); + JButton button1 = new JButton("Texas"); + JButton button2 = new JButton("Vermont"); + JButton button3 = new JButton("Florida"); + JButton button4 = new JButton("Alabama"); + JButton button5 = new JButton("Minnesota"); + JButton button6 = new JButton("California"); + + setBackground(Color.lightGray); + add(button1); + add(button2); + add(button3); + add(button4); + add(button5); + add(button6); + } + + public static void main(String[] args) { + JFrame frame = new JFrame("Alphabetized Button Focus Traversal"); + frame.setFocusTraversalPolicy(new AlphaButtonPolicy()); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setContentPane(new FocusTraversalExample()); + frame.setSize(400, 300); + frame.setVisible(true); + } +} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/InvokeExample.java b/src/main/java/jcs/ui/layout/tiles/sandbox/InvokeExample.java new file mode 100755 index 00000000..2f4815c2 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/sandbox/InvokeExample.java @@ -0,0 +1,115 @@ +// InvokeExample.java +// This class demonstrates several examples of how to handle long-running +// tasks (such as querying a remote resource). Some of the examples are +// good, some are not! +// + +package jcs.ui.layout.tiles.sandbox; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; + +public class InvokeExample { + private static JButton good = new JButton("Good"); + private static JButton bad = new JButton("Bad"); + private static JButton bad2 = new JButton("Bad2"); + private static JLabel resultLabel = new JLabel("Ready", JLabel.CENTER); + + public static void main(String[] args) { + JFrame f = new JFrame(); + f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + + // Layout . . . + JPanel p = new JPanel(); + p.setOpaque(true); + p.setLayout(new FlowLayout()); + p.add(good); + p.add(bad); + p.add(bad2); + + Container c = f.getContentPane(); + c.setLayout(new BorderLayout()); + c.add(p, BorderLayout.CENTER); + c.add(resultLabel, BorderLayout.SOUTH); + + // Listeners + good.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent ev) { + resultLabel.setText("Working . . ."); + setEnabled(false); + + // We're going to do something that takes a long time, so we + // spin off a thread and update the display when we're done. + Thread worker = new Thread() { + public void run() { + // Something that takes a long time . . . in real life, this + // might be a DB query, remote method invocation, etc. + try { + Thread.sleep(5000); + } + catch (InterruptedException ex) {} + + // Report the result using invokeLater(). + SwingUtilities.invokeLater(new Runnable() { + public void run() { + resultLabel.setText("Ready"); + setEnabled(true); + } + }); + } + }; + + worker.start(); // So we don't hold up the dispatch thread. + } + }); + + bad.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent ev) { + resultLabel.setText("Working . . ."); + setEnabled(false); + + // We're going to do the same thing, but not in a separate thread. + try { + Thread.sleep(5000); // Dispatch thread is starving! + } + catch (InterruptedException ex) {} + + // Report the result. + resultLabel.setText("Ready"); + setEnabled(true); + } + }); + + bad2.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent ev) { + resultLabel.setText("Working . . . "); + setEnabled(false); + + // The wrong way to use invokeLater(). The runnable() shouldn't + // starve the dispatch thread. + SwingUtilities.invokeLater(new Runnable() { + public void run() { + try { + Thread.sleep(5000); // Dispatch thread is starving! + } + catch (InterruptedException ex) {} + + resultLabel.setText("Ready"); + setEnabled(true); + } + }); + } + }); + + f.setSize(300, 100); + f.setVisible(true); + } + + // Allows us to turn the buttons on or off while we work. + static void setEnabled(boolean b) { + good.setEnabled(b); + bad.setEnabled(b); + bad2.setEnabled(b); + } +} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/JogShuttle.java b/src/main/java/jcs/ui/layout/tiles/sandbox/JogShuttle.java new file mode 100755 index 00000000..d39366fb --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/sandbox/JogShuttle.java @@ -0,0 +1,154 @@ +// JogShuttle.java +// A custom jog shuttle component. (Some VCRs have such a thing for doing +// variable speed fast-forward and fast-reverse.) An example of using the +// JogShuttle can be found in Sketch.java. +// +package jcs.ui.layout.tiles.sandbox; + +import java.awt.*; + +import javax.swing.*; +import javax.swing.event.*; + +public class JogShuttle extends JComponent implements ChangeListener { + + private BoundedRangeModel model; + + // The dialInsets property tells how far the dial is inset + // from the sunken border. + private Insets dialInsets = new Insets(3, 3, 3, 3); + + // The valuePerRevolution property tells how many units the dial + // takes to make a complete revolution. + private int valuePerRevolution; + + // Constructors + public JogShuttle() { + init(new DefaultBoundedRangeModel()); + } + + public JogShuttle(BoundedRangeModel m) { + init(m); + } + + public JogShuttle(int min, int max, int value) { + init(new DefaultBoundedRangeModel(value, 1, min, max)); + } + + protected void init(BoundedRangeModel m) { + setModel(m); + valuePerRevolution = m.getMaximum() - m.getMinimum(); + setMinimumSize(new Dimension(80, 80)); + setPreferredSize(new Dimension(80, 80)); + updateUI(); + } + + public void setUI(JogShuttleUI ui) { + super.setUI(ui); + } + + public void updateUI() { + setUI((JogShuttleUI) UIManager.getUI(this)); + invalidate(); + } + + public String getUIClassID() { + return JogShuttleUI.UI_CLASS_ID; + } + + public void setModel(BoundedRangeModel m) { + BoundedRangeModel old = model; + if (old != null) { + old.removeChangeListener(this); + } + + if (m == null) { + model = new DefaultBoundedRangeModel(); + } else { + model = m; + } + model.addChangeListener(this); + + firePropertyChange("model", old, model); + } + + public BoundedRangeModel getModel() { + return model; + } + + // Methods + public void resetToMinimum() { + model.setValue(model.getMinimum()); + } + + public void resetToMaximum() { + model.setValue(model.getMaximum()); + } + + public void stateChanged(ChangeEvent e) { + repaint(); + } + + // Accessors and mutators + public int getMinimum() { + return model.getMinimum(); + } + + public void setMinimum(int m) { + int old = getMinimum(); + if (m != old) { + model.setMinimum(m); + firePropertyChange("minimum", old, m); + } + } + + public int getMaximum() { + return model.getMaximum(); + } + + public void setMaximum(int m) { + int old = getMaximum(); + if (m != old) { + model.setMaximum(m); + firePropertyChange("maximum", old, m); + } + } + + public int getValue() { + return model.getValue(); + } + + public void setValue(int v) { + int old = getValue(); + if (v != old) { + model.setValue(v); + firePropertyChange("value", old, v); + } + } + + // Display-specific properties + public int getValuePerRevolution() { + return valuePerRevolution; + } + + public void setValuePerRevolution(int v) { + int old = getValuePerRevolution(); + if (v != old) { + valuePerRevolution = v; + firePropertyChange("valuePerRevolution", old, v); + } + repaint(); + } + + public void setDialInsets(Insets i) { + dialInsets = i; + } + + public void setDialInsets(int top, int left, int bottom, int right) { + dialInsets = new Insets(top, left, bottom, right); + } + + public Insets getDialInsets() { + return dialInsets; + } +} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/JogShuttleUI.java b/src/main/java/jcs/ui/layout/tiles/sandbox/JogShuttleUI.java new file mode 100755 index 00000000..790e0ae7 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/sandbox/JogShuttleUI.java @@ -0,0 +1,11 @@ +// JogShuttleUI.java +// Fill out the proper UIClassID information for our JogShuttle. +// + +package jcs.ui.layout.tiles.sandbox; + +import javax.swing.plaf.*; + +public abstract class JogShuttleUI extends ComponentUI { + public static final String UI_CLASS_ID = "JogShuttleUI"; +} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/SimpleModel.java b/src/main/java/jcs/ui/layout/tiles/sandbox/SimpleModel.java new file mode 100755 index 00000000..bcbbbea9 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/sandbox/SimpleModel.java @@ -0,0 +1,84 @@ +// SimpleModel.java +// An example of a custom data model that could be used in any MVC +// scenario. +// +package jcs.ui.layout.tiles.sandbox; + +import javax.swing.event.*; + +public class SimpleModel implements SimpleModelInterface { + + protected transient ChangeEvent changeEvent = null; + protected EventListenerList listenerList = new EventListenerList(); + + private int value = 0; + private boolean activated = false; + + public SimpleModel() { + } + + public SimpleModel(int v) { + value = v; + } + + public SimpleModel(boolean b) { + activated = b; + } + + public SimpleModel(int v, boolean b) { + value = v; + activated = b; + } + + public int getValue() { + return value; + } + + public synchronized void setValue(int v) { + if (v != value) { + value = v; + fireChange(); + } + } + + public boolean isActivated() { + return activated; + } + + public synchronized void setActivated(boolean b) { + if (b != activated) { + activated = b; + fireChange(); + } + } + + public void addChangeListener(ChangeListener l) { + listenerList.add(ChangeListener.class, l); + } + + public void removeChangeListener(ChangeListener l) { + listenerList.remove(ChangeListener.class, l); + } + + public ChangeListener[] getChangeListeners() { + return (ChangeListener[]) listenerList.getListeners(ChangeListener.class); + } + + protected void fireChange() { + Object[] listeners = listenerList.getListenerList(); + for (int i = listeners.length - 2; i >= 0; i -= 2) { + if (listeners[i] == ChangeListener.class) { + if (changeEvent == null) { + changeEvent = new ChangeEvent(this); + } + ((ChangeListener) listeners[i + 1]).stateChanged(changeEvent); + } + } + } + + public String toString() { + String modelString = "value=" + getValue() + ", " + + "activated=" + isActivated(); + return getClass().getName() + "[" + modelString + "]"; + } +} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/SimpleModelInterface.java b/src/main/java/jcs/ui/layout/tiles/sandbox/SimpleModelInterface.java new file mode 100755 index 00000000..1d24c7f0 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/sandbox/SimpleModelInterface.java @@ -0,0 +1,24 @@ +// SimpleModelInteface.java +// An example of a data model interface that could be used in any MVC +// scenario. This interface is implemented in the SimpleModel class. +// +package jcs.ui.layout.tiles.sandbox; + +import javax.swing.event.*; + +public interface SimpleModelInterface { + + public int getValue(); + + public void setValue(int v); + + public boolean isActivated(); + + public void setActivated(boolean b); + + public void addChangeListener(ChangeListener l); + + public void removeChangeListener(ChangeListener l); + + public ChangeListener[] getChangeListeners(); +} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/Sketch.java b/src/main/java/jcs/ui/layout/tiles/sandbox/Sketch.java new file mode 100755 index 00000000..a8d4e2f7 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/sandbox/Sketch.java @@ -0,0 +1,85 @@ +// Sketch.java +// A sketching application with two dials: one for horizontal movement, one +// for vertical movement. The dials are instances of the JogShuttle class. +// +package jcs.ui.layout.tiles.sandbox; + +import java.awt.*; +import java.awt.event.*; +import java.beans.*; + +import javax.swing.*; +import javax.swing.border.*; + +public class Sketch extends JPanel + implements PropertyChangeListener, ActionListener { + + JogShuttle shuttle1; + JogShuttle shuttle2; + JPanel board; + JButton clear; + + int lastX, lastY; // Keep track of the last point we drew. + + public Sketch() { + super(true); + + setLayout(new BorderLayout()); + board = new JPanel(true); + board.setPreferredSize(new Dimension(300, 300)); + board.setBorder(new LineBorder(Color.black, 5)); + + clear = new JButton("Clear Drawing Area"); + clear.addActionListener(this); + + shuttle1 = new JogShuttle(0, 300, 150); + lastX = shuttle1.getValue(); + shuttle2 = new JogShuttle(0, 300, 150); + lastY = shuttle2.getValue(); + + shuttle1.setValuePerRevolution(100); + shuttle2.setValuePerRevolution(100); + + shuttle1.addPropertyChangeListener(this); + shuttle2.addPropertyChangeListener(this); + + shuttle1.setBorder(new BevelBorder(BevelBorder.RAISED)); + shuttle2.setBorder(new BevelBorder(BevelBorder.RAISED)); + + add(board, BorderLayout.NORTH); + add(shuttle1, BorderLayout.WEST); + add(clear, BorderLayout.CENTER); + add(shuttle2, BorderLayout.EAST); + } + + public void propertyChange(PropertyChangeEvent e) { + if (e.getPropertyName() == "value") { + Graphics g = board.getGraphics(); + g.setColor(getForeground()); + g.drawLine(lastX, lastY, + shuttle1.getValue(), shuttle2.getValue()); + lastX = shuttle1.getValue(); + lastY = shuttle2.getValue(); + } + } + + public void actionPerformed(ActionEvent e) { + // The button must have been pressed. + Insets insets = board.getInsets(); + Graphics g = board.getGraphics(); + g.setColor(board.getBackground()); + g.fillRect(insets.left, insets.top, + board.getWidth() - insets.left - insets.right, + board.getHeight() - insets.top - insets.bottom); + } + + public static void main(String[] args) { + UIManager.put(JogShuttleUI.UI_CLASS_ID, "BasicJogShuttleUI"); + Sketch s = new Sketch(); + JFrame frame = new JFrame("Sample Sketch Application"); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setContentPane(s); + frame.pack(); + frame.setVisible(true); + } +} diff --git a/src/test/java/jcs/ui/layout/tiles/BlockTileTester.form b/src/test/java/jcs/ui/layout/tiles/BlockTileTester.form new file mode 100644 index 00000000..cf9a0f6c --- /dev/null +++ b/src/test/java/jcs/ui/layout/tiles/BlockTileTester.form @@ -0,0 +1,220 @@ + + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/java/jcs/ui/layout/tiles/BlockTileTester.java b/src/test/java/jcs/ui/layout/tiles/BlockTileTester.java index 9b4323d3..7b7d4a8f 100644 --- a/src/test/java/jcs/ui/layout/tiles/BlockTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/BlockTileTester.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Frans Jacobs. + * Copyright 2025 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,155 +17,302 @@ import java.awt.Color; import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; import java.awt.Image; import java.awt.Toolkit; import java.io.File; -import java.io.IOException; -import javax.imageio.ImageIO; +import java.util.Arrays; +import java.util.List; import javax.swing.JFrame; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import jcs.entities.BlockBean; +import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; -import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean; +import jcs.ui.util.ImageUtil; import org.tinylog.Logger; -/** - * @author Frans Jacobs - */ -public class BlockTileTester extends JFrame { +public class BlockTileTester extends javax.swing.JFrame { + + private Tile blockEast; + private Tile blockSouth; + private Tile blockWest; + private Tile blockNorth; - private final Tile tileEast; - private final Tile tileSouth; - private final Tile tileWest; - private final Tile tileNorth; + private final List blockStates = Arrays.stream(BlockState.values()).toList(); + private int blockStateIndex = 0; - @SuppressWarnings("OverridableMethodCallInConstructor") + /** + * Creates new form TileTester + * + * @param title + */ public BlockTileTester(String title) { super(title); + initComponents(); + eastStateBtn.setText(this.blockStates.get(1).getState()); + createTiles(); + this.setVisible(true); + } - //LocomotiveBean lok1 = new LocomotiveBean(2L, "BR 81 002", 2L, 2, "DB BR 81 008", "mm_prg", 120, 1, 0, 0, false, true); - LocomotiveBean lok2 = new LocomotiveBean(12L, "BR 141 015-08", 12L, 12, "DB BR 141 136-2", "mm_prg", 120, 0, 0, 2, false, true); - - LocomotiveBean lok1 = new LocomotiveBean(8L, "NS DHG 6505", 8L, 8, "", "dcc", 100, 0, 0, 1, true, true); + private void createTiles() { - String imgPath = System.getProperty("user.home") + File.separator + "jcs" + File.separator + "cache" + File.separator + "dcc-ex" + File.separator + "ns dhg 6505.png"; - lok1.setIcon(imgPath); + blockEast = new Block(TileBean.Orientation.EAST, 200, 40); + blockEast.setId("east"); + blockEast.setBlockState(blockStates.get(blockStateIndex)); + //blockEast.setBlockBean(createBlockBean(blockEast)); + blockEast.setTrackRouteColor(Color.MAGENTA); - Image locImage = readImage(imgPath); - lok1.setLocIcon(locImage); + blockSouth = new Block(TileBean.Orientation.SOUTH, 360, 80); + blockSouth.setId("south"); + blockSouth.setBlockState(blockStates.get(blockStateIndex+1)); - tileEast = new Block(Orientation.EAST, 70, 190); - tileEast.setId("bk-1"); + blockSouth.setTrackRouteColor(Color.YELLOW); - BlockBean bbe = new BlockBean(); - bbe.setId(tileEast.getId()); - bbe.setTileId(tileEast.getId()); - //lok1.setDirection(LocomotiveBean.Direction.FORWARDS); - bbe.setLocomotive(lok1); - bbe.setDescription(tileEast.getId()); - //bbe.setReverseArrival(true); - ((Block) tileEast).setBlockBean(bbe); + blockWest = new Block(TileBean.Orientation.WEST, 200, 120); + blockWest.setId("west"); + blockSouth.setBlockState(blockStates.get(blockStateIndex+1)); + blockWest.setTrackRouteColor(Color.CYAN); - // - tileSouth = new Block(Orientation.SOUTH, 160, 190); - tileSouth.setId("bk-2"); - - BlockBean bbs = new BlockBean(); - bbs.setId(tileSouth.getId()); - bbs.setTileId(tileSouth.getId()); - bbs.setDescription(tileSouth.getId()); - //lok1.setDirection(LocomotiveBean.Direction.BACKWARDS); - bbs.setLocomotive(lok1); - //bbs.setReverseArrival(true); - ((Block) tileSouth).setBlockBean(bbs); - - tileWest = new Block(Orientation.WEST, 250, 190); - tileWest.setId("bk-3"); - BlockBean bbw = new BlockBean(); - bbw.setId(tileWest.getId()); - bbw.setTileId(tileWest.getId()); - //lok1.setDirection(LocomotiveBean.Direction.FORWARDS); - bbw.setLocomotive(lok1); - bbw.setDescription(tileWest.getId()); - //bbw.setReverseArrival(true); - ((Block) tileWest).setBlockBean(bbw); - - tileNorth = new Block(Orientation.NORTH, 340, 190); - tileNorth.setId("bk-4"); - BlockBean bbn = new BlockBean(); - bbn.setId(tileNorth.getId()); - bbn.setTileId(tileNorth.getId()); - lok1.setDirection(LocomotiveBean.Direction.BACKWARDS); - bbn.setLocomotive(lok1); - //bbn.setReverseArrival(true); - ((Block) tileNorth).setBlockBean(bbn); + blockNorth = new Block(TileBean.Orientation.NORTH, 40, 80); + blockNorth.setId("north"); + blockSouth.setBlockState(blockStates.get(blockStateIndex+1)); + blockNorth.setTrackRouteColor(Color.blue); + + dotGridCanvas.add(blockEast); + + dotGridCanvas.add(blockSouth); + dotGridCanvas.add(blockWest); + dotGridCanvas.add(blockNorth); + } + + private BlockBean createBlockBean(Tile tile) { + BlockBean blockBean = new BlockBean(); + blockBean.setId(tile.getId()); + blockBean.setTileId(tile.getId()); + blockBean.setDescription("Block-" + tile.getOrientation().getOrientation().toLowerCase()); + blockBean.setDepartureSuffix(null); + + blockBean.setBlockState(blockStates.get(blockStateIndex)); + +// if (this.showLocCB.isSelected()) { +// bbe.setLocomotive(createLocomotiveBean()); +// } else { +// bbe.setLocomotive(null); +// } + return blockBean; + } + + private LocomotiveBean createLocomotiveBean() { -// Logger.trace("East: "+ ((Block)tileEast).getLocomotiveBlockSuffix()); -// Logger.trace("West: "+ ((Block)tileWest).getLocomotiveBlockSuffix()); -// Logger.trace("North: "+ ((Block)tileNorth).getLocomotiveBlockSuffix()); -// Logger.trace("South: "+ ((Block)tileSouth).getLocomotiveBlockSuffix()); + // LocomotiveBean lok2 = new LocomotiveBean(12L, "BR 141 015-08", 12L, 12, "DB BR 141 136-2", "mm_prg", 120, 0, 0, 2, false, true); + // LocomotiveBean lok1 = new LocomotiveBean(8L, "NS DHG 6505", 8L, 8, "", "dcc", 100, 0, 0, 1, true, true); + + //String imgPath = System.getProperty("user.home") + File.separator + "jcs" + File.separator + "cache" + File.separator + "dcc-ex" + File.separator + "ns dhg 6505.png"; + //lok1.setIcon(imgPath); + + //Image locImage = readImage(imgPath); + //lok1.setLocIcon(locImage); + + //activateEastSensorBtn.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/DHG 6505.png"))); // NOI18N + LocomotiveBean lb = new LocomotiveBean(8L, "NS DHG 6505", 8L, 8, "", "dcc", 100, 0, 0, 1, true, true); + String imgPath = System.getProperty("user.home") + File.separator + "jcs" + File.separator + "images" + File.separator + "DHG 6505.png"; + lb.setIcon(imgPath); + Image locImage = ImageUtil.readImage(imgPath); + //Image is sized by default so + locImage = ImageUtil.scaleImage(locImage, 100); + lb.setLocIcon(locImage); + +// if (this.backwardsRB.isSelected()) { +// lb.setDirection(LocomotiveBean.Direction.BACKWARDS); +// } else { +// lb.setDirection(LocomotiveBean.Direction.FORWARDS); +// } + return lb; } - @Override - public void paint(Graphics g) { - Graphics2D g2d = (Graphics2D) g; + /** + * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { - tileEast.drawTile(g2d, true); - tileEast.drawBounds(g2d); - tileEast.drawCenterPoint(g2d, Color.red); + toolbarPanel = new javax.swing.JPanel(); + toolBar = new javax.swing.JToolBar(); + eastStateBtn = new javax.swing.JButton(); + eastTileBtn = new javax.swing.JToggleButton(); + southTileBtn = new javax.swing.JToggleButton(); + westTileBtn = new javax.swing.JToggleButton(); + northTileBtn = new javax.swing.JToggleButton(); + selectSouthTileBtn = new javax.swing.JToggleButton(); + drawCenterBtn = new javax.swing.JToggleButton(); + activateEastSensorBtn = new javax.swing.JToggleButton(); + dotGridCanvas = new jcs.ui.layout.tiles.DotGridCanvas(); - tileSouth.drawTile(g2d, false); - tileSouth.drawBounds(g2d); - tileSouth.drawCenterPoint(g2d, Color.blue); + setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); - tileWest.drawTile(g2d, false); - tileWest.drawBounds(g2d); - tileWest.drawCenterPoint(g2d, Color.red); + java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); + flowLayout1.setAlignOnBaseline(true); + toolbarPanel.setLayout(flowLayout1); - tileNorth.drawTile(g2d, true); - tileNorth.drawBounds(g2d); - tileNorth.drawCenterPoint(g2d, Color.cyan); - } - - public static Image readImage(String path) { - Image image = null; - //path = System.getProperty("user.home") + File.separator + "jcs" + File.separator + "cache" + File.separator + shortName + File.separator; - - File imgFile; - if (path.contains(".")) { - imgFile = new File(path); - } else { - imgFile = new File(path); - } + toolBar.setRollover(true); + + eastStateBtn.setText("State"); + eastStateBtn.setFocusable(false); + eastStateBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + eastStateBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + eastStateBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + eastStateBtnActionPerformed(evt); + } + }); + toolBar.add(eastStateBtn); + + eastTileBtn.setText("East"); + eastTileBtn.setToolTipText(""); + eastTileBtn.setFocusable(false); + eastTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + eastTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + eastTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + eastTileBtnActionPerformed(evt); + } + }); + toolBar.add(eastTileBtn); + + southTileBtn.setText("South"); + southTileBtn.setFocusable(false); + southTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + southTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + southTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + southTileBtnActionPerformed(evt); + } + }); + toolBar.add(southTileBtn); + + westTileBtn.setText("West"); + westTileBtn.setFocusable(false); + westTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + westTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + westTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + westTileBtnActionPerformed(evt); + } + }); + toolBar.add(westTileBtn); - if (imgFile.exists()) { - try { - image = ImageIO.read(imgFile); + northTileBtn.setText("North"); + northTileBtn.setFocusable(false); + northTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + northTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + northTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + northTileBtnActionPerformed(evt); + } + }); + toolBar.add(northTileBtn); - //Image is sized by default so - if (image != null) { - int size = 100; - float aspect = (float) image.getHeight(null) / (float) image.getWidth(null); - image = image.getScaledInstance(size, (int) (size * aspect), Image.SCALE_SMOOTH); - } + selectSouthTileBtn.setText("Select Tile"); + selectSouthTileBtn.setFocusable(false); + selectSouthTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + selectSouthTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + selectSouthTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + selectSouthTileBtnActionPerformed(evt); + } + }); + toolBar.add(selectSouthTileBtn); - } catch (IOException e) { - Logger.trace("Image file " + path + " does not exists"); + drawCenterBtn.setText("show Center"); + drawCenterBtn.setFocusable(false); + drawCenterBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + drawCenterBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + drawCenterBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + drawCenterBtnActionPerformed(evt); } + }); + toolBar.add(drawCenterBtn); + + activateEastSensorBtn.setText("Icon"); + activateEastSensorBtn.setFocusable(false); + activateEastSensorBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + activateEastSensorBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + activateEastSensorBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + activateEastSensorBtnActionPerformed(evt); + } + }); + toolBar.add(activateEastSensorBtn); + + toolbarPanel.add(toolBar); + + getContentPane().add(toolbarPanel, java.awt.BorderLayout.NORTH); + + dotGridCanvas.setPreferredSize(new java.awt.Dimension(360, 280)); + getContentPane().add(dotGridCanvas, java.awt.BorderLayout.CENTER); + + pack(); + }// //GEN-END:initComponents + + private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed + Logger.trace(blockNorth.id + "..."); + blockNorth.setDrawRoute(this.northTileBtn.isSelected()); + }//GEN-LAST:event_northTileBtnActionPerformed + + private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed + blockEast.setDrawRoute(this.eastTileBtn.isSelected()); + }//GEN-LAST:event_eastTileBtnActionPerformed + + private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed + blockWest.setDrawRoute(this.westTileBtn.isSelected()); + }//GEN-LAST:event_westTileBtnActionPerformed + + private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed + blockSouth.setDrawRoute(this.southTileBtn.isSelected()); + }//GEN-LAST:event_southTileBtnActionPerformed + + private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed + blockSouth.setSelected(this.selectSouthTileBtn.isSelected()); + }//GEN-LAST:event_selectSouthTileBtnActionPerformed + + private void drawCenterBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_drawCenterBtnActionPerformed + blockEast.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + blockSouth.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + }//GEN-LAST:event_drawCenterBtnActionPerformed + + private void activateEastSensorBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_activateEastSensorBtnActionPerformed + blockEast.setActive(this.activateEastSensorBtn.isSelected()); + }//GEN-LAST:event_activateEastSensorBtnActionPerformed + + private void eastStateBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastStateBtnActionPerformed + if (blockStateIndex + 1 < blockStates.size()) { + blockStateIndex++; + } else { + blockStateIndex = 0; } - return image; - } - - + //Logger.trace("BlockStates: " + this.blockStates.size() + " index: " + this.blockStateIndex); + this.blockEast.setBlockState(this.blockStates.get(blockStateIndex)); + if (blockStateIndex + 1 < blockStates.size()) { + this.eastStateBtn.setText(this.blockStates.get(blockStateIndex + 1).getState()); + } else { + this.eastStateBtn.setText(this.blockStates.get(0).getState()); + } + }//GEN-LAST:event_eastStateBtnActionPerformed + + /** + * @param args the command line arguments + */ public static void main(String args[]) { try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); + BlockTileTester.setDefaultLookAndFeelDecorated(true); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException @@ -173,15 +320,27 @@ public static void main(String args[]) { Logger.error(ex); } - BlockTileTester app = new BlockTileTester("Block Tile Tester"); - - Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); - app.setSize(370, 300); - app.setLocation( - dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); - - app.setVisible(true); - - app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + /* Create and display the form */ + java.awt.EventQueue.invokeLater(() -> { + BlockTileTester app = new BlockTileTester("Sensor Tile Tester"); + app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); + app.setLocation(dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); + app.pack(); + }); } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JToggleButton activateEastSensorBtn; + private jcs.ui.layout.tiles.DotGridCanvas dotGridCanvas; + private javax.swing.JToggleButton drawCenterBtn; + private javax.swing.JButton eastStateBtn; + private javax.swing.JToggleButton eastTileBtn; + private javax.swing.JToggleButton northTileBtn; + private javax.swing.JToggleButton selectSouthTileBtn; + private javax.swing.JToggleButton southTileBtn; + private javax.swing.JToolBar toolBar; + private javax.swing.JPanel toolbarPanel; + private javax.swing.JToggleButton westTileBtn; + // End of variables declaration//GEN-END:variables } diff --git a/src/test/java/jcs/ui/layout/tiles/CrossTileTester.java b/src/test/java/jcs/ui/layout/tiles/CrossTileTester.java index fc62c582..3173bd54 100644 --- a/src/test/java/jcs/ui/layout/tiles/CrossTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/CrossTileTester.java @@ -61,41 +61,41 @@ public CrossTileTester(String title) { public void paint(Graphics g) { Graphics2D g2d = (Graphics2D) g; - switchEastR.drawTile(g2d, true); - switchEastR.drawBounds(g2d); +// switchEastR.drawTile(g2d, true); +// switchEastR.drawBounds(g2d); switchEastR.drawCenterPoint(g2d, Color.red); - ((Switch) switchEastR).setValue(AccessoryValue.RED); + ((Switch) switchEastR).setAccessoryValue(AccessoryValue.RED); - switchSouthR.drawTile(g2d, false); - switchSouthR.drawBounds(g2d); +// switchSouthR.drawTile(g2d, false); +// switchSouthR.drawBounds(g2d); switchSouthR.drawCenterPoint(g2d, Color.blue); - switchWestR.drawTile(g2d, true); - switchWestR.drawBounds(g2d); +// switchWestR.drawTile(g2d, true); +// switchWestR.drawBounds(g2d); switchWestR.drawCenterPoint(g2d, Color.red); - ((Switch) switchWestR).setValue(AccessoryValue.GREEN); + ((Switch) switchWestR).setAccessoryValue(AccessoryValue.GREEN); - switchNorthR.drawTile(g2d, false); - switchNorthR.drawBounds(g2d); +// switchNorthR.drawTile(g2d, false); +// switchNorthR.drawBounds(g2d); switchNorthR.drawCenterPoint(g2d, Color.cyan); // - switchEastL.drawTile(g2d, false); - switchEastL.drawBounds(g2d); +// switchEastL.drawTile(g2d, false); +// switchEastL.drawBounds(g2d); switchEastL.drawCenterPoint(g2d, Color.red); - switchSouthL.drawTile(g2d, true); - switchSouthL.drawBounds(g2d); +// switchSouthL.drawTile(g2d, true); +// switchSouthL.drawBounds(g2d); switchSouthL.drawCenterPoint(g2d, Color.blue); - ((Switch) switchSouthL).setValue(AccessoryValue.GREEN); + ((Switch) switchSouthL).setAccessoryValue(AccessoryValue.GREEN); - switchWestL.drawTile(g2d, false); - switchWestL.drawBounds(g2d); +// switchWestL.drawTile(g2d, false); +// switchWestL.drawBounds(g2d); switchWestL.drawCenterPoint(g2d, Color.red); - switchNorthL.drawTile(g2d, true); - switchNorthL.drawBounds(g2d); +// switchNorthL.drawTile(g2d, true); +// switchNorthL.drawBounds(g2d); switchNorthL.drawCenterPoint(g2d, Color.cyan); - ((Switch) switchNorthL).setValue(AccessoryValue.RED); + ((Switch) switchNorthL).setAccessoryValue(AccessoryValue.RED); } diff --git a/src/test/java/jcs/ui/layout/tiles/CrossingTileTester.form b/src/test/java/jcs/ui/layout/tiles/CrossingTileTester.form new file mode 100644 index 00000000..eade3117 --- /dev/null +++ b/src/test/java/jcs/ui/layout/tiles/CrossingTileTester.form @@ -0,0 +1,197 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/java/jcs/ui/layout/tiles/CrossingTileTester.java b/src/test/java/jcs/ui/layout/tiles/CrossingTileTester.java index 108c2c65..04773a8d 100644 --- a/src/test/java/jcs/ui/layout/tiles/CrossingTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/CrossingTileTester.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Frans Jacobs. + * Copyright 2025 fransjacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,76 +17,225 @@ import java.awt.Color; import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; import java.awt.Toolkit; import javax.swing.JFrame; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; -import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean; import org.tinylog.Logger; /** - * @author Frans Jacobs + * + * @author fransjacobs */ -public class CrossingTileTester extends JFrame { - - private final Tile trackEast; - private final Tile trackSouth; - private final Tile trackWest; - private final Tile trackNorth; - +public class CrossingTileTester extends javax.swing.JFrame { + + private Tile trackEast; + private Tile trackSouth; + private Tile trackWest; + private Tile trackNorth; + + /** + * Creates new form TileTester + * + * @param title + */ public CrossingTileTester(String title) { super(title); - - trackEast = new Crossing(Orientation.EAST, 70, 60); - trackSouth = new Crossing(Orientation.SOUTH, 160, 60); - trackWest = new Crossing(Orientation.WEST, 250, 60); - trackNorth = new Crossing(Orientation.NORTH, 340, 60); + initComponents(); + + createTiles(); + + this.setVisible(true); } - - @Override - public void paint(Graphics g) { - Graphics2D g2d = (Graphics2D) g; - - trackEast.drawTile(g2d, true); - trackEast.drawBounds(g2d); - //trackEast.drawCenterPoint(g2d, Color.red); - - trackSouth.drawTile(g2d, false); - trackSouth.drawBounds(g2d); - trackSouth.drawCenterPoint(g2d, Color.blue); - - trackWest.drawTile(g2d, true); - trackWest.drawBounds(g2d); - trackWest.drawCenterPoint(g2d, Color.red); - - trackNorth.drawTile(g2d, false); - trackNorth.drawBounds(g2d); - trackNorth.drawCenterPoint(g2d, Color.cyan); + + private void createTiles() { + + trackEast = new Crossing(TileBean.Orientation.EAST, 40, 40); + trackEast.setId("east"); + trackEast.setTrackRouteColor(Color.MAGENTA); + + trackSouth = new Crossing(TileBean.Orientation.SOUTH, 120, 40); + trackSouth.setId("south"); + trackSouth.setTrackRouteColor(Color.YELLOW); + trackSouth.setIncomingSide(TileBean.Orientation.EAST); + + trackWest = new Crossing(TileBean.Orientation.WEST, 200, 40); + trackWest.setId("west"); + trackWest.setTrackRouteColor(Color.CYAN); + trackWest.setIncomingSide(TileBean.Orientation.NORTH); + + trackNorth = new Crossing(TileBean.Orientation.NORTH, 280, 40); + trackNorth.setId("north"); + trackNorth.setTrackRouteColor(Color.blue); + + dotGridCanvas.add(trackEast); + + dotGridCanvas.add(trackSouth); + dotGridCanvas.add(trackWest); + dotGridCanvas.add(trackNorth); } + /** + * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + toolbarPanel = new javax.swing.JPanel(); + toolBar = new javax.swing.JToolBar(); + eastTileBtn = new javax.swing.JToggleButton(); + southTileBtn = new javax.swing.JToggleButton(); + westTileBtn = new javax.swing.JToggleButton(); + northTileBtn = new javax.swing.JToggleButton(); + selectSouthTileBtn = new javax.swing.JToggleButton(); + drawCenterBtn = new javax.swing.JToggleButton(); + dotGridCanvas = new jcs.ui.layout.tiles.DotGridCanvas(); + + setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + + java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); + flowLayout1.setAlignOnBaseline(true); + toolbarPanel.setLayout(flowLayout1); + + toolBar.setRollover(true); + + eastTileBtn.setText("East"); + eastTileBtn.setFocusable(false); + eastTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + eastTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + eastTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + eastTileBtnActionPerformed(evt); + } + }); + toolBar.add(eastTileBtn); + + southTileBtn.setText("South"); + southTileBtn.setFocusable(false); + southTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + southTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + southTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + southTileBtnActionPerformed(evt); + } + }); + toolBar.add(southTileBtn); + + westTileBtn.setText("West"); + westTileBtn.setFocusable(false); + westTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + westTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + westTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + westTileBtnActionPerformed(evt); + } + }); + toolBar.add(westTileBtn); + + northTileBtn.setText("North"); + northTileBtn.setFocusable(false); + northTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + northTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + northTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + northTileBtnActionPerformed(evt); + } + }); + toolBar.add(northTileBtn); + + selectSouthTileBtn.setText("Select Tile"); + selectSouthTileBtn.setFocusable(false); + selectSouthTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + selectSouthTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + selectSouthTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + selectSouthTileBtnActionPerformed(evt); + } + }); + toolBar.add(selectSouthTileBtn); + + drawCenterBtn.setText("show Center"); + drawCenterBtn.setFocusable(false); + drawCenterBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + drawCenterBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + drawCenterBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + drawCenterBtnActionPerformed(evt); + } + }); + toolBar.add(drawCenterBtn); + + toolbarPanel.add(toolBar); + + getContentPane().add(toolbarPanel, java.awt.BorderLayout.NORTH); + + dotGridCanvas.setPreferredSize(new java.awt.Dimension(360, 120)); + getContentPane().add(dotGridCanvas, java.awt.BorderLayout.CENTER); + + pack(); + }// //GEN-END:initComponents + + private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed + Logger.trace(trackNorth.id + "..."); + this.trackNorth.setDrawRoute(this.northTileBtn.isSelected()); + }//GEN-LAST:event_northTileBtnActionPerformed + + private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed + this.trackEast.setDrawRoute(this.eastTileBtn.isSelected()); + }//GEN-LAST:event_eastTileBtnActionPerformed + + private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed + this.trackWest.setDrawRoute(this.westTileBtn.isSelected()); + }//GEN-LAST:event_westTileBtnActionPerformed + + private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed + this.trackSouth.setDrawRoute(this.southTileBtn.isSelected()); + }//GEN-LAST:event_southTileBtnActionPerformed + + private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed + this.trackSouth.setSelected(this.selectSouthTileBtn.isSelected()); + }//GEN-LAST:event_selectSouthTileBtnActionPerformed + + private void drawCenterBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_drawCenterBtnActionPerformed + this.trackNorth.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + }//GEN-LAST:event_drawCenterBtnActionPerformed + + /** + * @param args the command line arguments + */ public static void main(String args[]) { - try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); + CrossingTileTester.setDefaultLookAndFeelDecorated(true); + } catch (ClassNotFoundException - | InstantiationException - | IllegalAccessException - | UnsupportedLookAndFeelException ex) { + | InstantiationException + | IllegalAccessException + | UnsupportedLookAndFeelException ex) { Logger.error(ex); } - CrossingTileTester app = new CrossingTileTester("Crossing Tile Tester"); - - Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); - app.setSize(400, 100); - - app.setLocation( - dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); - - app.setVisible(true); - - app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + /* Create and display the form */ + java.awt.EventQueue.invokeLater(() -> { + CrossingTileTester app = new CrossingTileTester("CrossingTile Tester"); + app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); + app.setLocation(dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); + app.pack(); + }); } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private jcs.ui.layout.tiles.DotGridCanvas dotGridCanvas; + private javax.swing.JToggleButton drawCenterBtn; + private javax.swing.JToggleButton eastTileBtn; + private javax.swing.JToggleButton northTileBtn; + private javax.swing.JToggleButton selectSouthTileBtn; + private javax.swing.JToggleButton southTileBtn; + private javax.swing.JToolBar toolBar; + private javax.swing.JPanel toolbarPanel; + private javax.swing.JToggleButton westTileBtn; + // End of variables declaration//GEN-END:variables } diff --git a/src/test/java/jcs/ui/layout/tiles/CurvedTileTester.form b/src/test/java/jcs/ui/layout/tiles/CurvedTileTester.form new file mode 100644 index 00000000..eade3117 --- /dev/null +++ b/src/test/java/jcs/ui/layout/tiles/CurvedTileTester.form @@ -0,0 +1,197 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/java/jcs/ui/layout/tiles/CurvedTileTester.java b/src/test/java/jcs/ui/layout/tiles/CurvedTileTester.java index ee73601a..a2dfcc60 100644 --- a/src/test/java/jcs/ui/layout/tiles/CurvedTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/CurvedTileTester.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Frans Jacobs. + * Copyright 2025 fransjacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,76 +17,223 @@ import java.awt.Color; import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; import java.awt.Toolkit; import javax.swing.JFrame; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; -import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean; import org.tinylog.Logger; /** - * @author Frans Jacobs + * + * @author fransjacobs */ -public class CurvedTileTester extends JFrame { - - private final Tile trackEast; - private final Tile trackSouth; - private final Tile trackWest; - private final Tile trackNorth; - +public class CurvedTileTester extends javax.swing.JFrame { + + private Tile trackEast; + private Tile trackSouth; + private Tile trackWest; + private Tile trackNorth; + + /** + * Creates new form TileTester + * + * @param title + */ public CurvedTileTester(String title) { super(title); + initComponents(); - trackEast = new Curved(Orientation.EAST, 70, 60); - trackSouth = new Curved(Orientation.SOUTH, 160, 60); - trackWest = new Curved(Orientation.WEST, 250, 60); - trackNorth = new Curved(Orientation.NORTH, 340, 60); + createTiles(); + + this.setVisible(true); } - @Override - public void paint(Graphics g) { - Graphics2D g2d = (Graphics2D) g; + private void createTiles() { + + trackEast = new Curved(TileBean.Orientation.EAST, 40, 40); + trackEast.setId("east"); + trackEast.setTrackRouteColor(Color.MAGENTA); - trackEast.drawTile(g2d, false); - trackEast.drawBounds(g2d); - trackEast.drawCenterPoint(g2d, Color.red); + trackSouth = new Curved(TileBean.Orientation.SOUTH, 120, 40); + trackSouth.setId("south"); + trackSouth.setTrackRouteColor(Color.YELLOW); - trackSouth.drawTile(g2d, false); - trackSouth.drawBounds(g2d); - trackSouth.drawCenterPoint(g2d, Color.blue); + trackWest = new Curved(TileBean.Orientation.WEST, 200, 40); + trackWest.setId("west"); + trackWest.setTrackRouteColor(Color.CYAN); - trackWest.drawTile(g2d, false); - trackWest.drawBounds(g2d); - trackWest.drawCenterPoint(g2d, Color.red); + trackNorth = new Curved(TileBean.Orientation.NORTH, 280, 40); + trackNorth.setId("north"); + trackNorth.setTrackRouteColor(Color.blue); - trackNorth.drawTile(g2d, false); - trackNorth.drawBounds(g2d); - trackNorth.drawCenterPoint(g2d, Color.cyan); + dotGridCanvas.add(trackEast); + + dotGridCanvas.add(trackSouth); + dotGridCanvas.add(trackWest); + dotGridCanvas.add(trackNorth); } + /** + * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + toolbarPanel = new javax.swing.JPanel(); + toolBar = new javax.swing.JToolBar(); + eastTileBtn = new javax.swing.JToggleButton(); + southTileBtn = new javax.swing.JToggleButton(); + westTileBtn = new javax.swing.JToggleButton(); + northTileBtn = new javax.swing.JToggleButton(); + selectSouthTileBtn = new javax.swing.JToggleButton(); + drawCenterBtn = new javax.swing.JToggleButton(); + dotGridCanvas = new jcs.ui.layout.tiles.DotGridCanvas(); + + setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + + java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); + flowLayout1.setAlignOnBaseline(true); + toolbarPanel.setLayout(flowLayout1); + + toolBar.setRollover(true); + + eastTileBtn.setText("East"); + eastTileBtn.setFocusable(false); + eastTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + eastTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + eastTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + eastTileBtnActionPerformed(evt); + } + }); + toolBar.add(eastTileBtn); + + southTileBtn.setText("South"); + southTileBtn.setFocusable(false); + southTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + southTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + southTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + southTileBtnActionPerformed(evt); + } + }); + toolBar.add(southTileBtn); + + westTileBtn.setText("West"); + westTileBtn.setFocusable(false); + westTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + westTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + westTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + westTileBtnActionPerformed(evt); + } + }); + toolBar.add(westTileBtn); + + northTileBtn.setText("North"); + northTileBtn.setFocusable(false); + northTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + northTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + northTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + northTileBtnActionPerformed(evt); + } + }); + toolBar.add(northTileBtn); + + selectSouthTileBtn.setText("Select Tile"); + selectSouthTileBtn.setFocusable(false); + selectSouthTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + selectSouthTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + selectSouthTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + selectSouthTileBtnActionPerformed(evt); + } + }); + toolBar.add(selectSouthTileBtn); + + drawCenterBtn.setText("show Center"); + drawCenterBtn.setFocusable(false); + drawCenterBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + drawCenterBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + drawCenterBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + drawCenterBtnActionPerformed(evt); + } + }); + toolBar.add(drawCenterBtn); + + toolbarPanel.add(toolBar); + + getContentPane().add(toolbarPanel, java.awt.BorderLayout.NORTH); + + dotGridCanvas.setPreferredSize(new java.awt.Dimension(360, 120)); + getContentPane().add(dotGridCanvas, java.awt.BorderLayout.CENTER); + + pack(); + }// //GEN-END:initComponents + + private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed + Logger.trace(trackNorth.id + "..."); + this.trackNorth.setDrawRoute(this.northTileBtn.isSelected()); + }//GEN-LAST:event_northTileBtnActionPerformed + + private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed + this.trackEast.setDrawRoute(this.eastTileBtn.isSelected()); + }//GEN-LAST:event_eastTileBtnActionPerformed + + private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed + this.trackWest.setDrawRoute(this.westTileBtn.isSelected()); + }//GEN-LAST:event_westTileBtnActionPerformed + + private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed + this.trackSouth.setDrawRoute(this.southTileBtn.isSelected()); + }//GEN-LAST:event_southTileBtnActionPerformed + + private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed + this.trackSouth.setSelected(this.selectSouthTileBtn.isSelected()); + }//GEN-LAST:event_selectSouthTileBtnActionPerformed + + private void drawCenterBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_drawCenterBtnActionPerformed + this.trackNorth.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + }//GEN-LAST:event_drawCenterBtnActionPerformed + + /** + * @param args the command line arguments + */ public static void main(String args[]) { - try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); + CurvedTileTester.setDefaultLookAndFeelDecorated(true); + } catch (ClassNotFoundException - | InstantiationException - | IllegalAccessException - | UnsupportedLookAndFeelException ex) { + | InstantiationException + | IllegalAccessException + | UnsupportedLookAndFeelException ex) { Logger.error(ex); } - CurvedTileTester app = new CurvedTileTester("Curved Tile Tester"); - - Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); - app.setSize(400, 100); - - app.setLocation( - dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); - - app.setVisible(true); - - app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + /* Create and display the form */ + java.awt.EventQueue.invokeLater(() -> { + CurvedTileTester app = new CurvedTileTester("CurvedTile Tester"); + app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); + app.setLocation(dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); + app.pack(); + }); } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private jcs.ui.layout.tiles.DotGridCanvas dotGridCanvas; + private javax.swing.JToggleButton drawCenterBtn; + private javax.swing.JToggleButton eastTileBtn; + private javax.swing.JToggleButton northTileBtn; + private javax.swing.JToggleButton selectSouthTileBtn; + private javax.swing.JToggleButton southTileBtn; + private javax.swing.JToolBar toolBar; + private javax.swing.JPanel toolbarPanel; + private javax.swing.JToggleButton westTileBtn; + // End of variables declaration//GEN-END:variables } diff --git a/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java b/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java new file mode 100644 index 00000000..3fcbfd65 --- /dev/null +++ b/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java @@ -0,0 +1,70 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Paint; +import javax.swing.JPanel; +import org.tinylog.Logger; + +/** + * + * @author fransjacobs + */ +public class DotGridCanvas extends JPanel { + + public DotGridCanvas() { + setLayout(null); + setOpaque(true); + setDoubleBuffered(false); + } + + @Override + public void paint(Graphics g) { + long started = System.currentTimeMillis(); + + //Rectangle r = g.getClipBounds(); + //Logger.trace("Rx: " + r.x + " Ry: " + r.y + " Rw: " + r.width + " Rh: " + r.height); + super.paint(g); + + paintDotGrid(g); + long now = System.currentTimeMillis(); + Logger.trace("Duration: " + (now - started) + " ms."); + } + + private void paintDotGrid(Graphics g) { + int width = this.getWidth(); + int height = this.getHeight(); + + int xOffset = 0; + int yOffset = 0; + + //Logger.trace("W: " + width + " H: " + height + " X: " + this.getX() + " Y: " + this.getY()); + Graphics2D gc = (Graphics2D) g; + Paint p = gc.getPaint(); + gc.setPaint(Color.black); + + for (int r = 0; r < width; r++) { + for (int c = 0; c < height; c++) { + gc.drawOval((r * 20 * 2) + xOffset - 2, (c * 20 * 2) + yOffset - 2, 4, 4); + } + } + gc.setPaint(p); + } + +} diff --git a/src/test/java/jcs/ui/layout/tiles/EndTileTester.form b/src/test/java/jcs/ui/layout/tiles/EndTileTester.form new file mode 100644 index 00000000..eade3117 --- /dev/null +++ b/src/test/java/jcs/ui/layout/tiles/EndTileTester.form @@ -0,0 +1,197 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/java/jcs/ui/layout/tiles/EndTileTester.java b/src/test/java/jcs/ui/layout/tiles/EndTileTester.java index 4a95cd73..1a9400ed 100644 --- a/src/test/java/jcs/ui/layout/tiles/EndTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/EndTileTester.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Frans Jacobs. + * Copyright 2025 fransjacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,76 +17,223 @@ import java.awt.Color; import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; import java.awt.Toolkit; import javax.swing.JFrame; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; -import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean; import org.tinylog.Logger; /** - * @author Frans Jacobs + * + * @author fransjacobs */ -public class EndTileTester extends JFrame { - - private final Tile trackEast; - private final Tile trackSouth; - private final Tile trackWest; - private final Tile trackNorth; - +public class EndTileTester extends javax.swing.JFrame { + + private Tile trackEast; + private Tile trackSouth; + private Tile trackWest; + private Tile trackNorth; + + /** + * Creates new form TileTester + * + * @param title + */ public EndTileTester(String title) { super(title); + initComponents(); + + createTiles(); - trackEast = new End(Orientation.EAST, 70, 60); - trackSouth = new End(Orientation.SOUTH, 160, 60); - trackWest = new End(Orientation.WEST, 250, 60); - trackNorth = new End(Orientation.NORTH, 340, 60); + this.setVisible(true); } - @Override - public void paint(Graphics g) { - Graphics2D g2d = (Graphics2D) g; + private void createTiles() { - trackEast.drawTile(g2d, false); - trackEast.drawBounds(g2d); - trackEast.drawCenterPoint(g2d, Color.red); + trackEast = new End(TileBean.Orientation.EAST, 40, 40); + trackEast.setId("east"); + trackEast.setTrackRouteColor(Color.MAGENTA); - trackSouth.drawTile(g2d, false); - trackSouth.drawBounds(g2d); - trackSouth.drawCenterPoint(g2d, Color.blue); + trackSouth = new End(TileBean.Orientation.SOUTH, 120, 40); + trackSouth.setId("south"); + trackSouth.setTrackRouteColor(Color.YELLOW); - trackWest.drawTile(g2d, false); - trackWest.drawBounds(g2d); - trackWest.drawCenterPoint(g2d, Color.red); + trackWest = new End(TileBean.Orientation.WEST, 200, 40); + trackWest.setId("west"); + trackWest.setTrackRouteColor(Color.CYAN); - trackNorth.drawTile(g2d, false); - trackNorth.drawBounds(g2d); - trackNorth.drawCenterPoint(g2d, Color.cyan); + trackNorth = new End(TileBean.Orientation.NORTH, 280, 40); + trackNorth.setId("north"); + trackNorth.setTrackRouteColor(Color.blue); + + dotGridCanvas.add(trackEast); + + dotGridCanvas.add(trackSouth); + dotGridCanvas.add(trackWest); + dotGridCanvas.add(trackNorth); } + /** + * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + toolbarPanel = new javax.swing.JPanel(); + toolBar = new javax.swing.JToolBar(); + eastTileBtn = new javax.swing.JToggleButton(); + southTileBtn = new javax.swing.JToggleButton(); + westTileBtn = new javax.swing.JToggleButton(); + northTileBtn = new javax.swing.JToggleButton(); + selectSouthTileBtn = new javax.swing.JToggleButton(); + drawCenterBtn = new javax.swing.JToggleButton(); + dotGridCanvas = new jcs.ui.layout.tiles.DotGridCanvas(); + + setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + + java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); + flowLayout1.setAlignOnBaseline(true); + toolbarPanel.setLayout(flowLayout1); + + toolBar.setRollover(true); + + eastTileBtn.setText("East"); + eastTileBtn.setFocusable(false); + eastTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + eastTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + eastTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + eastTileBtnActionPerformed(evt); + } + }); + toolBar.add(eastTileBtn); + + southTileBtn.setText("South"); + southTileBtn.setFocusable(false); + southTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + southTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + southTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + southTileBtnActionPerformed(evt); + } + }); + toolBar.add(southTileBtn); + + westTileBtn.setText("West"); + westTileBtn.setFocusable(false); + westTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + westTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + westTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + westTileBtnActionPerformed(evt); + } + }); + toolBar.add(westTileBtn); + + northTileBtn.setText("North"); + northTileBtn.setFocusable(false); + northTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + northTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + northTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + northTileBtnActionPerformed(evt); + } + }); + toolBar.add(northTileBtn); + + selectSouthTileBtn.setText("Select Tile"); + selectSouthTileBtn.setFocusable(false); + selectSouthTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + selectSouthTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + selectSouthTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + selectSouthTileBtnActionPerformed(evt); + } + }); + toolBar.add(selectSouthTileBtn); + + drawCenterBtn.setText("show Center"); + drawCenterBtn.setFocusable(false); + drawCenterBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + drawCenterBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + drawCenterBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + drawCenterBtnActionPerformed(evt); + } + }); + toolBar.add(drawCenterBtn); + + toolbarPanel.add(toolBar); + + getContentPane().add(toolbarPanel, java.awt.BorderLayout.NORTH); + + dotGridCanvas.setPreferredSize(new java.awt.Dimension(360, 120)); + getContentPane().add(dotGridCanvas, java.awt.BorderLayout.CENTER); + + pack(); + }// //GEN-END:initComponents + + private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed + Logger.trace(trackNorth.id + "..."); + this.trackNorth.setDrawRoute(this.northTileBtn.isSelected()); + }//GEN-LAST:event_northTileBtnActionPerformed + + private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed + this.trackEast.setDrawRoute(this.eastTileBtn.isSelected()); + }//GEN-LAST:event_eastTileBtnActionPerformed + + private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed + this.trackWest.setDrawRoute(this.westTileBtn.isSelected()); + }//GEN-LAST:event_westTileBtnActionPerformed + + private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed + this.trackSouth.setDrawRoute(this.southTileBtn.isSelected()); + }//GEN-LAST:event_southTileBtnActionPerformed + + private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed + this.trackSouth.setSelected(this.selectSouthTileBtn.isSelected()); + }//GEN-LAST:event_selectSouthTileBtnActionPerformed + + private void drawCenterBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_drawCenterBtnActionPerformed + this.trackNorth.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + }//GEN-LAST:event_drawCenterBtnActionPerformed + + /** + * @param args the command line arguments + */ public static void main(String args[]) { - try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); + EndTileTester.setDefaultLookAndFeelDecorated(true); + } catch (ClassNotFoundException - | InstantiationException - | IllegalAccessException - | UnsupportedLookAndFeelException ex) { + | InstantiationException + | IllegalAccessException + | UnsupportedLookAndFeelException ex) { Logger.error(ex); } - EndTileTester app = new EndTileTester("End Tile Tester"); - - Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); - app.setSize(400, 100); - - app.setLocation( - dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); - - app.setVisible(true); - - app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + /* Create and display the form */ + java.awt.EventQueue.invokeLater(() -> { + EndTileTester app = new EndTileTester("EndTile Tester"); + app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); + app.setLocation(dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); + app.pack(); + }); } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private jcs.ui.layout.tiles.DotGridCanvas dotGridCanvas; + private javax.swing.JToggleButton drawCenterBtn; + private javax.swing.JToggleButton eastTileBtn; + private javax.swing.JToggleButton northTileBtn; + private javax.swing.JToggleButton selectSouthTileBtn; + private javax.swing.JToggleButton southTileBtn; + private javax.swing.JToolBar toolBar; + private javax.swing.JPanel toolbarPanel; + private javax.swing.JToggleButton westTileBtn; + // End of variables declaration//GEN-END:variables } diff --git a/src/test/java/jcs/ui/layout/tiles/SensorTileTester.form b/src/test/java/jcs/ui/layout/tiles/SensorTileTester.form new file mode 100644 index 00000000..335bf54f --- /dev/null +++ b/src/test/java/jcs/ui/layout/tiles/SensorTileTester.form @@ -0,0 +1,208 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/java/jcs/ui/layout/tiles/SensorTileTester.java b/src/test/java/jcs/ui/layout/tiles/SensorTileTester.java index 817d2d27..4e016041 100644 --- a/src/test/java/jcs/ui/layout/tiles/SensorTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/SensorTileTester.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Frans Jacobs. + * Copyright 2025 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,78 +17,236 @@ import java.awt.Color; import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; import java.awt.Toolkit; import javax.swing.JFrame; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; -import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean; import org.tinylog.Logger; -/** - * @author Frans Jacobs - */ -public class SensorTileTester extends JFrame { +public class SensorTileTester extends javax.swing.JFrame { - private final Tile trackEast; - private final Tile trackSouth; - private final Tile trackWest; - private final Tile trackNorth; + private Tile sensorEast; + private Tile sensorSouth; + private Tile sensorWest; + private Tile sensorNorth; + /** + * Creates new form TileTester + * + * @param title + */ public SensorTileTester(String title) { super(title); + initComponents(); + + createTiles(); - trackEast = new Sensor(Orientation.EAST, 70, 60); - trackSouth = new Sensor(Orientation.SOUTH, 160, 60); - trackWest = new Sensor(Orientation.WEST, 250, 60); - trackNorth = new Sensor(Orientation.NORTH, 340, 60); + this.setVisible(true); } - @Override - public void paint(Graphics g) { - Graphics2D g2d = (Graphics2D) g; + private void createTiles() { + + sensorEast = new Sensor(TileBean.Orientation.EAST, 40, 40); + sensorEast.setId("east"); + sensorEast.setTrackRouteColor(Color.MAGENTA); - trackEast.drawTile(g2d, false); - trackEast.drawBounds(g2d); - trackEast.drawCenterPoint(g2d, Color.red); + sensorSouth = new Sensor(TileBean.Orientation.SOUTH, 120, 40); + sensorSouth.setId("south"); + sensorSouth.setTrackRouteColor(Color.YELLOW); - trackSouth.drawTile(g2d, false); - trackSouth.drawBounds(g2d); - trackSouth.drawCenterPoint(g2d, Color.blue); - ((Sensor) trackSouth).setActive(true); + sensorWest = new Sensor(TileBean.Orientation.WEST, 200, 40); + sensorWest.setId("west"); + sensorWest.setTrackRouteColor(Color.CYAN); - trackWest.drawTile(g2d, false); - trackWest.drawBounds(g2d); - trackWest.drawCenterPoint(g2d, Color.red); - ((Sensor) trackWest).setActive(true); + sensorNorth = new Sensor(TileBean.Orientation.NORTH, 280, 40); + sensorNorth.setId("north"); + sensorNorth.setTrackRouteColor(Color.blue); - trackNorth.drawTile(g2d, false); - trackNorth.drawBounds(g2d); - trackNorth.drawCenterPoint(g2d, Color.cyan); + dotGridCanvas.add(sensorEast); + + dotGridCanvas.add(sensorSouth); + dotGridCanvas.add(sensorWest); + dotGridCanvas.add(sensorNorth); } + /** + * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + toolbarPanel = new javax.swing.JPanel(); + toolBar = new javax.swing.JToolBar(); + eastTileBtn = new javax.swing.JToggleButton(); + southTileBtn = new javax.swing.JToggleButton(); + westTileBtn = new javax.swing.JToggleButton(); + northTileBtn = new javax.swing.JToggleButton(); + selectSouthTileBtn = new javax.swing.JToggleButton(); + drawCenterBtn = new javax.swing.JToggleButton(); + activateEastSensorBtn = new javax.swing.JToggleButton(); + dotGridCanvas = new jcs.ui.layout.tiles.DotGridCanvas(); + + setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + + java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); + flowLayout1.setAlignOnBaseline(true); + toolbarPanel.setLayout(flowLayout1); + + toolBar.setRollover(true); + + eastTileBtn.setText("East"); + eastTileBtn.setFocusable(false); + eastTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + eastTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + eastTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + eastTileBtnActionPerformed(evt); + } + }); + toolBar.add(eastTileBtn); + + southTileBtn.setText("South"); + southTileBtn.setFocusable(false); + southTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + southTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + southTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + southTileBtnActionPerformed(evt); + } + }); + toolBar.add(southTileBtn); + + westTileBtn.setText("West"); + westTileBtn.setFocusable(false); + westTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + westTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + westTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + westTileBtnActionPerformed(evt); + } + }); + toolBar.add(westTileBtn); + + northTileBtn.setText("North"); + northTileBtn.setFocusable(false); + northTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + northTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + northTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + northTileBtnActionPerformed(evt); + } + }); + toolBar.add(northTileBtn); + + selectSouthTileBtn.setText("Select Tile"); + selectSouthTileBtn.setFocusable(false); + selectSouthTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + selectSouthTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + selectSouthTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + selectSouthTileBtnActionPerformed(evt); + } + }); + toolBar.add(selectSouthTileBtn); + + drawCenterBtn.setText("show Center"); + drawCenterBtn.setFocusable(false); + drawCenterBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + drawCenterBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + drawCenterBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + drawCenterBtnActionPerformed(evt); + } + }); + toolBar.add(drawCenterBtn); + + activateEastSensorBtn.setText("Active"); + activateEastSensorBtn.setFocusable(false); + activateEastSensorBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + activateEastSensorBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + activateEastSensorBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + activateEastSensorBtnActionPerformed(evt); + } + }); + toolBar.add(activateEastSensorBtn); + + toolbarPanel.add(toolBar); + + getContentPane().add(toolbarPanel, java.awt.BorderLayout.NORTH); + + dotGridCanvas.setPreferredSize(new java.awt.Dimension(360, 120)); + getContentPane().add(dotGridCanvas, java.awt.BorderLayout.CENTER); + + pack(); + }// //GEN-END:initComponents + + private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed + Logger.trace(sensorNorth.id + "..."); + sensorNorth.setDrawRoute(this.northTileBtn.isSelected()); + }//GEN-LAST:event_northTileBtnActionPerformed + + private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed + sensorEast.setDrawRoute(this.eastTileBtn.isSelected()); + }//GEN-LAST:event_eastTileBtnActionPerformed + + private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed + sensorWest.setDrawRoute(this.westTileBtn.isSelected()); + }//GEN-LAST:event_westTileBtnActionPerformed + + private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed + sensorSouth.setDrawRoute(this.southTileBtn.isSelected()); + }//GEN-LAST:event_southTileBtnActionPerformed + + private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed + sensorSouth.setSelected(this.selectSouthTileBtn.isSelected()); + }//GEN-LAST:event_selectSouthTileBtnActionPerformed + + private void drawCenterBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_drawCenterBtnActionPerformed + sensorNorth.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + }//GEN-LAST:event_drawCenterBtnActionPerformed + + private void activateEastSensorBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_activateEastSensorBtnActionPerformed + sensorEast.setActive(this.activateEastSensorBtn.isSelected()); + }//GEN-LAST:event_activateEastSensorBtnActionPerformed + + /** + * @param args the command line arguments + */ public static void main(String args[]) { - try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); + SensorTileTester.setDefaultLookAndFeelDecorated(true); + } catch (ClassNotFoundException - | InstantiationException - | IllegalAccessException - | UnsupportedLookAndFeelException ex) { + | InstantiationException + | IllegalAccessException + | UnsupportedLookAndFeelException ex) { Logger.error(ex); } - SensorTileTester app = new SensorTileTester("Sensor Tile Tester"); - - Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); - app.setSize(400, 100); - - app.setLocation( - dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); - - app.setVisible(true); - - app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + /* Create and display the form */ + java.awt.EventQueue.invokeLater(() -> { + SensorTileTester app = new SensorTileTester("Sensor Tile Tester"); + app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); + app.setLocation(dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); + app.pack(); + }); } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JToggleButton activateEastSensorBtn; + private jcs.ui.layout.tiles.DotGridCanvas dotGridCanvas; + private javax.swing.JToggleButton drawCenterBtn; + private javax.swing.JToggleButton eastTileBtn; + private javax.swing.JToggleButton northTileBtn; + private javax.swing.JToggleButton selectSouthTileBtn; + private javax.swing.JToggleButton southTileBtn; + private javax.swing.JToolBar toolBar; + private javax.swing.JPanel toolbarPanel; + private javax.swing.JToggleButton westTileBtn; + // End of variables declaration//GEN-END:variables } diff --git a/src/test/java/jcs/ui/layout/tiles/SignalTileTester.form b/src/test/java/jcs/ui/layout/tiles/SignalTileTester.form new file mode 100644 index 00000000..c2b5aac8 --- /dev/null +++ b/src/test/java/jcs/ui/layout/tiles/SignalTileTester.form @@ -0,0 +1,208 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/java/jcs/ui/layout/tiles/SignalTileTester.java b/src/test/java/jcs/ui/layout/tiles/SignalTileTester.java index 62893ca8..c06af5b8 100644 --- a/src/test/java/jcs/ui/layout/tiles/SignalTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/SignalTileTester.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Frans Jacobs. + * Copyright 2025 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,176 +17,304 @@ import java.awt.Color; import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; import java.awt.Toolkit; import javax.swing.JFrame; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; -import jcs.entities.AccessoryBean.SignalType; -import jcs.entities.AccessoryBean.SignalValue; -import jcs.entities.TileBean.Orientation; +import jcs.entities.AccessoryBean; +import jcs.entities.TileBean; import org.tinylog.Logger; -/** - * @author Frans Jacobs - */ -public class SignalTileTester extends JFrame { - - private final Tile signal2East; - private final Tile signal2South; - private final Tile signal2West; - private final Tile signal2North; - - private final Tile signal2MEast; - private final Tile signal2MSouth; - private final Tile signal2MWest; - private final Tile signal2MNorth; - - private final Tile signal3East; - private final Tile signal3South; - private final Tile signal3West; - private final Tile signal3North; - - private final Tile signal4East; - private final Tile signal4South; - private final Tile signal4West; - private final Tile signal4North; - - @SuppressWarnings("OverridableMethodCallInConstructor") +public class SignalTileTester extends javax.swing.JFrame { + + private Tile signal2East; + private Tile signal2South; + private Tile signal2West; + private Tile signal2North; + + private Tile signal2MEast; + private Tile signal2MSouth; + private Tile signal2MWest; + private Tile signal2MNorth; + + private Tile signal3East; + private Tile signal3South; + private Tile signal3West; + private Tile signal3North; + + private Tile signal4East; + private Tile signal4South; + private Tile signal4West; + private Tile signal4North; + + /** + * Creates new form TileTester + * + * @param title + */ public SignalTileTester(String title) { super(title); + initComponents(); - signal2East = new Signal(Orientation.EAST, 70, 60, SignalType.HP01); - ((Signal) signal2East).setSignalValue(SignalValue.Hp0); - - signal2South = new Signal(Orientation.SOUTH, 160, 60, SignalType.HP01); - ((Signal) signal2South).setSignalValue(SignalValue.Hp1); - - signal2West = new Signal(Orientation.WEST, 250, 60, SignalType.HP01); - ((Signal) signal2West).setSignalValue(SignalValue.Hp0); - - signal2North = new Signal(Orientation.NORTH, 340, 60, SignalType.HP01); - ((Signal) signal2North).setSignalValue(SignalValue.Hp1); - - // - signal2MEast = new Signal(Orientation.EAST, 70, 110, SignalType.HP0SH1); - ((Signal) signal2MEast).setSignalValue(SignalValue.Hp0); - - signal2MSouth = new Signal(Orientation.SOUTH, 160, 110, SignalType.HP0SH1); - ((Signal) signal2MSouth).setSignalValue(SignalValue.Hp1); - - signal2MWest = new Signal(Orientation.WEST, 250, 110, SignalType.HP0SH1); - ((Signal) signal2MWest).setSignalValue(SignalValue.Hp0); - - signal2MNorth = new Signal(Orientation.NORTH, 340, 110, SignalType.HP0SH1); - ((Signal) signal2MNorth).setSignalValue(SignalValue.Hp1); - - // - signal3East = new Signal(Orientation.EAST, 70, 160, SignalType.HP012); - ((Signal) signal3East).setSignalValue(SignalValue.Hp0); - - signal3South = new Signal(Orientation.SOUTH, 160, 160, SignalType.HP012); - ((Signal) signal3South).setSignalValue(SignalValue.Hp1); - - signal3West = new Signal(Orientation.WEST, 250, 160, SignalType.HP012); - ((Signal) signal3West).setSignalValue(SignalValue.Hp2); - - signal3North = new Signal(Orientation.NORTH, 340, 160, SignalType.HP012); - ((Signal) signal3North).setSignalValue(SignalValue.Hp0); - - // - signal4East = new Signal(Orientation.EAST, 70, 210, SignalType.HP012SH1); - ((Signal) signal4East).setSignalValue(SignalValue.Hp0); - - signal4South = new Signal(Orientation.SOUTH, 160, 210, SignalType.HP012SH1); - ((Signal) signal4South).setSignalValue(SignalValue.Hp1); - - signal4West = new Signal(Orientation.WEST, 250, 210, SignalType.HP012SH1); - ((Signal) signal4West).setSignalValue(SignalValue.Hp2); - - signal4North = new Signal(Orientation.NORTH, 340, 210, SignalType.HP012SH1); - ((Signal) signal4North).setSignalValue(SignalValue.Hp0Sh1); + createTiles(); + this.setVisible(true); } - @Override - public void paint(Graphics g) { - Graphics2D g2d = (Graphics2D) g; - // - signal2East.drawTile(g2d, false); - signal2East.drawBounds(g2d); - signal2East.drawCenterPoint(g2d, Color.red); + private void createTiles() { + signal2East = new Signal(TileBean.Orientation.EAST, 40, 40, AccessoryBean.SignalType.HP01); + signal2East.setId("east2"); + signal2East.setTrackRouteColor(Color.MAGENTA); + signal2East.setSignalValue(AccessoryBean.SignalValue.Hp0); - signal2South.drawTile(g2d, false); - signal2South.drawBounds(g2d); - signal2South.drawCenterPoint(g2d, Color.blue); + signal2South = new Signal(TileBean.Orientation.SOUTH, 120, 40, AccessoryBean.SignalType.HP01); + signal2South.setId("south2"); + signal2South.setTrackRouteColor(Color.YELLOW); + signal2South.setSignalValue(AccessoryBean.SignalValue.Hp1); - signal2West.drawTile(g2d, false); - signal2West.drawBounds(g2d); - signal2West.drawCenterPoint(g2d, Color.red); + signal2West = new Signal(TileBean.Orientation.WEST, 200, 40, AccessoryBean.SignalType.HP01); + signal2West.setId("west2"); + signal2West.setTrackRouteColor(Color.CYAN); + signal2West.setSignalValue(AccessoryBean.SignalValue.Hp0); - signal2North.drawTile(g2d, false); - signal2North.drawBounds(g2d); - signal2North.drawCenterPoint(g2d, Color.cyan); + signal2North = new Signal(TileBean.Orientation.NORTH, 280, 40, AccessoryBean.SignalType.HP01); + signal2North.setId("north2"); + signal2North.setTrackRouteColor(Color.blue); + signal2North.setSignalValue(AccessoryBean.SignalValue.Hp1); // - signal2MEast.drawTile(g2d, true); - signal2MEast.drawBounds(g2d); - signal2MEast.drawCenterPoint(g2d, Color.red); + signal2MEast = new Signal(TileBean.Orientation.EAST, 40, 120, AccessoryBean.SignalType.HP0SH1); + signal2MEast.setId("east2m"); + signal2MEast.setTrackRouteColor(Color.MAGENTA); + signal2MEast.setSignalValue(AccessoryBean.SignalValue.Hp0); - signal2MSouth.drawTile(g2d, true); - signal2MSouth.drawBounds(g2d); - signal2MSouth.drawCenterPoint(g2d, Color.blue); + signal2MSouth = new Signal(TileBean.Orientation.SOUTH, 120, 120, AccessoryBean.SignalType.HP0SH1); + signal2MSouth.setId("south2m"); + signal2MSouth.setSignalValue(AccessoryBean.SignalValue.Hp1); - signal2MWest.drawTile(g2d, true); - signal2MWest.drawBounds(g2d); - signal2MWest.drawCenterPoint(g2d, Color.red); + signal2MWest = new Signal(TileBean.Orientation.WEST, 200, 120, AccessoryBean.SignalType.HP0SH1); + signal2MWest.setId("west2m"); + signal2MWest.setSignalValue(AccessoryBean.SignalValue.Hp0); - signal2MNorth.drawTile(g2d, true); - signal2MNorth.drawBounds(g2d); - signal2MNorth.drawCenterPoint(g2d, Color.cyan); + signal2MNorth = new Signal(TileBean.Orientation.NORTH, 280, 120, AccessoryBean.SignalType.HP0SH1); + signal2MWest.setId("north2m"); + signal2MNorth.setSignalValue(AccessoryBean.SignalValue.Hp1); // - signal3East.drawTile(g2d, false); - signal3East.drawBounds(g2d); - signal3East.drawCenterPoint(g2d, Color.red); + signal3East = new Signal(TileBean.Orientation.EAST, 40, 200, AccessoryBean.SignalType.HP012); + signal3East.setId("east3"); + signal3East.setSignalValue(AccessoryBean.SignalValue.Hp0); - signal3South.drawTile(g2d, false); - signal3South.drawBounds(g2d); - signal3South.drawCenterPoint(g2d, Color.blue); + signal3South = new Signal(TileBean.Orientation.SOUTH, 120, 200, AccessoryBean.SignalType.HP012); + signal3South.setId("south3"); + signal3South.setSignalValue(AccessoryBean.SignalValue.Hp1); - signal3West.drawTile(g2d, false); - signal3West.drawBounds(g2d); - signal3West.drawCenterPoint(g2d, Color.red); + signal3West = new Signal(TileBean.Orientation.WEST, 200, 200, AccessoryBean.SignalType.HP012); + signal3West.setId("west3"); + signal3West.setSignalValue(AccessoryBean.SignalValue.Hp2); - signal3North.drawTile(g2d, false); - signal3North.drawBounds(g2d); - signal3North.drawCenterPoint(g2d, Color.cyan); + signal3North = new Signal(TileBean.Orientation.NORTH, 280, 200, AccessoryBean.SignalType.HP012); + signal3North.setId("north3"); + signal3North.setSignalValue(AccessoryBean.SignalValue.Hp0); // - signal4East.drawTile(g2d, true); - signal4East.drawBounds(g2d); - signal4East.drawCenterPoint(g2d, Color.red); - - signal4South.drawTile(g2d, true); - signal4South.drawBounds(g2d); - signal4South.drawCenterPoint(g2d, Color.blue); - - signal4West.drawTile(g2d, true); - signal4West.drawBounds(g2d); - signal4West.drawCenterPoint(g2d, Color.red); - - signal4North.drawTile(g2d, true); - signal4North.drawBounds(g2d); - signal4North.drawCenterPoint(g2d, Color.cyan); + signal4East = new Signal(TileBean.Orientation.EAST, 40, 280, AccessoryBean.SignalType.HP012SH1); + signal4East.setId("east4"); + signal4East.setSignalValue(AccessoryBean.SignalValue.Hp0); + + signal4South = new Signal(TileBean.Orientation.SOUTH, 120, 280, AccessoryBean.SignalType.HP012SH1); + signal4South.setId("south4"); + signal4South.setSignalValue(AccessoryBean.SignalValue.Hp1); + + signal4West = new Signal(TileBean.Orientation.WEST, 200, 280, AccessoryBean.SignalType.HP012SH1); + signal4West.setId("west4"); + signal4West.setSignalValue(AccessoryBean.SignalValue.Hp2); + + signal4North = new Signal(TileBean.Orientation.NORTH, 280, 280, AccessoryBean.SignalType.HP012SH1); + signal4North.setId("north4"); + signal4North.setSignalValue(AccessoryBean.SignalValue.Hp0Sh1); + + dotGridCanvas.add(signal2East); + dotGridCanvas.add(signal2South); + dotGridCanvas.add(signal2West); + dotGridCanvas.add(signal2North); + + dotGridCanvas.add(signal2MEast); + dotGridCanvas.add(signal2MSouth); + dotGridCanvas.add(signal2MWest); + dotGridCanvas.add(signal2MNorth); + + dotGridCanvas.add(signal3East); + dotGridCanvas.add(signal3South); + dotGridCanvas.add(signal3West); + dotGridCanvas.add(signal3North); + + dotGridCanvas.add(signal4East); + dotGridCanvas.add(signal4South); + dotGridCanvas.add(signal4West); + dotGridCanvas.add(signal4North); } - public static void main(String args[]) { + /** + * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + toolbarPanel = new javax.swing.JPanel(); + toolBar = new javax.swing.JToolBar(); + eastTileBtn = new javax.swing.JToggleButton(); + southTileBtn = new javax.swing.JToggleButton(); + westTileBtn = new javax.swing.JToggleButton(); + northTileBtn = new javax.swing.JToggleButton(); + selectSouthTileBtn = new javax.swing.JToggleButton(); + drawCenterBtn = new javax.swing.JToggleButton(); + greenRedBtn = new javax.swing.JToggleButton(); + dotGridCanvas = new jcs.ui.layout.tiles.DotGridCanvas(); + + setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + + java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); + flowLayout1.setAlignOnBaseline(true); + toolbarPanel.setLayout(flowLayout1); + + toolBar.setRollover(true); + + eastTileBtn.setText("East"); + eastTileBtn.setFocusable(false); + eastTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + eastTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + eastTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + eastTileBtnActionPerformed(evt); + } + }); + toolBar.add(eastTileBtn); + + southTileBtn.setText("South"); + southTileBtn.setFocusable(false); + southTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + southTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + southTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + southTileBtnActionPerformed(evt); + } + }); + toolBar.add(southTileBtn); + + westTileBtn.setText("West"); + westTileBtn.setFocusable(false); + westTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + westTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + westTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + westTileBtnActionPerformed(evt); + } + }); + toolBar.add(westTileBtn); + + northTileBtn.setText("North"); + northTileBtn.setFocusable(false); + northTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + northTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + northTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + northTileBtnActionPerformed(evt); + } + }); + toolBar.add(northTileBtn); + + selectSouthTileBtn.setText("Select Tile"); + selectSouthTileBtn.setFocusable(false); + selectSouthTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + selectSouthTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + selectSouthTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + selectSouthTileBtnActionPerformed(evt); + } + }); + toolBar.add(selectSouthTileBtn); + + drawCenterBtn.setText("show Center"); + drawCenterBtn.setFocusable(false); + drawCenterBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + drawCenterBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + drawCenterBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + drawCenterBtnActionPerformed(evt); + } + }); + toolBar.add(drawCenterBtn); + + greenRedBtn.setText("Red"); + greenRedBtn.setFocusable(false); + greenRedBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + greenRedBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + greenRedBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + greenRedBtnActionPerformed(evt); + } + }); + toolBar.add(greenRedBtn); + + toolbarPanel.add(toolBar); + + getContentPane().add(toolbarPanel, java.awt.BorderLayout.NORTH); + + dotGridCanvas.setPreferredSize(new java.awt.Dimension(360, 360)); + getContentPane().add(dotGridCanvas, java.awt.BorderLayout.CENTER); + + pack(); + }// //GEN-END:initComponents + + private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed + Logger.trace(signal2North.id + "..."); + this.signal2North.setDrawRoute(this.northTileBtn.isSelected()); + }//GEN-LAST:event_northTileBtnActionPerformed + + private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed + this.signal2East.setDrawRoute(this.eastTileBtn.isSelected()); + }//GEN-LAST:event_eastTileBtnActionPerformed + + private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed + this.signal2West.setDrawRoute(this.westTileBtn.isSelected()); + }//GEN-LAST:event_westTileBtnActionPerformed + + private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed + this.signal2South.setDrawRoute(this.southTileBtn.isSelected()); + }//GEN-LAST:event_southTileBtnActionPerformed + + private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed + this.signal2South.setSelected(this.selectSouthTileBtn.isSelected()); + }//GEN-LAST:event_selectSouthTileBtnActionPerformed + + private void drawCenterBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_drawCenterBtnActionPerformed + this.signal2North.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + }//GEN-LAST:event_drawCenterBtnActionPerformed + + private void greenRedBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_greenRedBtnActionPerformed + boolean red = this.greenRedBtn.isSelected(); + if (red) { + this.greenRedBtn.setText("Green"); + this.signal2East.setSignalValue(AccessoryBean.SignalValue.Hp0); + this.signal2MEast.setSignalValue(AccessoryBean.SignalValue.Hp0); + } else { + this.greenRedBtn.setText("Red"); + this.signal2East.setSignalValue(AccessoryBean.SignalValue.Hp1); + this.signal2MEast.setSignalValue(AccessoryBean.SignalValue.Hp1); + } + }//GEN-LAST:event_greenRedBtnActionPerformed + /** + * @param args the command line arguments + */ + public static void main(String args[]) { try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); + SignalTileTester.setDefaultLookAndFeelDecorated(true); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException @@ -194,16 +322,26 @@ public static void main(String args[]) { Logger.error(ex); } - SignalTileTester app = new SignalTileTester("Signal Tile Tester"); - - Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); - app.setSize(400, 250); - - app.setLocation( - dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); - - app.setVisible(true); - - app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + /* Create and display the form */ + java.awt.EventQueue.invokeLater(() -> { + SignalTileTester app = new SignalTileTester("Signal Tile Tester"); + app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); + app.setLocation(dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); + app.pack(); + }); } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private jcs.ui.layout.tiles.DotGridCanvas dotGridCanvas; + private javax.swing.JToggleButton drawCenterBtn; + private javax.swing.JToggleButton eastTileBtn; + private javax.swing.JToggleButton greenRedBtn; + private javax.swing.JToggleButton northTileBtn; + private javax.swing.JToggleButton selectSouthTileBtn; + private javax.swing.JToggleButton southTileBtn; + private javax.swing.JToolBar toolBar; + private javax.swing.JPanel toolbarPanel; + private javax.swing.JToggleButton westTileBtn; + // End of variables declaration//GEN-END:variables } diff --git a/src/test/java/jcs/ui/layout/tiles/StraightDirectionTileTester.form b/src/test/java/jcs/ui/layout/tiles/StraightDirectionTileTester.form new file mode 100644 index 00000000..eade3117 --- /dev/null +++ b/src/test/java/jcs/ui/layout/tiles/StraightDirectionTileTester.form @@ -0,0 +1,197 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/java/jcs/ui/layout/tiles/StraightDirectionTileTester.java b/src/test/java/jcs/ui/layout/tiles/StraightDirectionTileTester.java index a72eaaf2..138f32c2 100644 --- a/src/test/java/jcs/ui/layout/tiles/StraightDirectionTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/StraightDirectionTileTester.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Frans Jacobs. + * Copyright 2025 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,76 +17,219 @@ import java.awt.Color; import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; import java.awt.Toolkit; import javax.swing.JFrame; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; -import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean; import org.tinylog.Logger; -/** - * @author Frans Jacobs - */ -public class StraightDirectionTileTester extends JFrame { +public class StraightDirectionTileTester extends javax.swing.JFrame { - private final Tile trackEast; - private final Tile trackSouth; - private final Tile trackWest; - private final Tile trackNorth; + private Tile trackEast; + private Tile trackSouth; + private Tile trackWest; + private Tile trackNorth; + /** + * Creates new form TileTester + * + * @param title + */ public StraightDirectionTileTester(String title) { super(title); + initComponents(); + + createTiles(); - trackEast = new StraightDirection(Orientation.EAST, 70, 60); - trackSouth = new StraightDirection(Orientation.SOUTH, 160, 60); - trackWest = new StraightDirection(Orientation.WEST, 250, 60); - trackNorth = new StraightDirection(Orientation.NORTH, 340, 60); + this.setVisible(true); } - @Override - public void paint(Graphics g) { - Graphics2D g2d = (Graphics2D) g; + private void createTiles() { + + trackEast = new StraightDirection(TileBean.Orientation.EAST, 40, 40); + trackEast.setId("east"); + trackEast.setTrackRouteColor(Color.MAGENTA); - trackEast.drawTile(g2d, false); - trackEast.drawBounds(g2d); - trackEast.drawCenterPoint(g2d, Color.red); + trackSouth = new StraightDirection(TileBean.Orientation.SOUTH, 120, 40); + trackSouth.setId("south"); + trackSouth.setTrackRouteColor(Color.YELLOW); - trackSouth.drawTile(g2d, false); - trackSouth.drawBounds(g2d); - trackSouth.drawCenterPoint(g2d, Color.blue); + trackWest = new StraightDirection(TileBean.Orientation.WEST, 200, 40); + trackWest.setId("west"); + trackWest.setTrackRouteColor(Color.CYAN); - trackWest.drawTile(g2d, false); - trackWest.drawBounds(g2d); - trackWest.drawCenterPoint(g2d, Color.red); + trackNorth = new StraightDirection(TileBean.Orientation.NORTH, 280, 40); + trackNorth.setId("north"); + trackNorth.setTrackRouteColor(Color.blue); - trackNorth.drawTile(g2d, false); - trackNorth.drawBounds(g2d); - trackNorth.drawCenterPoint(g2d, Color.cyan); + dotGridCanvas.add(trackEast); + + dotGridCanvas.add(trackSouth); + dotGridCanvas.add(trackWest); + dotGridCanvas.add(trackNorth); } + /** + * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + toolbarPanel = new javax.swing.JPanel(); + toolBar = new javax.swing.JToolBar(); + eastTileBtn = new javax.swing.JToggleButton(); + southTileBtn = new javax.swing.JToggleButton(); + westTileBtn = new javax.swing.JToggleButton(); + northTileBtn = new javax.swing.JToggleButton(); + selectSouthTileBtn = new javax.swing.JToggleButton(); + drawCenterBtn = new javax.swing.JToggleButton(); + dotGridCanvas = new jcs.ui.layout.tiles.DotGridCanvas(); + + setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + + java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); + flowLayout1.setAlignOnBaseline(true); + toolbarPanel.setLayout(flowLayout1); + + toolBar.setRollover(true); + + eastTileBtn.setText("East"); + eastTileBtn.setFocusable(false); + eastTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + eastTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + eastTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + eastTileBtnActionPerformed(evt); + } + }); + toolBar.add(eastTileBtn); + + southTileBtn.setText("South"); + southTileBtn.setFocusable(false); + southTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + southTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + southTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + southTileBtnActionPerformed(evt); + } + }); + toolBar.add(southTileBtn); + + westTileBtn.setText("West"); + westTileBtn.setFocusable(false); + westTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + westTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + westTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + westTileBtnActionPerformed(evt); + } + }); + toolBar.add(westTileBtn); + + northTileBtn.setText("North"); + northTileBtn.setFocusable(false); + northTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + northTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + northTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + northTileBtnActionPerformed(evt); + } + }); + toolBar.add(northTileBtn); + + selectSouthTileBtn.setText("Select Tile"); + selectSouthTileBtn.setFocusable(false); + selectSouthTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + selectSouthTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + selectSouthTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + selectSouthTileBtnActionPerformed(evt); + } + }); + toolBar.add(selectSouthTileBtn); + + drawCenterBtn.setText("show Center"); + drawCenterBtn.setFocusable(false); + drawCenterBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + drawCenterBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + drawCenterBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + drawCenterBtnActionPerformed(evt); + } + }); + toolBar.add(drawCenterBtn); + + toolbarPanel.add(toolBar); + + getContentPane().add(toolbarPanel, java.awt.BorderLayout.NORTH); + + dotGridCanvas.setPreferredSize(new java.awt.Dimension(360, 120)); + getContentPane().add(dotGridCanvas, java.awt.BorderLayout.CENTER); + + pack(); + }// //GEN-END:initComponents + + private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed + Logger.trace(trackNorth.id + "..."); + this.trackNorth.setDrawRoute(this.northTileBtn.isSelected()); + }//GEN-LAST:event_northTileBtnActionPerformed + + private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed + this.trackEast.setDrawRoute(this.eastTileBtn.isSelected()); + }//GEN-LAST:event_eastTileBtnActionPerformed + + private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed + this.trackWest.setDrawRoute(this.westTileBtn.isSelected()); + }//GEN-LAST:event_westTileBtnActionPerformed + + private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed + this.trackSouth.setDrawRoute(this.southTileBtn.isSelected()); + }//GEN-LAST:event_southTileBtnActionPerformed + + private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed + this.trackSouth.setSelected(this.selectSouthTileBtn.isSelected()); + }//GEN-LAST:event_selectSouthTileBtnActionPerformed + + private void drawCenterBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_drawCenterBtnActionPerformed + this.trackNorth.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + }//GEN-LAST:event_drawCenterBtnActionPerformed + + /** + * @param args the command line arguments + */ public static void main(String args[]) { - try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); + StraightDirectionTileTester.setDefaultLookAndFeelDecorated(true); + } catch (ClassNotFoundException - | InstantiationException - | IllegalAccessException - | UnsupportedLookAndFeelException ex) { + | InstantiationException + | IllegalAccessException + | UnsupportedLookAndFeelException ex) { Logger.error(ex); } - StraightDirectionTileTester app = new StraightDirectionTileTester("Straight Tile Tester"); - - Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); - app.setSize(400, 100); - - app.setLocation( - dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); - - app.setVisible(true); - - app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + /* Create and display the form */ + java.awt.EventQueue.invokeLater(() -> { + StraightDirectionTileTester app = new StraightDirectionTileTester("StraightDirTile Tester"); + app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); + app.setLocation(dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); + app.pack(); + }); } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private jcs.ui.layout.tiles.DotGridCanvas dotGridCanvas; + private javax.swing.JToggleButton drawCenterBtn; + private javax.swing.JToggleButton eastTileBtn; + private javax.swing.JToggleButton northTileBtn; + private javax.swing.JToggleButton selectSouthTileBtn; + private javax.swing.JToggleButton southTileBtn; + private javax.swing.JToolBar toolBar; + private javax.swing.JPanel toolbarPanel; + private javax.swing.JToggleButton westTileBtn; + // End of variables declaration//GEN-END:variables } diff --git a/src/test/java/jcs/ui/layout/tiles/StraightTileTester.form b/src/test/java/jcs/ui/layout/tiles/StraightTileTester.form new file mode 100644 index 00000000..eade3117 --- /dev/null +++ b/src/test/java/jcs/ui/layout/tiles/StraightTileTester.form @@ -0,0 +1,197 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/java/jcs/ui/layout/tiles/StraightTileTester.java b/src/test/java/jcs/ui/layout/tiles/StraightTileTester.java index 39e88cf9..0a383d3b 100644 --- a/src/test/java/jcs/ui/layout/tiles/StraightTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/StraightTileTester.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Frans Jacobs. + * Copyright 2025 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,76 +17,220 @@ import java.awt.Color; import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; import java.awt.Toolkit; import javax.swing.JFrame; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; -import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean; import org.tinylog.Logger; -/** - * @author Frans Jacobs - */ -public class StraightTileTester extends JFrame { +public class StraightTileTester extends javax.swing.JFrame { - private final Tile trackEast; - private final Tile trackSouth; - private final Tile trackWest; - private final Tile trackNorth; + private Tile trackEast; + private Tile trackSouth; + private Tile trackWest; + private Tile trackNorth; + /** + * Creates new form TileTester + * + * @param title + */ public StraightTileTester(String title) { super(title); + initComponents(); + + createTiles(); - trackEast = new Straight(Orientation.EAST, 70, 60); - trackSouth = new Straight(Orientation.SOUTH, 160, 60); - trackWest = new Straight(Orientation.WEST, 250, 60); - trackNorth = new Straight(Orientation.NORTH, 340, 60); + this.setVisible(true); } - @Override - public void paint(Graphics g) { - Graphics2D g2d = (Graphics2D) g; + private void createTiles() { + + trackEast = new Straight(TileBean.Orientation.EAST, 40, 40); + trackEast.setId("east"); + trackEast.setTrackRouteColor(Color.MAGENTA); - trackEast.drawTile(g2d, false); - trackEast.drawBounds(g2d); - trackEast.drawCenterPoint(g2d, Color.red); + trackSouth = new Straight(TileBean.Orientation.SOUTH, 120, 40); + trackSouth.setId("south"); + trackSouth.setTrackRouteColor(Color.YELLOW); - trackSouth.drawTile(g2d, false); - trackSouth.drawBounds(g2d); - trackSouth.drawCenterPoint(g2d, Color.blue); + trackWest = new Straight(TileBean.Orientation.WEST, 200, 40); + trackWest.setId("west"); + trackWest.setTrackRouteColor(Color.CYAN); - trackWest.drawTile(g2d, false); - trackWest.drawBounds(g2d); - trackWest.drawCenterPoint(g2d, Color.red); + trackNorth = new Straight(TileBean.Orientation.NORTH, 280, 40); + trackNorth.setId("north"); + trackNorth.setTrackRouteColor(Color.blue); - trackNorth.drawTile(g2d, false); - trackNorth.drawBounds(g2d); - trackNorth.drawCenterPoint(g2d, Color.cyan); + dotGridCanvas.add(trackEast); + + dotGridCanvas.add(trackSouth); + dotGridCanvas.add(trackWest); + dotGridCanvas.add(trackNorth); } + /** + * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + toolbarPanel = new javax.swing.JPanel(); + toolBar = new javax.swing.JToolBar(); + eastTileBtn = new javax.swing.JToggleButton(); + southTileBtn = new javax.swing.JToggleButton(); + westTileBtn = new javax.swing.JToggleButton(); + northTileBtn = new javax.swing.JToggleButton(); + selectSouthTileBtn = new javax.swing.JToggleButton(); + drawCenterBtn = new javax.swing.JToggleButton(); + dotGridCanvas = new jcs.ui.layout.tiles.DotGridCanvas(); + + setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + + java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); + flowLayout1.setAlignOnBaseline(true); + toolbarPanel.setLayout(flowLayout1); + + toolBar.setRollover(true); + + eastTileBtn.setText("East"); + eastTileBtn.setFocusable(false); + eastTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + eastTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + eastTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + eastTileBtnActionPerformed(evt); + } + }); + toolBar.add(eastTileBtn); + + southTileBtn.setText("South"); + southTileBtn.setFocusable(false); + southTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + southTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + southTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + southTileBtnActionPerformed(evt); + } + }); + toolBar.add(southTileBtn); + + westTileBtn.setText("West"); + westTileBtn.setFocusable(false); + westTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + westTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + westTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + westTileBtnActionPerformed(evt); + } + }); + toolBar.add(westTileBtn); + + northTileBtn.setText("North"); + northTileBtn.setFocusable(false); + northTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + northTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + northTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + northTileBtnActionPerformed(evt); + } + }); + toolBar.add(northTileBtn); + + selectSouthTileBtn.setText("Select Tile"); + selectSouthTileBtn.setFocusable(false); + selectSouthTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + selectSouthTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + selectSouthTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + selectSouthTileBtnActionPerformed(evt); + } + }); + toolBar.add(selectSouthTileBtn); + + drawCenterBtn.setText("show Center"); + drawCenterBtn.setFocusable(false); + drawCenterBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + drawCenterBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + drawCenterBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + drawCenterBtnActionPerformed(evt); + } + }); + toolBar.add(drawCenterBtn); + + toolbarPanel.add(toolBar); + + getContentPane().add(toolbarPanel, java.awt.BorderLayout.NORTH); + + dotGridCanvas.setPreferredSize(new java.awt.Dimension(360, 120)); + getContentPane().add(dotGridCanvas, java.awt.BorderLayout.CENTER); + + pack(); + }// //GEN-END:initComponents + + private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed + Logger.trace(trackNorth.id + "..."); + this.trackNorth.setDrawRoute(this.northTileBtn.isSelected()); + }//GEN-LAST:event_northTileBtnActionPerformed + + private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed + this.trackEast.setDrawRoute(this.eastTileBtn.isSelected()); + }//GEN-LAST:event_eastTileBtnActionPerformed + + private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed + this.trackWest.setDrawRoute(this.westTileBtn.isSelected()); + }//GEN-LAST:event_westTileBtnActionPerformed + + private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed + this.trackSouth.setDrawRoute(this.southTileBtn.isSelected()); + }//GEN-LAST:event_southTileBtnActionPerformed + + private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed + this.trackSouth.setSelected(this.selectSouthTileBtn.isSelected()); + }//GEN-LAST:event_selectSouthTileBtnActionPerformed + + private void drawCenterBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_drawCenterBtnActionPerformed + this.trackNorth.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + this.trackEast.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + }//GEN-LAST:event_drawCenterBtnActionPerformed + + /** + * @param args the command line arguments + */ public static void main(String args[]) { - try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); + StraightTileTester.setDefaultLookAndFeelDecorated(true); + } catch (ClassNotFoundException - | InstantiationException - | IllegalAccessException - | UnsupportedLookAndFeelException ex) { + | InstantiationException + | IllegalAccessException + | UnsupportedLookAndFeelException ex) { Logger.error(ex); } - StraightTileTester app = new StraightTileTester("Straight Tile Tester"); - - Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); - app.setSize(400, 100); - - app.setLocation( - dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); - - app.setVisible(true); - - app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + /* Create and display the form */ + java.awt.EventQueue.invokeLater(() -> { + StraightTileTester app = new StraightTileTester("StraightTile Tester"); + app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); + app.setLocation(dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); + app.pack(); + }); } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private jcs.ui.layout.tiles.DotGridCanvas dotGridCanvas; + private javax.swing.JToggleButton drawCenterBtn; + private javax.swing.JToggleButton eastTileBtn; + private javax.swing.JToggleButton northTileBtn; + private javax.swing.JToggleButton selectSouthTileBtn; + private javax.swing.JToggleButton southTileBtn; + private javax.swing.JToolBar toolBar; + private javax.swing.JPanel toolbarPanel; + private javax.swing.JToggleButton westTileBtn; + // End of variables declaration//GEN-END:variables } diff --git a/src/test/java/jcs/ui/layout/tiles/SwitchTileTester.form b/src/test/java/jcs/ui/layout/tiles/SwitchTileTester.form new file mode 100644 index 00000000..4ea0ebf0 --- /dev/null +++ b/src/test/java/jcs/ui/layout/tiles/SwitchTileTester.form @@ -0,0 +1,208 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/java/jcs/ui/layout/tiles/SwitchTileTester.java b/src/test/java/jcs/ui/layout/tiles/SwitchTileTester.java index 1305ba3c..4b615a58 100644 --- a/src/test/java/jcs/ui/layout/tiles/SwitchTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/SwitchTileTester.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Frans Jacobs. + * Copyright 2025 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,92 +17,284 @@ import java.awt.Color; import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; import java.awt.Toolkit; import javax.swing.JFrame; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import jcs.entities.AccessoryBean.AccessoryValue; -import jcs.entities.TileBean.Direction; -import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean; import org.tinylog.Logger; -/** - * @author Frans Jacobs - */ -public class SwitchTileTester extends JFrame { +public class SwitchTileTester extends javax.swing.JFrame { - private final Tile switchEastR; - private final Tile switchSouthR; - private final Tile switchWestR; - private final Tile switchNorthR; + private Tile switchEastR; + private Tile switchSouthR; + private Tile switchWestR; + private Tile switchNorthR; - private final Tile switchEastL; - private final Tile switchSouthL; - private final Tile switchWestL; - private final Tile switchNorthL; + private Tile switchEastL; + private Tile switchSouthL; + private Tile switchWestL; + private Tile switchNorthL; + /** + * Creates new form TileTester + * + * @param title + */ public SwitchTileTester(String title) { super(title); + initComponents(); - switchEastR = new Switch(Orientation.EAST, Direction.RIGHT, 70, 60); - switchSouthR = new Switch(Orientation.SOUTH, Direction.RIGHT, 160, 60); - switchWestR = new Switch(Orientation.WEST, Direction.RIGHT, 250, 60); - switchNorthR = new Switch(Orientation.NORTH, Direction.RIGHT, 340, 60); + createTiles(); - switchEastL = new Switch(Orientation.EAST, Direction.LEFT, 70, 110); - switchSouthL = new Switch(Orientation.SOUTH, Direction.LEFT, 160, 110); - switchWestL = new Switch(Orientation.WEST, Direction.LEFT, 250, 110); - switchNorthL = new Switch(Orientation.NORTH, Direction.LEFT, 340, 110); + this.setVisible(true); } - @Override - public void paint(Graphics g) { - Graphics2D g2d = (Graphics2D) g; - - switchEastR.drawTile(g2d, true); - switchEastR.drawBounds(g2d); - switchEastR.drawCenterPoint(g2d, Color.red); - ((Switch) switchEastR).setValue(AccessoryValue.RED); - - switchSouthR.drawTile(g2d, false); - switchSouthR.drawBounds(g2d); - switchSouthR.drawCenterPoint(g2d, Color.blue); - - switchWestR.drawTile(g2d, true); - switchWestR.drawBounds(g2d); - switchWestR.drawCenterPoint(g2d, Color.red); - ((Switch) switchWestR).setValue(AccessoryValue.GREEN); - - switchNorthR.drawTile(g2d, false); - switchNorthR.drawBounds(g2d); - switchNorthR.drawCenterPoint(g2d, Color.cyan); - // - switchEastL.drawTile(g2d, false); - switchEastL.drawBounds(g2d); - switchEastL.drawCenterPoint(g2d, Color.red); - - switchSouthL.drawTile(g2d, true); - switchSouthL.drawBounds(g2d); - switchSouthL.drawCenterPoint(g2d, Color.blue); - ((Switch) switchSouthL).setValue(AccessoryValue.GREEN); - - switchWestL.drawTile(g2d, false); - switchWestL.drawBounds(g2d); - switchWestL.drawCenterPoint(g2d, Color.red); - - switchNorthL.drawTile(g2d, true); - switchNorthL.drawBounds(g2d); - switchNorthL.drawCenterPoint(g2d, Color.cyan); - ((Switch) switchNorthL).setValue(AccessoryValue.RED); + private void createTiles() { + + switchEastR = new Switch(TileBean.Orientation.EAST, TileBean.Direction.RIGHT, 40, 40); + switchEastR.setId("eastR"); + switchEastR.setTrackRouteColor(Color.MAGENTA); + switchEastR.setRouteValue(AccessoryValue.GREEN); + + switchSouthR = new Switch(TileBean.Orientation.SOUTH, TileBean.Direction.RIGHT, 120, 40); + switchSouthR.setId("southR"); + switchSouthR.setTrackRouteColor(Color.YELLOW); + switchSouthR.setRouteValue(AccessoryValue.RED); + + switchWestR = new Switch(TileBean.Orientation.WEST, TileBean.Direction.RIGHT, 200, 40); + switchWestR.setId("westR"); + switchWestR.setTrackRouteColor(Color.CYAN); + + switchNorthR = new Switch(TileBean.Orientation.NORTH, TileBean.Direction.RIGHT, 280, 40); + switchNorthR.setId("northR"); + switchNorthR.setTrackRouteColor(Color.blue); + switchNorthR.setRouteValue(AccessoryValue.GREEN); + +// switchEastR = new Switch(TileBean.Orientation.EAST, TileBean.Direction.RIGHT, 70, 60); +// switchSouthR = new Switch(TileBean.Orientation.SOUTH, TileBean.Direction.RIGHT, 160, 60); +// switchWestR = new Switch(TileBean.Orientation.WEST, TileBean.Direction.RIGHT, 250, 60); +// switchNorthR = new Switch(TileBean.Orientation.NORTH, TileBean.Direction.RIGHT, 340, 60); +// switchEastL = new Switch(TileBean.Orientation.EAST, TileBean.Direction.LEFT, 70, 110); +// switchSouthL = new Switch(TileBean.Orientation.SOUTH, TileBean.Direction.LEFT, 160, 110); +// switchWestL = new Switch(TileBean.Orientation.WEST, TileBean.Direction.LEFT, 250, 110); +// switchNorthL = new Switch(TileBean.Orientation.NORTH, TileBean.Direction.LEFT, 340, 110); + switchEastL = new Switch(TileBean.Orientation.EAST, TileBean.Direction.LEFT, 40, 120); + switchEastL.setId("eastR"); + switchEastL.setTrackRouteColor(Color.MAGENTA); + switchEastL.setRouteValue(AccessoryValue.GREEN); + + switchSouthL = new Switch(TileBean.Orientation.SOUTH, TileBean.Direction.LEFT, 120, 120); + switchSouthL.setId("southR"); + switchSouthL.setTrackRouteColor(Color.YELLOW); + switchSouthL.setRouteValue(AccessoryValue.RED); + + switchWestL = new Switch(TileBean.Orientation.WEST, TileBean.Direction.LEFT, 200, 120); + switchWestL.setId("westR"); + switchWestL.setTrackRouteColor(Color.CYAN); + + switchNorthL = new Switch(TileBean.Orientation.NORTH, TileBean.Direction.LEFT, 280, 120); + switchNorthL.setId("northR"); + switchNorthL.setTrackRouteColor(Color.blue); + switchNorthL.setRouteValue(AccessoryValue.GREEN); + + dotGridCanvas.add(switchEastR); + dotGridCanvas.add(switchSouthR); + dotGridCanvas.add(switchWestR); + dotGridCanvas.add(switchNorthR); + + dotGridCanvas.add(switchEastL); + dotGridCanvas.add(switchSouthL); + dotGridCanvas.add(switchWestL); + dotGridCanvas.add(switchNorthL); } - public static void main(String args[]) { + /** + * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + toolbarPanel = new javax.swing.JPanel(); + toolBar = new javax.swing.JToolBar(); + eastTileBtn = new javax.swing.JToggleButton(); + southTileBtn = new javax.swing.JToggleButton(); + westTileBtn = new javax.swing.JToggleButton(); + northTileBtn = new javax.swing.JToggleButton(); + selectSouthTileBtn = new javax.swing.JToggleButton(); + drawCenterBtn = new javax.swing.JToggleButton(); + greenRedBtn = new javax.swing.JToggleButton(); + dotGridCanvas = new jcs.ui.layout.tiles.DotGridCanvas(); + + setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + + java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); + flowLayout1.setAlignOnBaseline(true); + toolbarPanel.setLayout(flowLayout1); + + toolBar.setRollover(true); + + eastTileBtn.setText("East"); + eastTileBtn.setFocusable(false); + eastTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + eastTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + eastTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + eastTileBtnActionPerformed(evt); + } + }); + toolBar.add(eastTileBtn); + + southTileBtn.setText("South"); + southTileBtn.setFocusable(false); + southTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + southTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + southTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + southTileBtnActionPerformed(evt); + } + }); + toolBar.add(southTileBtn); + + westTileBtn.setText("West"); + westTileBtn.setFocusable(false); + westTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + westTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + westTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + westTileBtnActionPerformed(evt); + } + }); + toolBar.add(westTileBtn); + + northTileBtn.setText("North"); + northTileBtn.setFocusable(false); + northTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + northTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + northTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + northTileBtnActionPerformed(evt); + } + }); + toolBar.add(northTileBtn); + + selectSouthTileBtn.setText("Select Tile"); + selectSouthTileBtn.setFocusable(false); + selectSouthTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + selectSouthTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + selectSouthTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + selectSouthTileBtnActionPerformed(evt); + } + }); + toolBar.add(selectSouthTileBtn); + + drawCenterBtn.setText("show Center"); + drawCenterBtn.setFocusable(false); + drawCenterBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + drawCenterBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + drawCenterBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + drawCenterBtnActionPerformed(evt); + } + }); + toolBar.add(drawCenterBtn); + + greenRedBtn.setText("Red"); + greenRedBtn.setFocusable(false); + greenRedBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + greenRedBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + greenRedBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + greenRedBtnActionPerformed(evt); + } + }); + toolBar.add(greenRedBtn); + + toolbarPanel.add(toolBar); + getContentPane().add(toolbarPanel, java.awt.BorderLayout.NORTH); + + dotGridCanvas.setPreferredSize(new java.awt.Dimension(360, 200)); + getContentPane().add(dotGridCanvas, java.awt.BorderLayout.CENTER); + + pack(); + }// //GEN-END:initComponents + + private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed + Logger.trace(switchNorthR.id + "..."); + this.switchNorthR.setDrawRoute(this.northTileBtn.isSelected()); + this.switchNorthL.setDrawRoute(this.northTileBtn.isSelected()); + }//GEN-LAST:event_northTileBtnActionPerformed + + private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed + this.switchEastR.setDrawRoute(this.eastTileBtn.isSelected()); + this.switchEastL.setDrawRoute(this.eastTileBtn.isSelected()); + }//GEN-LAST:event_eastTileBtnActionPerformed + + private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed + this.switchWestR.setDrawRoute(this.westTileBtn.isSelected()); + this.switchWestL.setDrawRoute(this.westTileBtn.isSelected()); + }//GEN-LAST:event_westTileBtnActionPerformed + + private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed + this.switchSouthR.setDrawRoute(this.southTileBtn.isSelected()); + this.switchSouthL.setDrawRoute(this.southTileBtn.isSelected()); + }//GEN-LAST:event_southTileBtnActionPerformed + + private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed + this.switchSouthR.setSelected(this.selectSouthTileBtn.isSelected()); + this.switchSouthL.setSelected(this.selectSouthTileBtn.isSelected()); + }//GEN-LAST:event_selectSouthTileBtnActionPerformed + + private void drawCenterBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_drawCenterBtnActionPerformed + this.switchNorthR.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + this.switchEastL.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + }//GEN-LAST:event_drawCenterBtnActionPerformed + + private void greenRedBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_greenRedBtnActionPerformed + boolean red = this.greenRedBtn.isSelected(); + if (red) { + this.greenRedBtn.setText("Green"); + if (this.westTileBtn.isSelected()) { + this.switchWestR.setAccessoryValue(AccessoryValue.OFF); + this.switchWestR.setRouteValue(AccessoryValue.GREEN); + + this.switchWestL.setAccessoryValue(AccessoryValue.OFF); + this.switchWestL.setRouteValue(AccessoryValue.GREEN); + + } else { + this.switchWestR.setAccessoryValue(AccessoryValue.GREEN); + + this.switchWestL.setAccessoryValue(AccessoryValue.GREEN); + } + } else { + this.greenRedBtn.setText("Red"); + if (this.westTileBtn.isSelected()) { + this.switchWestR.setAccessoryValue(AccessoryValue.OFF); + this.switchWestR.setRouteValue(AccessoryValue.RED); + + this.switchWestL.setAccessoryValue(AccessoryValue.OFF); + this.switchWestL.setRouteValue(AccessoryValue.RED); + } else { + this.switchWestR.setAccessoryValue(AccessoryValue.RED); + + this.switchWestL.setAccessoryValue(AccessoryValue.RED); + } + } + }//GEN-LAST:event_greenRedBtnActionPerformed + + /** + * @param args the command line arguments + */ + public static void main(String args[]) { try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); + SwitchTileTester.setDefaultLookAndFeelDecorated(true); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException @@ -110,16 +302,26 @@ public static void main(String args[]) { Logger.error(ex); } - SwitchTileTester app = new SwitchTileTester("Turnout Tile Tester"); - - Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); - app.setSize(400, 150); - - app.setLocation( - dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); - - app.setVisible(true); - - app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + /* Create and display the form */ + java.awt.EventQueue.invokeLater(() -> { + SwitchTileTester app = new SwitchTileTester("Switch Tile Tester"); + app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); + app.setLocation(dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); + app.pack(); + }); } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private jcs.ui.layout.tiles.DotGridCanvas dotGridCanvas; + private javax.swing.JToggleButton drawCenterBtn; + private javax.swing.JToggleButton eastTileBtn; + private javax.swing.JToggleButton greenRedBtn; + private javax.swing.JToggleButton northTileBtn; + private javax.swing.JToggleButton selectSouthTileBtn; + private javax.swing.JToggleButton southTileBtn; + private javax.swing.JToolBar toolBar; + private javax.swing.JPanel toolbarPanel; + private javax.swing.JToggleButton westTileBtn; + // End of variables declaration//GEN-END:variables } diff --git a/src/test/java/jcs/ui/layout/tiles/TileTester.form b/src/test/java/jcs/ui/layout/tiles/TileTester.form new file mode 100644 index 00000000..2d98e3fa --- /dev/null +++ b/src/test/java/jcs/ui/layout/tiles/TileTester.form @@ -0,0 +1,175 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/java/jcs/ui/layout/tiles/TileTester.java b/src/test/java/jcs/ui/layout/tiles/TileTester.java new file mode 100644 index 00000000..6485baf5 --- /dev/null +++ b/src/test/java/jcs/ui/layout/tiles/TileTester.java @@ -0,0 +1,170 @@ +/* + * Copyright 2025 fransjacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles; + +import java.awt.Dimension; +import java.awt.Toolkit; +import javax.swing.JFrame; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; +import org.tinylog.Logger; + +/** + * + * @author fransjacobs + */ +public class TileTester extends javax.swing.JFrame { + + /** + * Creates new form TileTester + * @param title + */ + public TileTester(String title) { + super(title); + initComponents(); + + this.setVisible(true); + } + + /** + * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + toolbarPanel = new javax.swing.JPanel(); + toolBar = new javax.swing.JToolBar(); + northTileBtn = new javax.swing.JToggleButton(); + eastTileBtn = new javax.swing.JToggleButton(); + westTileBtn = new javax.swing.JToggleButton(); + southTileBtn = new javax.swing.JToggleButton(); + dotGridCanvas = new jcs.ui.layout.tiles.DotGridCanvas(); + + setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + + java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); + flowLayout1.setAlignOnBaseline(true); + toolbarPanel.setLayout(flowLayout1); + + toolBar.setRollover(true); + + northTileBtn.setText("North"); + northTileBtn.setFocusable(false); + northTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + northTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + northTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + northTileBtnActionPerformed(evt); + } + }); + toolBar.add(northTileBtn); + + eastTileBtn.setText("East"); + eastTileBtn.setFocusable(false); + eastTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + eastTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + eastTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + eastTileBtnActionPerformed(evt); + } + }); + toolBar.add(eastTileBtn); + + westTileBtn.setText("West"); + westTileBtn.setFocusable(false); + westTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + westTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + westTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + westTileBtnActionPerformed(evt); + } + }); + toolBar.add(westTileBtn); + + southTileBtn.setText("South"); + southTileBtn.setFocusable(false); + southTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + southTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + southTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + southTileBtnActionPerformed(evt); + } + }); + toolBar.add(southTileBtn); + + toolbarPanel.add(toolBar); + + getContentPane().add(toolbarPanel, java.awt.BorderLayout.NORTH); + + dotGridCanvas.setPreferredSize(new java.awt.Dimension(360, 120)); + getContentPane().add(dotGridCanvas, java.awt.BorderLayout.CENTER); + + pack(); + }// //GEN-END:initComponents + + private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_northTileBtnActionPerformed + + private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_eastTileBtnActionPerformed + + private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_westTileBtnActionPerformed + + private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_southTileBtnActionPerformed + + /** + * @param args the command line arguments + */ + public static void main(String args[]) { + try { + UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); + TileTester.setDefaultLookAndFeelDecorated(true); + + } catch (ClassNotFoundException + | InstantiationException + | IllegalAccessException + | UnsupportedLookAndFeelException ex) { + Logger.error(ex); + } + + /* Create and display the form */ + java.awt.EventQueue.invokeLater(() -> { + TileTester app = new TileTester("Tile Tester"); + app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); + //app.setPreferredSize(new Dimension(360, 150)); + app.setLocation(dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); + app.pack(); + }); + } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private jcs.ui.layout.tiles.DotGridCanvas dotGridCanvas; + private javax.swing.JToggleButton eastTileBtn; + private javax.swing.JToggleButton northTileBtn; + private javax.swing.JToggleButton southTileBtn; + private javax.swing.JToolBar toolBar; + private javax.swing.JPanel toolbarPanel; + private javax.swing.JToggleButton westTileBtn; + // End of variables declaration//GEN-END:variables +} diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java index 92b2c3cc..dc8f3998 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java @@ -17,7 +17,6 @@ import java.awt.Color; import java.awt.Dimension; -import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.image.BufferedImage; @@ -39,6 +38,7 @@ public UnscaledBlockCanvas() { public void addTile(Tile block) { this.tiles.add(block); + this.add(block); } public boolean isShowCenter() { @@ -57,7 +57,7 @@ private Dimension getMinCanvasSize() { for (Tile tile : this.tiles) { Point tc = tile.getCenter(); - boolean expand = !((AbstractTile) tile).isScaleImage(); + boolean expand = !tile.isScaleImage(); int tw = tile.getWidth() * (expand ? 10 : 1); int th = tile.getHeight() * (expand ? 10 : 1); @@ -131,9 +131,9 @@ private BufferedImage paintTiles() { g2d.clearRect(0, 0, canvasSize.width, canvasSize.height); for (Tile tile : tiles) { - tile.setDrawOutline(showCenter); +// tile.setDrawOutline(showCenter); - tile.drawTile(g2d, true); + //tile.drawTile(g2d, true); if (showCenter) { tile.drawCenterPoint(g2d, Color.red); @@ -144,38 +144,38 @@ private BufferedImage paintTiles() { return canvasImage; } - @Override - protected void paintComponent(Graphics g) { - Graphics2D g2d = (Graphics2D) g; - BufferedImage canvasImage = paintTiles(); - - //paint the image in the middle so - int w = this.getSize().width; - int h = this.getSize().height; - - int cx = w / 2; - int cy = h / 2; - - int bw = canvasImage.getWidth(); - int bh = canvasImage.getHeight(); - - int pw = w; - int ph = h; - - if(bw > w) { - pw = w; - } - if(bh > h) { - ph = h; - } - - setPreferredSize(new Dimension(bw, bh)); - //setPreferredSize(new Dimension(pw, ph)); - - int x = cx - (bw / 2); - int y = cy - (bh / 2); - g2d.drawImage(canvasImage, null, x, y); - } +// @Override +// protected void paintComponent(Graphics g) { +// Graphics2D g2d = (Graphics2D) g; +// BufferedImage canvasImage = paintTiles(); +// +// //paint the image in the middle so +// int w = this.getSize().width; +// int h = this.getSize().height; +// +// int cx = w / 2; +// int cy = h / 2; +// +// int bw = canvasImage.getWidth(); +// int bh = canvasImage.getHeight(); +// +// int pw = w; +// int ph = h; +// +// if(bw > w) { +// pw = w; +// } +// if(bh > h) { +// ph = h; +// } +// +// setPreferredSize(new Dimension(bw, bh)); +// //setPreferredSize(new Dimension(pw, ph)); +// +// int x = cx - (bw / 2); +// int y = cy - (bh / 2); +// g2d.drawImage(canvasImage, null, x, y); +// } @Override public void propertyChange(PropertyChangeEvent evt) { diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.java b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.java index 54529517..6e37aad9 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.java +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.java @@ -52,6 +52,8 @@ public UnscaledBlockTileFrame() { this.stateCB.setModel(createStateComboBoxModel()); initTile(); + + setVisible(true); } private ComboBoxModel createOrientationComboBoxModel() { @@ -119,9 +121,9 @@ private void initTile() { ((Block) blockTile).setBlockBean(bbe); if (this.scaleCB.isSelected()) { - ((AbstractTile) blockTile).setScaleImage(false); + blockTile.setScaleImage(false); } else { - ((AbstractTile) blockTile).setScaleImage(true); + blockTile.setScaleImage(true); } blockTileCanvas.addTile(blockTile); @@ -131,21 +133,21 @@ private void initTile() { private void changeOrientation() { Orientation orientation = (Orientation) this.orientationCB.getSelectedItem(); blockTile.setOrientation(orientation); - if (Orientation.EAST.equals(blockTile.getOrientation()) || Orientation.WEST.equals(blockTile.getOrientation())) { - ((Block) blockTile).setWidth(Tile.DEFAULT_WIDTH * 3); - ((Block) blockTile).setHeight(Tile.DEFAULT_HEIGHT); - - ((Block) blockTile).setRenderWidth(Tile.RENDER_WIDTH * 3); - ((Block) blockTile).setRenderHeight(Tile.RENDER_HEIGHT); - } else { - ((Block) blockTile).setWidth(Tile.DEFAULT_WIDTH); - ((Block) blockTile).setHeight(Tile.DEFAULT_HEIGHT * 3); - - ((Block) blockTile).setRenderWidth(Tile.RENDER_WIDTH); - ((Block) blockTile).setRenderHeight(Tile.RENDER_HEIGHT * 3); - } - - blockTile.drawTile((Graphics2D) getGraphics(), this.showCenterCB.isSelected()); +// if (Orientation.EAST.equals(blockTile.getOrientation()) || Orientation.WEST.equals(blockTile.getOrientation())) { +// ((Block) blockTile).setWidth(Tile.DEFAULT_WIDTH * 3); +// ((Block) blockTile).setHeight(Tile.DEFAULT_HEIGHT); +// +// ((Block) blockTile).setRenderWidth(Tile.RENDER_WIDTH * 3); +// ((Block) blockTile).setRenderHeight(Tile.RENDER_HEIGHT); +// } else { +// ((Block) blockTile).setWidth(Tile.DEFAULT_WIDTH); +// ((Block) blockTile).setHeight(Tile.DEFAULT_HEIGHT * 3); +// +// ((Block) blockTile).setRenderWidth(Tile.RENDER_WIDTH); +// ((Block) blockTile).setRenderHeight(Tile.RENDER_HEIGHT * 3); +// } +// +// blockTile.drawTile((Graphics2D) getGraphics(), this.showCenterCB.isSelected()); Dimension vps = this.blockTileCanvas.getPreferredSize(); Point cc = new Point(Math.abs(vps.width / 2), Math.abs(vps.height / 2)); @@ -396,9 +398,9 @@ private void forwardsRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FI private void scaleCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_scaleCBActionPerformed if (this.scaleCB.isSelected()) { - ((AbstractTile) blockTile).setScaleImage(false); + blockTile.setScaleImage(false); } else { - ((AbstractTile) blockTile).setScaleImage(true); + blockTile.setScaleImage(true); } repaint(); }//GEN-LAST:event_scaleCBActionPerformed @@ -454,7 +456,7 @@ public static void main(String args[]) { app.setTitle("Unscaled Tile Tester"); app.pack(); app.setLocationRelativeTo(null); - app.setVisible(true); + //app.setVisible(true); }); } diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.form b/src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.form index b59a2535..a7bb9ab5 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.form +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.form @@ -405,9 +405,12 @@ - + + + + diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.java b/src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.java index cf3a9f5b..8efa793e 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.java +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.java @@ -1,5 +1,5 @@ /* - * Copyright 2024 FJA. + * Copyright 2024 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,12 +17,10 @@ import java.awt.Color; import java.awt.Graphics; -import java.awt.Graphics2D; import java.awt.Point; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; import javax.swing.ComboBoxModel; import javax.swing.DefaultComboBoxModel; +import javax.swing.JComponent; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import jcs.entities.AccessoryBean; @@ -41,7 +39,7 @@ * * @author FJA */ -public class UnscaledTileFrame extends javax.swing.JFrame implements PropertyChangeListener { +public class UnscaledTileFrame extends javax.swing.JFrame { private Tile tile; @@ -54,7 +52,9 @@ public UnscaledTileFrame() { this.orientationCB.setModel(createOrientationComboBoxModel()); this.incomingSideCB.setModel(createOrientationComboBoxModel()); this.directionCB.setModel(createDirectionComboBoxModel(true)); - drawTile(); + //drawTile(); + + addTile(); } private ComboBoxModel createTileTypeComboBoxModel() { @@ -97,7 +97,13 @@ private ComboBoxModel createDirectionComboBoxModel(boolean dontCare) return directionModel; } - private void drawTile() { + private void addTile() { + if (this.tile != null) { + Logger.trace("Removing tile " + this.tile.getId()); + this.cPanel.remove((JComponent) this.tile); + this.tile = null; + } + TileType tileType = (TileType) this.tileCB.getSelectedItem(); Orientation orientation = (Orientation) this.orientationCB.getSelectedItem(); @@ -135,8 +141,8 @@ private void drawTile() { } } } else { - x = w / 2; - y = h / 2 + 50; + x = w / 2 - 200; + y = h / 2 - 200; } Point center; @@ -146,18 +152,21 @@ private void drawTile() { center = new Point(x, y); } - tile = TileFactory.createTile(tileType, orientation, direction, center, showOutline); - tile.setPropertyChangeListener(this); + Tile newTile = TileFactory.createTile(tileType, orientation, direction, center, showOutline); + newTile.setScaleImage(false); + //tile.setPropertyChangeListener(this); Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); - tile.setIncomingSide(incomingSide); + newTile.setIncomingSide(incomingSide); - tile.setDrawRoute(this.displayRouteCB.isSelected()); - tile.setTrackRouteColor(Color.blue); + newTile.setDrawRoute(this.displayRouteCB.isSelected()); + newTile.setTrackRouteColor(Color.blue); - ((AbstractTile) tile).setScaleImage(false); + Logger.trace("Adding tile " + newTile.getId() + " " + newTile.xyToString()); - this.repaint(); + //this.cPanel.add((JComponent) newTile); + this.cPanel.add(newTile); + this.tile = newTile; } private AccessoryValue getAccessoryState() { @@ -178,7 +187,7 @@ private void changeAccesoryState() { if (this.displayRouteCB.isSelected()) { aSwitch.setRouteValue(getAccessoryState()); } else { - aSwitch.setValue(getAccessoryState()); + aSwitch.setAccessoryValue(getAccessoryState()); } } @@ -192,32 +201,39 @@ private void changeAccesoryState() { } } - repaint(); - } - - @Override - public void propertyChange(PropertyChangeEvent evt) { - if ("repaintTile".equals(evt.getPropertyName())) { - Tile t = (Tile) evt.getNewValue(); - Logger.trace("Tile: " + t); - this.repaint(); - } + this.tile.repaint(); } +// @Override +// public void propertyChange(PropertyChangeEvent evt) { +// if ("repaintTile".equals(evt.getPropertyName())) { +// Tile t = (Tile) evt.getNewValue(); +// Logger.trace("Tile: " + t); +// //this.repaint(); +// } +// } +// @Override +// public void paint(Graphics g) { +// super.paint(g); +// Graphics2D g2d = (Graphics2D) g; +// boolean outline = this.drawOutlineCB.isSelected(); +// boolean showRoute = this.displayRouteCB.isSelected(); +// tile.setDrawRoute(showRoute); +// +// tile.drawTile(g2d, outline); +// +// if (outline) { +// tile.drawBounds(g2d); +// tile.drawCenterPoint(g2d, Color.red); +// } +// } @Override public void paint(Graphics g) { + long started = System.currentTimeMillis(); super.paint(g); - Graphics2D g2d = (Graphics2D) g; - boolean outline = this.drawOutlineCB.isSelected(); - boolean showRoute = this.displayRouteCB.isSelected(); - tile.setDrawRoute(showRoute); - - tile.drawTile(g2d, outline); - if (outline) { - tile.drawBounds(g2d); - tile.drawCenterPoint(g2d, Color.red); - } + long now = System.currentTimeMillis(); + Logger.trace("Duration: " + (now - started) + " ms."); } private void changeDirection() { @@ -227,7 +243,7 @@ private void changeDirection() { if (TileType.CROSS == tile.getTileType()) { ((Cross) tile).setWidthHeightAndOffsets(); } - this.repaint(); + //this.repaint(); } private void rotateTile() { @@ -263,7 +279,7 @@ private void rotateTile() { this.orientationCB.setSelectedItem(tile.getOrientation()); - this.repaint(); + //this.repaint(); } private void changeOrientation() { @@ -300,10 +316,13 @@ private void changeOrientation() { tile.setCenter(new Point(x, y)); } - this.repaint(); + //this.repaint(); } private void showRoute() { + + Logger.trace("Show route on tile " + tile.getId()); + String tileId = tile.getId(); Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); @@ -314,20 +333,21 @@ private void showRoute() { } else { tileEvent = new TileEvent(tileId, true, incomingSide); } - TileFactory.fireTileEventListener(tileEvent); + //TileCache.fireTileEventListener(tileEvent); - //tile.setDrawRoute(displayRouteCB.isSelected()); + // ((JComponent) this.tile).repaint(); + tile.setDrawRoute(displayRouteCB.isSelected()); //repaint(); } private void showOutline() { - repaint(); + //repaint(); } private void changeIncomingSide() { Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); tile.setIncomingSide(incomingSide); - this.repaint(); + //this.repaint(); } /** @@ -450,9 +470,10 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { getContentPane().add(nPanel, java.awt.BorderLayout.NORTH); - cPanel.setPreferredSize(new java.awt.Dimension(1000, 1000)); + cPanel.setPreferredSize(new java.awt.Dimension(800, 800)); cPanel.setLayout(null); getContentPane().add(cPanel, java.awt.BorderLayout.CENTER); + cPanel.getAccessibleContext().setAccessibleDescription(""); pack(); }// //GEN-END:initComponents @@ -462,7 +483,10 @@ private void rotateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN- }//GEN-LAST:event_rotateButtonActionPerformed private void tileCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tileCBActionPerformed - drawTile(); + addTile(); + //this.tile.repaint(); + + this.repaint(); }//GEN-LAST:event_tileCBActionPerformed private void orientationCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_orientationCBActionPerformed @@ -511,7 +535,7 @@ public static void main(String args[]) { java.awt.EventQueue.invokeLater(() -> { UnscaledTileFrame app = new UnscaledTileFrame(); app.setTitle("Unscaled Tile Tester"); - app.pack(); + //app.pack(); app.setLocationRelativeTo(null); app.setVisible(true); }); diff --git a/src/test/resources/images/DHG 6505.png b/src/test/resources/images/DHG 6505.png new file mode 100644 index 0000000000000000000000000000000000000000..1d57774457d44bd5a3ed690770d9a2729ffbb30e GIT binary patch literal 25034 zcmV(*K;FNJP)ZRA0;qoZf!zKP#Ya7 z=GJ%`A1g;uTjkYp&Axw%2cgw0}b8uwa#dM{Lc)y)+M{rC?V3kW=WJp_LO<-qrl9fzfX5z?FOI%_=Q(Hz@ zU*pPEc9WM-V`@xaWkOY3K2cb5kdsGRU`bqNCUVndnO;21dK1U=XDrIJCI6p*ocX}-^ zH!?m?ji#txVPc@5o=#6ul#`Oxu}N`qa!*`jM@m;JDKIK7Lz|nKUuA40DLFYiOWM0t z93nY?m6bq7S1>d|4-p*?8Za(4OOB0;=G9|rY;ajrOhQ6K6DBvp!MlW?qGD@wS6p1` z&s%P9V|;#eLq9oP}PIfcR+Hkz~?}*mUy{N3`l|h-~%X#1G7w$RF==JUPT>j*~q;U9D zkBQXV03MlYNB{s{JV``BRCr$8y$O62*Of1Ps=B&*t=_xUQfomH2w||X0kPN+g0bW{JOi$>hzvXw8PllkWHJ^S|^b=P|P)~$2T@;~R^Dsk}6)Aa&y0+i&zx1M;H z693i%|L3Xi_{-JT@NT9vmR zf49=RfM=Y~Vu^mx5;eZ{1c1@V@w~_K*2C{Gy>mRX^wu|G_zfNH1EFzXhAgJ$HlN$a zz4iDzO#k1v$I>y_%X&t%q~>@=be6``d?a-sV56fKf>PmybZ-FOhG5 z`&<=VX&06+Xy-Urx=&F46@BSM`4f3_RW`7nm1Zh<2kEN$O{2?0+}XjUTz6z=Zf+MX zHo?6BpV>KGC{<^QBg^s1=*KW3E`hN}Ji$m?F(nzE9J4jbeH_=$X zkoACbswF=F^DE!{LU;24y7@YzX2q$#W@m=yGKz?H)&d-0OZ?#0=C+{&(>_@7h7VqE z&d(|Pj*)I!uL5}u!TeZjzP2w?d@=&{Qzwl@4P4(eSJndFSYA;WLW?R%A^hRNV(l zFmPd>`b`p(Sw(~yEu14)!*gW}cbRaZkR3Px2i6{7a`sSWCz#>P3V7qPqVFVKE!|XR zD%!Ap8?6NYH0b=fO!=-%j7^{`CNd4zn=50+SNJ6WZ|oMe4flNe^78KtT`f6dbUkP< ziLhY`{J3NM+kailSfI0PEi+I5K_ctVif;~%?JYOKnKQ70M`XL=E#=-Bx>|CEQ1pdh zeY*vbRMM67Sbbfv^2o{~uoB?N$^$Ez9N`jo=%W*D*Ee-uk#>@hA(Iar__J69?2)Dz zJp9lX;X8QJ@-9HNR|{*ne!eeZ9dueyZZ{&=+9iVgYLHUPv+%Li_@DS=Je6##6;MvuZv%Hu1(>a1n6IGaE`9o{Z zQGm)&)o^XAp=wc~Y5_Pk)HY7nJh*0G7e-uyWD~aK}q`sDxlrAPyZ|gG}peZI9LjO#ndy?k2~+ z>d`e&S#$7_M5qSbe3)OmOxC5GWT-lZ4+?AGU>{UJhjLbcW6J@x^Wlf)7JTREYWV;O z-~yPCW$+SIk!2!4hbhtr2LY~iWp+60^qe}ezSKuu^+>k%l+)?>?spweKb70DBWJ3U z+9H+Ixas~1iJ4%IUIXx({aCFP9)^ei|K$VRXc;3WjLmHrnBRf1cm!awc67~}wAq$3 zJy1oC!b{7J-(koX7LB83LRNKr9LxV#DBP`deFnY_A5Wo-VMXalt2@k1-nk0}^I-EL zsN?P;phbHlUwO-Q-wC=}JVOdZXjwp}Ig`Ko^CsL=h&iCdn}*|1oq(XSm>d4hherg| z%&%ngvEu`ez+XJPqjhZM*S`GP{%|lwncAuG)*=L-{II7Y^c}3%jDpK!aQ-l?7iTZ` z&e7G<%^5%i7g=Gj8*uHR(ju+6hFSZ7#%%z;OdNcrD!x>`JA!SlWKolTTBLoJfGA3ca%@+sZ>yNBAO zQCMsM5s_S_4;?C4cO6>z-nD=0>N&P>!&dYe7)mDba3P;$<`AIoXdg>s?5`fHW{aqt zDwMAlHu~S8tHm=y{_re*2^Z|zgbTp~&;x4_PsLGGl*CRv)(_%3Do7T=H+G+?N9z3f ze7M#;{)?#EA4yH2)k<}!jCDvTXPq#{HVq_w$jNubaLU!n3UF^ttvsbFi31g@`P9+}A%a0B{@zoXEm2f^iI5=3AvC_tH$I#M*Wsj#V8+^qlXK z*y(EV4DW}z03QD~Jxy{3&|It=q>2nL{o+@x{rQe6g#&PuSt@I+tu6l=23!?_!_d-X zhwqSteGVW<^4bTL#~_Uds_2FVpB44>JJ-7O8sAa6N`BL5c0pvUL4V#L@ot+-7xDR1uXhaYV-6-^z`(k2OWA zR9;uv*yPSNfVkPk3-cJfokMN{k6 zb<8U&u=Yb{GtWL|NPQY;{BC zOyFRshn<`ZO_IZ_fz?fNwoOM76K&82$DCZPAAFH@VXj6ggO;gUXgEnO<>(OAO7;vL zC>(79Qc?!l-5$gL~%>pIPo#q9I1j1@NkJ#+~ zF~2r^JuFP-QJjXBVMB-IVGIJABF6zfB%}ofJTwh08iJA; z;PkZyxDWal&+qRwt60s@wxf5V5149c8AUxEiiMZe(yr=GxU;1dWM~<-wgCQWI}F_b z%f_?}3`8h=T0V#|`aZW-hF~1!Ev}DsT1y5BOri37@8t5#5vRFaIa}zw!Q%S1>G4i| z+5><~`G1#S`n^}G6Yn%?7BE=5im{KqL_*ww#yOTnm$vn1AO@lUch&aZ2fw}QwLUJH6q-c=`gjk`3`m!n z>zk1#n8xjC-W{)jdEPl^#);+7WFt$8@JE@@=x2nUWwpDfs+Y!`Ijwjryl|Jn(Dp2` z;?82ee<{`TwYJo1Z1*`>xEo+K4Btlwt8I4m*`sISZx$UrPUA2+2@cUU@q5dwQAZZc zMQa9pF<#I>)A%pK8!O(}vk~BR`f-mhPFh`0F_8s~v#p^8IVneJ0G5Txu_gQr;E!lQ z)B&R%Y@-NazETI)zlYvl&Mf7X!9ob$3^f=Q0ThNvlY(qQZqaP92=K+6urpJ%20^rSz_AzC`TBW` zSVNHDVd!IzQGp;v7JT6tZCW)RUaz&6=4lwS2Y`3;8=uIU=fMtuQRo>5EyQDq(m48Q zEUl3fUpR2FNwO7C5C7)xM|uz)_n^@nX&&iphT-O6)D-9*FMTrHNXz4$7OgO8mVSDL zLBY4@S&2W@Y=z+-MKIygm$1(%gPEoX8 zr~GZ>Qo)9OOOX}WbqF%%)=%~f!A<9}*Jb$9?jl4;isy{FcIPBQXE(vo5l}@!ZcSW~ zIt`)$fahIVC`N-o32+Q~X*HQ%+z%vQP0;UymrYISxVje4eJSrBcUxf`gmM44FpfRi z)RY2uD&ZDtO>dI&Bbo4%V%dNz(A)D2YW$Et=&r?zU=G=ay9+jb+JGStZJnS?w9?*Q zR@C;{M`aMRLi#2$yQ^c}&}=h+E3QXL0Jq^calxG;E>%0nw{P2iCp*sQ^j$Ez^rK&g zHLznv2kgGg`+JTsz z{#S5~v*0d>1!ga*7!#o(wNWqQ-*qthYvb2p!ntpKVYK7caY}7`f2)-uC)CVkqpU6O ztr{@8e~<+PM0+>T0+u`WppV$F*YDr3cUz(vMc-Cvwy`9hp33VT{GfQCrSYo<^$yP2 zK6cwHHd25G9{=Ry4?GSJpv@V)l3%&f+ymYhTpU-ky{GwbE|Rq5EqTQ!!ubH?$2{od zVvc-LP@HDFVy!`%tGLS*t}s-vM>5BH1)~~ncZeC|xyp65)k>zzy*TRRhUnlJ9VM4ZSAg-=KYek3E+UgH}mFxl*oF zo;rDY;ZqBLb*|&7)7jHV*=*))Hd@GzzW2~=KPmpYn7!>_JRK|E{8~0K6^TUJIm_{w z|CghIs-?6^F5uTTFmk?MFuhTxnRCCN zuHZMh>uxPt&HeK7Y(<|_VV)p+K@yxtamzFpRkSXmN=5)T<`rd*`6`1C`V5d;7qX4+ z-r2KE;~t#I?_#!S(=NE%{l6iXazi#@AFlqNc3n*sj zH{lgneJIitdH+%7Hq)+XAljG}p8-=v)65F^a*ESf&Y(Gs`60&D{OBrOX{;MM>?tr7 znqUGb5#Wpan);o%<;>t_d@Y*ZC8?BO0%kQB;Z|xg1V8^z`Ar}TV75_?p+O5u$S}!3 zY|~ukj2|3Bpb4;QkE0kQ1H(WjCAHZwicTey{N(-0rzz2Gs(c)T!bQtt0z!cgZa1L~ z2SoyD3$j{)Ex6Kyn+&wso;->H4r|=4L(}g=C=qBvqYkh03lj-Lr(X5Y^|g~WP!{Ps zokLcK16t4LZ$OxlbwJqaK#O~+JdH8k$c-a6?!iI{E|xNYFNN%n2{HI>a|X@`2^ba7 zMiBH^0)zyuOHw+nc^kSS&ya?j8M-4s1#%jDs0r#nw?@S~v~{M&5D0B9LFLtoklU%GIS{6mFeKm2r3Mz+o+JZRo{ z6#Z$1(reZu25bLmLqC-k3XY@YvXT6vDmtwbaWiM}4i&&ISL|ZK@d!s~ z*MVW(f(ykxEE>LXkELWn&tM|eKu{Z$&?opENe?&>-k`6^K}Qa9a+e!4^V??wuEaCy z^M!;A$ zB2*VCQgph;DwG+>3luM)$YXB;IbNQc$uqBAY2^wAjo*!Y+>LHhkwTL>Qii0}B_jx% zGRvVr1fj(fjY(39SyaIPVAg(4xMYOCmf6Dq6Vuzmsq05YR2 zSoDWM%J!TPFczSm)L{y;4n>zGxo9DTW4;77r@{lW4NL?mnn(n4r0n1dD^pzz6izo^ zL-WXKw#2M?`+amJo}p$gMlHWyDKNtyF=6SVm7q3gRo0!@%$Pr}!%Ik6P%>x0z?{Tf zh0P~Gt}S~S5&Qj`c~b}MPoG;gTcSaSSK%MfViool)70Z_upiB%0LRG0h`^^&t_jLn<`Z7vZhh;1;q--R=U-&Y23c7|=pf zAj~qz7rW3mT!F64GX$}L$q{cJa!nACtZ~pXxeDt~SIm~t{M6UPv;erHpjv=K+h2wF zq4!e4z^aS+x!=}v4tNufIv{&0eXcY83SSC7n%SbKm@Fj=l-OqHDE`3@H%B|8FBIy4 zcsH!u|K9z}u@VG@S4a-*#I&ZH&9fH zQI#%=aRZM6(6H0k6Tu`Zkgh^?b-7|Fa0Q;t|2#%CK{?KFC|blES`cr%LSyDJAy={l zt0nNq>=>39A*FJf2wY958W3t+D>w86Y2j~i(Q}sI?UQ&LipdNm?S)OR7AnHd3T)ZA zc}HW=GULpk7eFgUW^Z%C@D`r*{FO+rXo}-g0KSv>_P!el$Oabbw@=ehf#q_g{bSKyhDf$6viril!s(~u4=mKGZpcg#og75CQ_fdX|uWHb&$N6A&G zp{F%On%=bCLpfuWAP%uXVDnYZ0+|$Wnj53(kt8YSv`CW8HVND4CUxY2 zU<1~X#2l`;NKxISHpDVfu=B)3T$p*ZQ;Z=z$YGv1La~EJOf0xjJ$Tjvs)gDd19wHE zYfeX|i)q&1t`J^N0EtGP|9}U$BF~VT3-lZa*~v8Y_gf)(rf|lV&KU8+Xe<2w5^Dii zjVa)4O?cHR_Gu*Y8`*}9^SJ76yTV`s+YtDMe}HNr>xNwjxZsuWZh)WY5TiH>+lhyQWp_Vj-S6w(^rucm#DN zdxCNeB@~z#^IhO}f!as2sH!CIlq4L632ms(AhIpQIFy_xKO&<&Gu34eGE@&}n|Ibh z6?tM_a~94rb!I1bTi5M3G}}M}d9K7)j2TwCVNym5#7kAcKQ)Lkov!ji)3ejd-Fp(iidq$TueZN9n z;Y+y}$R5)t$7`D@coIlND3{9QY?jnrkY*D%P|#u}bbWge&!bT-+QF+?&Ey(^)KnmC zWZhz6Ie%6i#+wv^Qsf!;`_Q`aDD32b(k@7?`22%^_TZY@pa0q2x+Ay(T~W>upasKF z^4gQ+k;}vJq2~eSm7cuixE1zTnUrbZgSfMrQb0uX&(K+8JTt{V0xPg=*q2DE5ok^y%ghJ+{d^f7AewCmFRrBkg6yYWKF5JU4=JviF zT~W?tueS^?lrw}Ii$jLCkM_vXqMFMcUsmwq=@>S%o}P0zfvr!E(J!Y){S|#=XogdG z8brlRIz0DlVgsP)FIc% ziE0FVf@l=64qjKsFq>mksgR)gW97IHjA9LHaq#)6aTRj#xiF+fU)N86`&&n>SS)>E^xSGa0^a^OP zncaOwH*1Y6;yo~(-T4*XBk)2&gJ}nUW4jO<*WCdL0Am`BCs>aigJZfAfQD|$c}lKR z(xr!hC^{u5S&@0D7-rH>p7gW+6Ot+Xi~BRRm=LEx)kh6yjC3I~cTF$m_d%!U{CRC^ zd=MSy6;qB^<{4QYlx!&Hu`xOEH2g&nJ2)Z3gcE@g#A9=N#MZ}J7=g&48Qq)-LIvg~ zSYQO76sYxA~BWYm zH<3p6j1-fA1|48gj+x0=hPipIGT91~4j2#d;CIuQ6DtO~tiiHdi51H++!Pu)t&GSy zAzv!RkoSBhdZSOrd)^{rS`dn?UO^+=Pnz5lXVv-r{y3sZCq^-T@KL|eQ3*1pbUrAz z?UE$B-JQ<#;>`~07kV42^UTxUzP!EN;qVLk^>s22Q@@sikefy>U>JKofO1AXija~? z0|GP-9Hf&q=rfSxjIacn#Kt&)h9wV=7@h3p@k~=4s=?I8= ztXNZrblaFh2OE#aj3%hWxw0?CAp;?v^E;J-m`3@WM572`8pK=e&g;MD5ps%Fw2zmi zv+EkK`Mxy<&^`uV3+svlG(U=#-G}^>EOg3EfBm!Hr6(rxtU-B~G~pw(LF01(eJ`>V zInK?8P&sLoy+OKs(MDZ28C6)4Z_BP|M7C%gr#-8fpWke#qGtwY2!?uwgbKBM*e2-dV|yOaWR?<-Qe&U0hCcXa!<0JXXb#*8qgx4m9*fjj+G z!lSVL&ucSTT{emkMMFC=-JC-KD^FOkvX|(nBHE1>2K?eq#O7A?nVX=hr&kU^M}aC2 z$%AH+vz>HJMx>z3$eDp9WPb`##A_=d=$Qk&cT&j_LIWrtK z4y_k2iv>T%J2s~duu;w^vqeAkT>6*Kf6i0Ub?^JzpYSr5*U-)K)HSteB9X}c$+yLZ zi7T^>0wurfISN;<0Wk-88aQbMeL%k)FZ_o2auII#5UOmx@EEBfx z6(bi02PaRSJbwJ#mb;zg52-eN1&Kd#Fm7f`o9r_tO{V7vIerwYqG6-SR;!e^+p%2} z*k)hJ95eb@*1Q5okCNp#fPp+fPRp!-IfK4+S^gcOYa_BC>1auI>3m9(;K_+9A0}4;^4cj)vdo z^I@c1#%LgeJzlQ)<31@YB&oP5;S6`!^E`PD9|~K5L6{t zE08nNN}5Jk2(0=e1VO7eZ?{qeiYUzo8#B=3r^{B5Ph`&0WX3X1pAm!4vL4fxLMlQ;sf$D@PT9Az>Pelwl^AvSjAd!#p#XJdHo-HNC! z=tcRmVi1-06BrAi0Nz-~9x>t*kw4DVgDf&bxV$Jw|CEeb4m2afX6DsfD1$`{(gw1c#AJSo? z0Zk}qdKQP#xtT4Zdf=?T;6=kFPYED?=gx`9{t@&E#IzY%M32Dey_9sUV6f?WWj%0d zVws;MJBj2V^(WV#546Dq2|o^Kv7m2Q@3!d+cOANk^=gv=V~jg`9p=|;i* z0ISGxy6R)~kjb!QCo)IDU-<2Wdr3L$%qQ84%u}JNqDi*vGx=C?dh&w_TPEXVQbvd; z2L&`QH0_Oe-89Oe^Yf7+wB9!x4~W8tXC@=e8oA(xM@a_kh7LqO9@5hWSz!;FepMCr z7IpcVF4;gvbS5HY&=)~~hOD8^HNY5sHhs3LA+rQBnQ_zL0Z#XLy!!-3+?Ow3=3`OG||N>D21i`IOJRCFWZ1hj65aY?q2Q5Nw= zG;T~R$$k;s02A5?A43}Tv}X>hZG*ZFQ-q$@z^EE#Q;#h-)k6cA%dL(Dg4hup-{rFe(Swz?~qEiKr zGmowQV|GDvfoiiNqn%IIF)Yxm)Z1ok{M`9x-uHc7R!NrARZy({xYN+=ft0BtX}m=> z7{qExlC4df`jLgnWX$42WNA>1kTMIELjJm;JK$oC@y*^UEs<-5>%>}IPS{-)#amr6 zUaDTdZS?)6FScxJ`JYW@;RUrStEwp{(oj{6`H7sWDntT}Mc#i>C{@cVoKkL zf$0{So|~@PwX$j$2DJ(v1^M2Zk}4@v(OL$Zi00K=DRX(*C>ry23Rl#kt*BXRH6!P= z6_KB11*|d7q}YmPqgg^ghdy7dDS}+7irKEV-FB}D(yhG{X@B%WvF7^a>=PG(|Nig4 zPd6d@Drcka%c4xfWZ9N~Ke-Uwq7o>1wEYNqY=z>;GaNQ<1DMFP8*3=QxHhu@Z5J3w zHJczO$l8jAoTb6Nx@M@kYqcHjntR9K4)4E!#eCQO7U_P8RCv?oI((-QDCzz!lI8xb z053RgP}y1~c!s(OlygK&NYlpUGL1W-bxL5M?i=;91|VlpF~N%WWei%ONb}=>Y-bE1 zFIAq1k*lSmeo*{zpczhaGprBI-(X@-XfchAIy({Dg zUtSOAm>AK5ZT#TDPd$%zedJR=xb9PI|J!=m9{_yn2P1GDBEp;WBO~bQk1u0h6P5Fo z+X(-I#vEsfbUKFkt7It~&~_DzJbF%4s*U@Zx-zFp$qlgQrJe~{pL5`J8X@M=XgHvp z@zuy}n(!V>RHf8ScuPX7e?BydwY#cM-rlg%;C$ji!n}2w!?RMLY&5r?hoXa^oSNKB zQ&+m_-8I-}Dt?oNc@(P?p;-#oL@91Xz0OWkU0fgdHd0Q~3^w9^mk<3EDbBHX<7w=Ao%+@}w- zmhEJA=uwzFpYY1E%HOz~FA~?t!RPmgVYbG7tDX+>+jLkM^ZVE|NTWiNE75n+9BC&= zIn|_^FnAjLHHy7`{sq)AyhqQ3(`av?3sHJ`76@D(KbOU%1ABxea-d{=m1ea=RZsI$ z%(U1t&C_%o753VI4^BgwvYwPIAm6`@h7a}OO-ZgB0`s|`=_@7pw{dz0&Pw*)8{Y#T zITsYal4Hp<{Rx0AJ80GhZhRi@e-b|bvBy5P9Yd$b1eSB8@y#OLHI1QQ-=L|=`!lFk zd6cXSFR13%d25~lH0zo@V5tVZg;}Wf~O$G+Kr?b@4EN4Z_miwW%i6HTAe`&HLjG4!Z6xFmTgw4^V76eMe~9J zC}ESDiN`Z2@L0d;*}${A=JJ1r=mLMz*4DPAO()!4XqWE-$>Id(V~9bV(yPv0m0j%h z8#D_>cuaTtDH_wWp`SDOY-5wrTX;rDwN9nP zJwb{DY(bUU!|+)P5K>dg{yXVO6mr)Y86ypPDusdfrpC0cI@z(c|5l+1LagCOJB00Vuo&HwnT<4gTR8X8xw8@8 z!n3)g{X4uTioSTPL=J`VES+aF40RG2Oq@Zf`n%xH#eBnfo8jpC!H`sxJr?*g z{byh{$i>;4gv;&O>?B1-{JQh#yB40U%8IVAi&;hp7kcQbGGiv25oSggUZPR{04R)O z^AtGB#*Oa1H)fzoX|H`Cuh{h01H z50iZ<+blFU*aB#m@RRqK5lXE)NKR5K3K~tQ%}FU)BXF#fY>i3!^n)1osjiPi=mPxZ zxD&#`97iKUk*0Z1+Sn5>k1xM;p%1QO;-=FR?}vZ+!0hhjJiDB%#qdSE$Fl~Z2BDoj zl&c@=DGY@4(2~_hn>%|3dKxUl*kU;xTaLjh&7>_+J|aeggg_~6*&p|y71Q#9HBWQ( z=yv!DxMOuE6f;{aG}ll-i9^gw;$?Emaed^qH6sVngqf~CY!cNVcx|~H1o#JPFTxpE zV6*(=eR>^Y#h`7NG4t>{JexavAnPA3S)kycr*m>7R(Y$ni#_HvaUNPWJ|TW|q7^3e z$DWR45VECI)4eRqQ{;~=XV25YgY2=fh@Q5=+vFp_uLo|^Z3M?w!OWLdM4$RWeS=Xa zeuEP?!-2I1yQ5$*X`low5H`1EXb1+mV@9yy&GR&Moimvf3jVECgGIE--UN*os2JlJ z{IV?4EhkW(>^Z1eVjbZsMwLu)a^0t{hoxp2P9>W1&5(m!{1qwQQcnyYx$q7kUa!G=wdcmUOhUq1Gkc(1HxKbNk0$$eH z*yYfD{u8@NQMIK-Z7E8_;sVxeyXMSG3g5sXNalarGP`pb&*sFQI?1jYUookMuq{tr zsV*2^mLTnDg@P$!a$uu1Wek#45+e)05F511f{5F843>LYI;(W}!F{fE|FlqMFU>=g z@rrp3{N%yg_bz*K2=u$4k<1=kJjRCSdLC;W#6{)k-Eh47w#?Dhhe+XB6HI9nC@4|r zwbQsm5GqZxti1`b2vV)6s$wne#b9lSa4oW;0YXL$%?S3EZ@lz^0XKTa)#?M(}0JXtY!2LAyj&S>@EyP^CQX06-nOGO1i;dlA3NB$oh&1I#R+LK4LKu*sktHLqG|Ohym@y@ZPp^q(+Edx z==&0=eu}H*WRx^*s@d{6wFddT2_+|KOoAewVhF>IG5abuG8Z(9&~i#y zI<4^1)D(I!I^7_G8TZUJT5|{0=T*n~V69Z~mSi@Fv{gE2w5tqlNp5~M2bjI=0sI=Q#4s%^O8YA<}sLRBhJ#M1Sn(} z`{mKT@%)FMzS@55v+yr5hBr8NOEtY12BR{7K0oj?H1( zT%Ot81+S)-K2oeKKhg^@SZm3(qA2tm%kGjR>w@EVO@!4B!ZTz$0Pg#tljf&`b0qrJ zubPy`bOSrAMyaveKFZIVt-C>U)#GGHtLGy4AE+wiS>?YSdkyK5Uzy2Sah?PMIB0Ms@}jpeIGqr9nwHJIcnaPtDR3 z2^LdY<6UVm*gWZ6)gZxWwnGpvak+_fAk0y2i}~DA=iSfU z{oE;!>ek@{3Z1)T=r%fzLG@3+LD8&r_0r1tY zHckWl>u2f6OLx$+PET*0*g<>=3_JG>eN0)FPLT@q(>h9AxU>e$2}S9Mcr8F zK0)tYI`heAaCzS|_dNrIA)cuNiCG$Jr^TUx_ndb)FJ3f}f*_h6dJ|NBtm1t;o-O|S z12^XP7ZP91kKUk!VDi5$iOr&1+>F@we`qp-J7MFUY9fSQ469!PqUxWEl0 z1LUj2GWx@M9N zk`rxId_{5+PwPc-i?MNg?=jg{e+f97!4k-Lzwf9uzaSF}H>xbL) z=jnO}dFUDB3D+`LIfpLJJO{!~4bcO3>>)cMeS;ottREoKCr4gRSU{*WN?&%keof}D zXO3Tt1};M2y7A@5YMMmZ2uB(Hm9O;QqfU-lM0K&RpF43dqv~HbXUjje4oQ_{RZP>6It&8&hU26}lwHk8$ zmax~zVc7XbGwR+$caLv<=8n^>ik2z*{4TK`qI&-jwX(Pf%@d*g2C*HP3T$8i+m=bPvLBayYGV-iolCEvp&^$R;H%StZjQSgZjP6%TKPlF1QZKxr z*cHh|uSW_^LP#u`v_xt74a%b1SzV-2vz>+D?v?$OPBRxi0vP>Wllz zjtE8xM`7^`cVuCROwp>pKtC|x{-+to(pzHC-RhQ)+?HOg2R=zH(Jdpi!#6%$JJ5T~d*nvTz92mT z3$g`V(}r8VEYE$?+TioBjJeYwTdJIBwY-nNI4LKr=jV+sJ8Q6*Cn2Y0YxY>ii2kS7i56W<8s?i)`{qJ=n)421}#oAJ})D6m+<(Q|gf8y*)eIFP?z; z7s2Emy(W?1dY>HG0a#fYXmZ~Zz z#JQ5ISmFdt@K!X*R>0#fjL=Ia!QS;D3cjb2%$wY%r9r?1VvF9GUWk?YWLX&ewrS#@~C*E_hNS@qY4AN_KC$o2dO&IB4cTkaQI%L2^HEs7gm zKiRQdg^7WGDW<^onJ>X4Y8FhdWAVuhk68EC| zgi+jQYo-n+YIh2fUtLkQA<8YVkuQHdv%ra{A06&9t5;=LWq)j61P&t@iPOX+{9T5S zYk*vHUA2gDbroamCQqGF6km7{Tua ziE@4y=#e@J4#T5Tua?_-0@y#A>b>Dd?IwBX&&3ZPv7~amfKgP3*%BAv`S&-ig_jfa z)hApoKFuQ{`oTgtZ|fZiO&@bOjv`*hkRv}7nwPK#Mh8E9lK9o&8g7tn!7thvJa~}| z4=`DCMit_!`)mNpVieu)%5jVjJ^?@EFJ|oQHV>b4qs_YG@BqL+!N4Q>&lrEm4p9`2 z7M1O@Gj*2H0VA<3z&OL6P)1Hfi9Ki|gMUn}9=Q}H=9A@Oyd+TJjMgz5Arc+CpmSs? zbEHG}HD^)I0FF&tUsYj}Jn?iQ(Ld-A6Lc$P{>cX1i0>+=k~zuFg|!s z(h<6F8~*%jH~;v;e?3>mYv+Q%=k&=JlOZwYw-lZt;}>XTVQCXF8gh%ijB|FnzdYk3 zA-EKl6sHZ?fHzhk+<0X?=JH?E<#5#>OWThug0KDqJTkBnZaKtkI^zu9E>=ezBg0OV zM?UFhf(n%>PA8^9MrT=u$s01|@FK_IMT-b{1n?A7S!{}lkR)-rGsy&yz#T(#p7!ir zb(HeR>ZMufF#MI-FZ-iOJXm!>I_D6<(X{R2wQwDL`tdzHc)AjMKPZ5pZq38S7nP@P z^_V&7@6t|-cxl7EFlf+Hem(b1QJcn3hAdfcV8AlNu8P2t6%7WG>=EDc_J%)WN)$EO z+ol-`JHqDvVJySc7saJ80PX=ebp3q;i&(cX_Rx=wiV|gBnf7%DNx#uWjyA~Dv3(PX z6Fa4_7o@+k3Rcy=UB(M%6p}HfoY5KNIzk*n79tWKaWb|!q8Pk6aO2^z2nk0yQFE0c zz+RqHD0#EPl)LSE(J>FcpV)|zKLWbE!Ib)F%3!!P{e|x>a^=0+HA|*=E<6Tqo=+5Q zU9M=z=}d5~`BsNdH8>`nP^f3=*#iqPy_2E=G+0r*5GAVUaa2{8k3#jf*8@ItaFR}x_lwW4e#k5vX)} z1408GR*`$vYN2Y%LbYJyjF%=l9y)TyHC;tnPz0vu)q+V;D#%r5CM%#BG~3Kjp|LW0 zmU4Mbk(k2*dk9P>j2=yV(F|2fpcp~Qz=9~YCcsAPhEA;- zTRa$I=C>Z#V_5VJk;fp?o)2`cUNt?|{tWhhu@T=h{H0f*13)IT^>6*KUUKHpT)Jft zFo@?N!rUp@MPTki7e*bJ&44osyFS_62y}>~Bk&8=EV$?$o=kfyK7O=NaQo;*^+b3{ z5$+bsi7L8AUiEFpUpp{H?8Pu*fiZMe{q2$i4hIi81HGJ%M^_q3x?^F@+@8`aKrr3- zFNVCQqWf?Iq7QdL0;RXRkdcDwYzYC%}5w-Ja{L>Af)aTF$5RkdF*OScx5?z;s%Ev-^Ad{Ujsi4Z=>zZ24ptW z%{KMu)Hsu1W^ZPpY!D^X{AM`@yd%rPOg+~0(u-L&ddip;C0wJ&L-Z>w8}p;tO4A%h z+|sC8Ix#y%(39g$xlS0o?i4JVB%iH{As9)n!MIyA8lPc28UdSqyZS-SQZ|w+?25@$ zkFjY>zjdCo?Kmuu;k3uno1~K_6hO!h=AcLAMi|xuuxZf-DypLZJIfq#PLP&6o@ZrH z9Y4_h)KMEt{!`xV)U-2gzpp+jU9;+8potG-{X+HqzrE>2iVh9c_n%z-Bbt+K7pgS^ zMWjpwi^&lbd4$F-V%T$uQr8<{&&EBtfQ=`i?CROq47r}6DqYx+>_}@h%E<@A=4#Iw z&gd$ZgX?xf)ME$=2Pvm1RQ~$mvaxI;8NdJMw~DXWdLtM8iFvqtiKeU@Alf?Ro%}ew z^wWU`Z=0XY-pg@rrn~}gAnq95drA?D_rJ@_weecA+%msX9}Px>d8X`I8@)Jw9qpmH zU$B?l7nysI!u0+VGebeL(e>W5(M?Aw?W*1n=I*DmuGx4VRdl#_#I5ht=U@=TCWtc{ zSqbzK7vRJX>`s-C&+&=OH5b;rju+nu^%q>~DT;#RGK^XDoJ9Rymo;SU8`iEfJwrV; zL~WVVeP$?5uD`U`*nFY_!r@iJ;%N5Ru+`_& zvltksGv1YCW&B2<%mtK$Jsgc;hRyW0KV9N{F@M}-eBe+ntk5e2@w$ES^*^f5oKMl? zGhpOz-Hrlk7TG}5s#n-4z(%Y1i$8f-|DUDqh0k*vX^_4j)`+-b*&rHfY0!{03zl*Z zu_98-R+WF$P14&cL!YMTjmgg;c?K;Su?;&pc_V5*# ztT~%JZgtew8=JJI>-vhV&dKgJZaCa}f z9mxZq8pu?+fZgG6ORwlOn@orxiq;4Ap@Wnwf^1LN z%r$x@O%}{xwl6uEbXID-qTW1yV>*!SDo#7FbDT1F(pWawa#}Igl(7YJaYK8?Xfc{h z1((Sv2!;+z-cpIUC#M@M16%WV?-A(5QuW+6>^?NoRR28WpuQ|k{4wk&?so7rFN3w2zt;j>gl|=D5 zA+U26{l9AgsqE_nDuOhYtxVS;q$gOIj8J3YRx zBL!Ix?Ahm(GD3<87`=>2L$hR)-9ZITraQpP9k-Cm(`)R2oFjO7LrP zG!~E$+tO?j1+Yno`UcV1!V<4PI#_>8Z=KA>T>W1P(nF1GlPx5RX&j8U+I}eUcPq-I zQ7jB}fONie6TOSj4QKdy2w6(d67hlFK}0184ZEXfJ6qQ!?ty=|ZlGiP`$xIYJn;Af zJ7CM>gyC(yu)wZ7ac^Q-#hvqf=Uls5Y}H%TO_G7@#98z3rc)4+pzmU75u(ws&MivN zQR5fx((IuTvk|?VzpO1lq}>W9nG<1QDSD{V0+~j=7g;7maPq_82}}x(Ks474_#N(F zOv7!LlD86%a5F&D#0dPeoE?4G19cz{cPBLpd9t%ZRt_wb^wjMch?6u@4J2%UODMNebaLH^&1bnxC;vJu zmJ;WUWy<|HZ3(gcj0hWF#!!(0s6L>fIdHtBdvL7E1gmp4VXu9oKGN41>+>Pc;`-R% z%g$*lzq<#F0Y*7cr;Yv6%?W!<+fcw~ps8N;AbfmkaHpc3}N zk>v}H4VQ*isW;Go3ys052EE@Iw-Cl5@JNrYMl+LGGrwP-u*KK0&x7Q(3G!0ST=bZ%19Wtt$#NGHujJYU$b&jQLV zV+&4BP+BNM;U9MD>ho=c_MN^J{~$Km;HLf8ANL(!Od5!4h(Sbg0XE)-%8jst36JJs zMk|OoRZbA1&pOH_4S_nZx%B5pXM+Vw7-z{b_^ULj9Jdg&;%Q@+-pbqwIRsvn79pO+ z#x59VTA4Nylme6B5_|)YaWEuCny`eXm97-CQx|$$Lm%I*_evA&xJ%@uAhDSOIf74B z{>$@^tR1}J_|2YV+wFno`T4rLI=Kc8hFX2YQ~MfO-peTXAR^qQ=8*}jt7ob$;T`eO z6zMd7Zqxd+2j|4}0C)VNhCH)<=neWO3P{&|t2uX{?JRBfu~z~f2kF>6C#Az(pZyxm zGK;sPjJ^UMDX}VTU|Dix&BU5Zn$bmx70p#HvFM17WBBBk28wAgRDkn!B=uJ%AZJXr z__`aEZ={8a>E;^7;=O|lCfT%x!o1<`^iUUENNw;B1E&$DWm$H7wOw;y=QOLv~+9|k_vqFX%IC%LjbGBT30y$ji_O6B4CE>A9;_0 z6}2w@{tZ+7!KMs_Ix)Y?Z064%o5!x8r{X|6Al5R#_Uo=``$s>LpL*n&*qqQ-Q&yVRH33 z<~v7t2)W;8{w?R5Y-K_96J!3?{!&}gNSwvMyQZF9mh7_pief_xJvIpAeKA+rxTF$- zNn%-uNm!jo%%;?KOUp%inwLH3hJq$l`Eg6uy{Is#^$wC7uz~1%b6xgqr!j3b7D`}< zP1FBHWse^K1vCWf`yldQa`(Et^PgD8W z1D}Q5gzAdl1UI3yqJTiNIM(e==FqGJ>-n3asa1U=B3%CNT4BLtS6{x_{!lFh`-WT7 zg{lJu%{}3!mQLg+)~tAKZt(`WGrDDgn-XHl(V4Y!z5;Vd3bZC6q#{kI~1san_`;cjet^3wbLVuvDGoWoaZ8e1D?v{%&di9A-XXLp3 z!SjKe_qfth(vwz)?jQX565x-(5yO$@a={uFQV3c4n=gWnq%rKO6{xcZ>B*f_TOw+rG-Me+UP{lnXaEJ^C&d_E=Xiq->wAS6wj_1j{|S( z%N}giWlzBlil%S>xA~o&gW(&ep|I`QwrVfln$|YnrU^!LA!UPQ-Q*D#rC#jsg?V68 zOa+G56m5u-24llE^K|2#VIaS5{pd>Dznq(AE41RC028fHNYUiPoVxnC#vr=EzSR$Z zX_$#Vbuxcil8rq!o-d>_zkYLQFxNBB<9zXKvO;f6L{jTc^m20igZ~V-BnqSc@fG8O zX<8glbS6C2f>%z-#ZuR(^_Iwm=NAsjH(Hy=961QlCl{&*w7C%Cp#gb8 z^WlV5IxQ%@aacKSI6d7Lo)md&F>f-Jq$~!QgXt63p0E0BHjisr@Mq$+7i&!~RIl?6 z`Mim~aWGXTY_ih;9b=%@R=$aWed)q{j`tLAc+(zN9cj-*N;B4ywScMfY(lF)MF6FI z^x4C|xTHkB*7l1`Mv1Fje`(sDn}`+{W(>R7%bJk1d?6lx@vZYgl^5G`HF zo2LtzV*kMduf{Zm-XO;4E#-9*|0;ALP$plHKHxN8!G7R9Bqoj0mLx&C@A!jJv%7b9fKcq7RGZ+;~ib&ZSiX+4RXz5 zNr7a}%MJ|6Z#%DC+f=js<~^?VR8w0bq>NhID?a{sIqyrfIHyfw+0d>`*d~Qw)^maL z!g)(>Wb_8Ue9is|4t3O$)p*Xx8>R*64T>P^q}Aj^BsOk&PguJy&$}iy?HaSOEjZaR zo_Hxe17;do%*#kf#XYFXIm0lwCT--QT+C$DKlsn0DdjSX^@%L`YN-~3*DZ4IHrhxB zvL0!CTuZb?5zxVS8y3xsCrKrkDmoG0F@#6<3?b2yX2-sG>F4>$1?AUGyWdcU)05tU z!|R`@+Kp$xt-|=&*Rn(LI4HM)8MSCK7Zz7oVzxkRp=aIjiotQPI12n!1X2cmKVNRv z9BIEZXt7SHt?=O&UA%!Z5A>E8wdnZOTVPYERDw$nc3rdnea&NB=AmNHB_|h5nkVQD zBXjAka%S+$mo9iq&NID#?Td^i-%|SR$bGM4zGRC*<&+S&dLa|wv}$K(^H|6`HPVyH zbbIXK)2j?w&fF0$R5+z~X;LX`Z3>MAITfcq@ay!)P&Wg^+0wP`(-lX>m$>wi_F=x< zGSyW!guPW+u9;=I;3>%pqLHI5V(%|nmgmk+Y3}i6Q!YxgfpVr|wvuf!%Cf;=tVz=z zjQXdFMN?%#wokpd@}9}l!wbbU=P*vHTBzyO!8usCLABzhQ9b zo^b|K4W1Jxf7xq^n;aDz@^v_i_u)_trcyi-Pg{7gs!8RMd8ws3S2T-5ef{1KO``fe zm2r-hY|U%dy!vDIcKzR>P7#A4_+PC(YjhN4mba?9s;l4cM>^^5bVx!HNWefq2?-DZ zUnr|Gj*1V?AnW6-qQhZ^(F143jIOK8jQ-g@v%9mdI&)@MXV)|Pm^~r1du>N z5|VV1?xefZ??+X4bye;6RVRSL?$Oz~$>~aN-|uzne)qfI_ucP)hQj3Z)PZDraIo!A z`5HGW1-{BNyyo5nYeX`kOMOj_VJF!TgkJdpGBw8Rf4CXPdPI|`VFIYzmoI8I;JBlr zBOerifx{(rHMco**xTF;m~B|0%<(IouKpYrx0%1NfmGC3(Qwd{0$ulTu~r&4sH?%I zNr6ozK`P~C11UAL`WEAvU#0u1%~Sah*d=Uwj}`@i$qqoGTuUcxxe4Kej6_?lDH1fl z9^W=2fKV2X80yq9`Si~wV_#)O1q2vufYBO7h3OlXHh*5KEHPXIU-H?*pwgH@vOfWX zNQWK7k?g(>ShQ?uQd{-T%MJ7;ZHNAZ8z?dBh0C>g0Vam@HyBzO9NlmMp3#R)_fk{v z?7@L%7*G~fFr-a+UA`PTMLYUeIL>ETa~`Tibx7;a7*nJ6X;Km!;LN7qx${^Ldk5L) zO7-wgM}H_q~=)y$du=nK!SaypCrW2s56(7B(IJx;z7dKrK=IE_48-@YeSo z>wdYCFC;BF3OkiT){>+gSwpIJ5ZOC)%5)(?gc&JrKD6!#3_$Y$=9+I4e-L`)ci#3z z9T!MaSXD~sBIu>p%mU>J;{d7>%jj?nGt{i#W=s(^QsB;a;6TVo8}0wHWT?s*ZyFL7 z83#Ga!%a7h)?IL-DKxewm!F1ZKMV2mO`&Vk-dN^_vt|rh8#RuXw>ZSJhYm6j6t5%w z>KIS~zEmh=q)T$?hF$(fAQM_S@L}_0Ec1k~?@@mp6B1$z<2IIOg=!IaS+B-QCADd^ z(f_yU@Jy0J{q8;ePj_rR{P07++5F7EcfXx^`|mT>2Z`T1zSy#AK)s;*!gM-XB`iwQ zC9A2dmWnc!%WF8}gOlE+znRj6OUPKH?qa+j=@MN9Ro9&@7Z;wN4QS6TNo&;wt?qQ` z=1Vl8=E+A3+B=x#eK;5Eb^9&{*sLiKUA(;SpFa*a`+^U zlup^+4GTN|#=PU*$-^36Es*I0JrC5|mJ*gu&c&^5^?ae7iB#nYBS+=r8re3}IQt-1 zC;ccW=S6HQ<`36q{N40IpEFEOe#>9KdM2nQ#Z=y%LB_H~P1P3`tP#V3T6yZlZ5#gl zZTpXnNtRb{H*kauX&q<#^6?ic!m z6sW!(_drQPmXl-W%#|TtqlQ$&3@_@qGIm%;KzR0|&&5&NE1c#s?P1ofE6#pgn@B)p z8y$pG_C{adyVF;u$YfwQepmxDz>GP^b-#zrD=yC-3fn=Ky2q{#zyH#S*`Dd|;Kj<} zALKh8zfLv%QSc|?+0Cf#&u23-?fB`6seWtKMTvC8QauSBGVQr3_%ot^aX#x~Cf)pl z^U><&fJQ?(aWxPFS*0*7Z~d)%5k#q}DksXpdJr~FYPj3qhjws3c$H=7o4v}yx|O`p zE<~+kbr+iv>lYU@Vti3Q=dGXYbGL|F@!R0N`w4mb4cD>0G5jxm^P56`Rq^$)f((rA zHmG3@q_N68*}|4D^R4W3M{|zgnr6=@wS(^BR_;sdD08!st9?bzo$JQ)@6iq-sIy#1 z+H-t>3^~>`xXC5s){dc@F8$)#47iWZtig{ueYwB3%2zAr7=cN~N3x9nB!~c%}RmYT>+{#Cc4QBfZ>33*U0 zKQXcr+2&|kC$(REj=o~0U#Y^JXVEndLRW#r=MeFVKfdJ#Uve|I!A7tZb9mSOU2pB& zKS!+GkZ}Dhpp5-0cFhx2K%si|#htK!7rcd@ZvpIvk_(@2OX54KU6ogWO<9!x>-b(J zC4=6*y(yF#{u8By{k^d7wLR#cm-oTTdwcipQm_iV^(wr$yJUvFfN3zM>nQAb4KTG# zybQ1prNW!9dvIFVi`wzltC62zWQ86R!fQBwLg!qT6$b{na=jkFafHW(%a!I_Q55sv z8$keQdIKI|c*$W;~B%>bh zW#X+vWp@}OL7}<|71H{+8kFmlGvFSVZJ-{NTwDDJ%^|^O`5Tm3Cq13Hf%UTcHeV=+`Z}0mcGfr1W(J;ot+&NWf!`-sNT*hq;4cS z;NAHl`APSyHzQ7xxAtx+OGO)R7TS1*TImw_@kTTna75ITJ#EQ|_*f6mqq1q>=vkgM zNAHPCtMzSC-jvVhU*EvD#RBFjxN~n0f9ETA@?h7DO*>L$rzr(`L4JTAmi`r%Pa zSU;ShMUmQbaQzQAKGQllK0aAJVLqPj?G|YS`X?3Cq`fRk{j+p$ckjkblBAz$9(>*# zv2em?NM=6XtV5~UA8wqTnaQx~ixFkE+vN+gPkzw+^y1<174cJ-zq<+ctiL_3`}p9o zqsQN`3VR^@#$T=7UZ+4y%R|(g+m}7w5`_{ibG{uxl&gHK`-rqM-#y)4MN2U3a!;dX zXkI+ANz)6PQe#y`UdnvG^{^}-lkecoJ%`#(*6hB&Tyma%=?=DcBP;eEyW@*ga;VCl zD>+9rdVz0OJdvgy<#L}-iiKP$k?lQp@Y7?P_uRp-O$4q65ONDZU;E(S0rsaar$W2(JnZ;hx%Yp zYPuhxRIg&mR|GoQI8Yb!pe~PhIOoULOtL1c#{CUnZHqCe^W8>{g>Q)|sskZAkK-;p z8>)#L=OkYNlu6NXJljEY_#%b56UYFa!eGO2>v5Eg1qaknGU?2W)dUww7^8G(rRe+w z)YTlA@3BhnajiIRHt~rFK7Uy0bI@7LhH7*r^(j0GA*B#OV+bUdlY>INv9d3y_z&Pb zY9zLF-h#R-FiJnh+lk~wky= zRdq9nAxQbyCK`e;2rU<>u9-4u&}e|hli>OwTsFp`j>O}L;_Rcbp?5dhLZ7q;(nyij zOd(uNTmbjXWdWLKe2*P&2{Jese-Y!LzJM2}aj^)?xF>?AqlQZf}#)SRc$;Cr#Q?%SpNmC}4uo1@hO3p|$7Y_f!qhncM_zo$f zwM#h%750ur%T*FxXDe{*njIUqJ8*>9^oW1RE^qwhV**W=AzsW$w9_=4)mcPsV2iA= z3*};Xifo|9nFzN)LyMOPV{CxlEdAtSL@Tq|>p~(ui4P zt$Len8)?xALo+ZjkrEi4noktQ1_UxtTsT!U*|^K{s*=H{F5j|-_$MrHtXX@?2&x43 zId>cX?Y`3R!Z5(rpDQL;MzXsUZ)N~@%2}Gh2l+faxbOOJYf-=}zs?Om$AKJK;9U_V zmKTdO2x$uU9Kent4JKY!Jr4Xu5AQ3f&LZ(|7$$`|XC8lnOesj=&&L38sfjmwU zJ;+fO6+AObg5bh7W&$4*AO(79DV3{uv&7ATU<0a}hp!t@ms3m6;t04IFrqIrR>Ybx z4`owOgk`f%q@RxXvj*njG$d{^MkQ9`wDq^?os`vJb;sy%m4#HRGY>q% z7*oTH$7-Qy(ai@T0XBM}-{wZZmh1^ZvUEU_7Tgr!%ND`TMx3@uxh9qx?-_4(vu3ZG zt+i6lq}w!{NJuj#%hv6NkW^H=X`gMhR5Ib81$sAaFrdjP&pJgmXjzH$zl8JzC5dv; zqo&kJ-pG+mtgHczmN6Q=b)Xw%ODSXpv6~Yh)dPZy{3usn7}VP1_MJr%dyJ^0(2C7YO%ozXLDks?-ETa$_)RI)7Hx>+)jL_-vO zPt%a491KE|W%+CxN3z#6(q&mI5-LV7P-%(drhxL=fHr0sf?(_t5$0sJEjTQ>b*zOE zkv>%m4sl5KnL`DKxVx%G+Lk-Yr+zh2NTWO7o(h$M~ l&DcH#N2*#{_n0bX`yYE Date: Sun, 19 Jan 2025 19:04:23 +0100 Subject: [PATCH 02/70] Fix persistance, WIP Commit for the weekend --- .../jcs/persistence/H2PersistenceService.java | 18 +- src/main/java/jcs/ui/VNCPanel.java | 46 ++- .../ui/layout/tiles/UnscaledBlockCanvas.java | 286 ++++++++++-------- .../layout/tiles/UnscaledBlockTileFrame.form | 54 ++-- .../layout/tiles/UnscaledBlockTileFrame.java | 141 +++++---- 5 files changed, 296 insertions(+), 249 deletions(-) diff --git a/src/main/java/jcs/persistence/H2PersistenceService.java b/src/main/java/jcs/persistence/H2PersistenceService.java index 0409ec81..cb696eac 100755 --- a/src/main/java/jcs/persistence/H2PersistenceService.java +++ b/src/main/java/jcs/persistence/H2PersistenceService.java @@ -40,7 +40,6 @@ import jcs.entities.SensorBean; import jcs.entities.TileBean; import jcs.persistence.sqlmakers.H2SqlMaker; -import jcs.ui.layout.tiles.Tile; import org.tinylog.Logger; public class H2PersistenceService implements PersistenceService { @@ -611,20 +610,13 @@ public synchronized TileBean persist(TileBean tileBean) { if (tileBean == null) { return null; } -// //TODO - TileBean tb = null; -// if (tileBean instanceof Tile tile) { -// tb = tile.getTileBean(); -// } else { -// tb = tileBean; -// } - - if (tb != null && tb.getId() != null) { - if (database.where("id=?", tb.getId()).first(TileBean.class) != null) { - database.update(tb).getRowsAffected(); + + if (tileBean.getId() != null) { + if (database.where("id=?", tileBean.getId()).first(TileBean.class) != null) { + database.update(tileBean).getRowsAffected(); //Logger.trace("Updated " + tileBean); } else { - database.insert(tb); + database.insert(tileBean); } } diff --git a/src/main/java/jcs/ui/VNCPanel.java b/src/main/java/jcs/ui/VNCPanel.java index deced133..bf69b6c6 100644 --- a/src/main/java/jcs/ui/VNCPanel.java +++ b/src/main/java/jcs/ui/VNCPanel.java @@ -49,8 +49,7 @@ * * Inspired on the work of https://github.com/shinyhut/vernacular-vnc
* My ESU Ecos 50000 has a defect in the screen.
- * This Java viewer is helping the development. - * In hind site I thin is a welcome addition to add to the main frame in due time + * This Java viewer is helping the development. In hind site I thin is a welcome addition to add to the main frame in due time * * @author frans */ @@ -71,8 +70,23 @@ public VNCPanel() { private void initVnc() { addDrawingSurface(); - initialiseVernacularClient(); //clipboardMonitor.start(); + initialiseVernacularClient(); + + + String host; + InetAddress ia = EcosConnectionFactory.discoverEcos(); + //InetAddress ia = CSConnectionFactory.discoverCs(); + + if (ia != null) { + host = ia.getHostAddress(); + } else { + Logger.warn("Use a default host ip....."); + host = "192.168.1.110"; + } + + int port = DEFAULT_VNC_PORT; + this.connect(host, port); } @@ -388,19 +402,19 @@ public void windowClosing(java.awt.event.WindowEvent e) { vncPanel.menuPanel.setVisible(false); //String host = "192.168.1.110"; - String host; - InetAddress ia = EcosConnectionFactory.discoverEcos(); - //InetAddress ia = CSConnectionFactory.discoverCs(); - - if (ia != null) { - host = ia.getHostAddress(); - } else { - Logger.warn("Use a default host ip....."); - host = "192.168.1.110"; - } - - int port = DEFAULT_VNC_PORT; - vncPanel.connect(host, port); +// String host; +// InetAddress ia = EcosConnectionFactory.discoverEcos(); +// //InetAddress ia = CSConnectionFactory.discoverCs(); +// +// if (ia != null) { +// host = ia.getHostAddress(); +// } else { +// Logger.warn("Use a default host ip....."); +// host = "192.168.1.110"; +// } +// +// int port = DEFAULT_VNC_PORT; +// vncPanel.connect(host, port); testFrame.pack(); testFrame.setLocationRelativeTo(null); diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java index dc8f3998..39eb21b4 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java @@ -16,134 +16,171 @@ package jcs.ui.layout.tiles; import java.awt.Color; -import java.awt.Dimension; +import java.awt.Graphics; import java.awt.Graphics2D; -import java.awt.Point; -import java.awt.image.BufferedImage; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.util.ArrayList; -import java.util.List; -import javax.swing.JComponent; +import java.awt.Paint; +import javax.swing.JPanel; +import org.tinylog.Logger; -public class UnscaledBlockCanvas extends JComponent implements PropertyChangeListener { +public class UnscaledBlockCanvas extends JPanel { //implements PropertyChangeListener { - private boolean showCenter; - - private final List tiles; + private boolean expanded; public UnscaledBlockCanvas() { - tiles = new ArrayList<>(); - } - - public void addTile(Tile block) { - this.tiles.add(block); - this.add(block); - } - - public boolean isShowCenter() { - return showCenter; + setLayout(null); + setOpaque(true); + setDoubleBuffered(false); } - public void setShowCenter(boolean showCenter) { - this.showCenter = showCenter; - } - - private Dimension getMinCanvasSize() { - int minX = this.getSize().width; - int maxX = 0; - int minY = this.getSize().height; - int maxY = 0; - - for (Tile tile : this.tiles) { - Point tc = tile.getCenter(); - boolean expand = !tile.isScaleImage(); - int tw = tile.getWidth() * (expand ? 10 : 1); - int th = tile.getHeight() * (expand ? 10 : 1); - - if (minX > tc.x - (tw / 2)) { - minX = tc.x - (tw / 2); - } - if (maxX < tc.x + (tw / 2)) { - maxX = tc.x + (tw / 2); - } - if (minY > tc.y - (th / 2)) { - minY = tc.y - (th / 2); - } - if (maxY < tc.y + (th / 2)) { - maxY = tc.y + (th / 2); - } - } - - int totalWidth = maxX - minX; - if (totalWidth <= 120) { - totalWidth = totalWidth + 20; - } + @Override + public void paint(Graphics g) { + long started = System.currentTimeMillis(); - int totalHeight = maxY - minY; - if (totalHeight <= 40) { - totalHeight = totalHeight + 20; - } + //Rectangle r = g.getClipBounds(); + //Logger.trace("Rx: " + r.x + " Ry: " + r.y + " Rw: " + r.width + " Rh: " + r.height); + super.paint(g); - //Logger.trace("MinX: " + minX + " maxX: " + maxX + " minY: " + minY + " maxY: " + maxY + " Width: " + totalWidth + " Height: " + totalHeight); - return new Dimension(Math.abs(totalWidth), Math.abs(totalHeight)); + paintGrid(g); + long now = System.currentTimeMillis(); + Logger.trace("Duration: " + (now - started) + " ms."); } - private Dimension getMinRenderCanvasSize() { - int minX = this.getSize().width; - int maxX = 0; - int minY = this.getSize().height; - int maxY = 0; + private void paintGrid(Graphics g) { + int width = this.getWidth(); + int height = this.getHeight(); - for (Tile tile : this.tiles) { - Point tc = tile.getCenter(); + int xOffset = 0; + int yOffset = 0; - int tw = ((Block) tile).getRenderWidth(); - int th = ((Block) tile).getRenderHeight(); + //Logger.trace("W: " + width + " H: " + height + " X: " + this.getX() + " Y: " + this.getY()); + Graphics2D gc = (Graphics2D) g; + Paint p = gc.getPaint(); + gc.setPaint(Color.black); - if (minX > tc.x - (tw / 2)) { - minX = tc.x - (tw / 2); - } - if (maxX < tc.x + (tw / 2)) { - maxX = tc.x + (tw / 2); - } - if (minY > tc.y - (th / 2)) { - minY = tc.y - (th / 2); - } - if (maxY < tc.y + (th / 2)) { - maxY = tc.y + (th / 2); - } + int grid; + if (expanded) { + grid = 200; + } else { + grid = 20; } - int totalWidth = maxX - minX; - int totalHeight = maxY - minY; - - //Logger.trace("MinX: " + minX + " maxX: " + maxX + " minY: " + minY + " maxY: " + maxY + " Width: " + totalWidth + " Height: " + totalHeight); - return new Dimension(Math.abs(totalWidth), Math.abs(totalHeight)); - } - - private BufferedImage paintTiles() { - Dimension canvasSize = getMinCanvasSize(); - BufferedImage canvasImage = new BufferedImage(Math.abs(canvasSize.width), Math.abs(canvasSize.height), BufferedImage.TYPE_INT_RGB); - Graphics2D g2d = canvasImage.createGraphics(); - - g2d.setBackground(Color.white); - g2d.clearRect(0, 0, canvasSize.width, canvasSize.height); - - for (Tile tile : tiles) { -// tile.setDrawOutline(showCenter); - - //tile.drawTile(g2d, true); - - if (showCenter) { - tile.drawCenterPoint(g2d, Color.red); + for (int r = 0; r < width; r++) { + for (int c = 0; c < height; c++) { + gc.drawOval((r * grid * 2) + xOffset - 2, (c * grid * 2) + yOffset - 2, 4, 4); } } - g2d.dispose(); - - return canvasImage; + gc.setPaint(p); } + + + //private boolean showCenter; + //private final List tiles; +// public UnscaledBlockCanvas() { +// tiles = new ArrayList<>(); +// } +// public void addTile(Tile block) { +// this.tiles.add(block); +// this.add(block); +// } +// public boolean isShowCenter() { +// return showCenter; +// } +// public void setShowCenter(boolean showCenter) { +// this.showCenter = showCenter; +// } +// private Dimension getMinCanvasSize() { +// int minX = this.getSize().width; +// int maxX = 0; +// int minY = this.getSize().height; +// int maxY = 0; +// +// for (Tile tile : this.tiles) { +// Point tc = tile.getCenter(); +// boolean expand = !tile.isScaleImage(); +// int tw = tile.getWidth() * (expand ? 10 : 1); +// int th = tile.getHeight() * (expand ? 10 : 1); +// +// if (minX > tc.x - (tw / 2)) { +// minX = tc.x - (tw / 2); +// } +// if (maxX < tc.x + (tw / 2)) { +// maxX = tc.x + (tw / 2); +// } +// if (minY > tc.y - (th / 2)) { +// minY = tc.y - (th / 2); +// } +// if (maxY < tc.y + (th / 2)) { +// maxY = tc.y + (th / 2); +// } +// } +// +// int totalWidth = maxX - minX; +// if (totalWidth <= 120) { +// totalWidth = totalWidth + 20; +// } +// +// int totalHeight = maxY - minY; +// if (totalHeight <= 40) { +// totalHeight = totalHeight + 20; +// } +// +// //Logger.trace("MinX: " + minX + " maxX: " + maxX + " minY: " + minY + " maxY: " + maxY + " Width: " + totalWidth + " Height: " + totalHeight); +// return new Dimension(Math.abs(totalWidth), Math.abs(totalHeight)); +// } +// private Dimension getMinRenderCanvasSize() { +// int minX = this.getSize().width; +// int maxX = 0; +// int minY = this.getSize().height; +// int maxY = 0; +// +// for (Tile tile : this.tiles) { +// Point tc = tile.getCenter(); +// +// int tw = ((Block) tile).getRenderWidth(); +// int th = ((Block) tile).getRenderHeight(); +// +// if (minX > tc.x - (tw / 2)) { +// minX = tc.x - (tw / 2); +// } +// if (maxX < tc.x + (tw / 2)) { +// maxX = tc.x + (tw / 2); +// } +// if (minY > tc.y - (th / 2)) { +// minY = tc.y - (th / 2); +// } +// if (maxY < tc.y + (th / 2)) { +// maxY = tc.y + (th / 2); +// } +// } +// +// int totalWidth = maxX - minX; +// int totalHeight = maxY - minY; +// +// //Logger.trace("MinX: " + minX + " maxX: " + maxX + " minY: " + minY + " maxY: " + maxY + " Width: " + totalWidth + " Height: " + totalHeight); +// return new Dimension(Math.abs(totalWidth), Math.abs(totalHeight)); +// } +// private BufferedImage paintTiles() { +// Dimension canvasSize = getMinCanvasSize(); +// BufferedImage canvasImage = new BufferedImage(Math.abs(canvasSize.width), Math.abs(canvasSize.height), BufferedImage.TYPE_INT_RGB); +// Graphics2D g2d = canvasImage.createGraphics(); +// +// g2d.setBackground(Color.white); +// g2d.clearRect(0, 0, canvasSize.width, canvasSize.height); +// +// for (Tile tile : tiles) { +//// tile.setDrawOutline(showCenter); +// +// //tile.drawTile(g2d, true); +// +// if (showCenter) { +// tile.drawCenterPoint(g2d, Color.red); +// } +// } +// g2d.dispose(); +// +// return canvasImage; +// } // @Override // protected void paintComponent(Graphics g) { // Graphics2D g2d = (Graphics2D) g; @@ -175,23 +212,28 @@ private BufferedImage paintTiles() { // int x = cx - (bw / 2); // int y = cy - (bh / 2); // g2d.drawImage(canvasImage, null, x, y); +// } +// @Override +// public void propertyChange(PropertyChangeEvent evt) { +// if ("repaintTile".equals(evt.getPropertyName())) { +// Tile tile = (Tile) evt.getNewValue(); +// this.repaint(tile.getBounds()); +// } +// } +// @Override +// public Dimension getPreferredSize() { +// if (!tiles.isEmpty()) { +// return getMinCanvasSize(); +// } else { +// return this.getSize(); +// } // } - @Override - public void propertyChange(PropertyChangeEvent evt) { - if ("repaintTile".equals(evt.getPropertyName())) { - Tile tile = (Tile) evt.getNewValue(); - this.repaint(tile.getBounds()); - } + public boolean isExpanded() { + return expanded; } - @Override - public Dimension getPreferredSize() { - if (!tiles.isEmpty()) { - return getMinCanvasSize(); - } else { - return this.getSize(); - } + public void setExpanded(boolean expanded) { + this.expanded = expanded; } - } diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.form b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.form index 2f7f61a7..144e15cd 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.form +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.form @@ -52,6 +52,14 @@ + + + + + + + + @@ -73,6 +81,22 @@ + + + + + + + + + + + + + + + + @@ -98,22 +122,6 @@ - - - - - - - - - - - - - - - - @@ -122,14 +130,6 @@ - - - - - - - - @@ -182,7 +182,7 @@ - + @@ -196,7 +196,7 @@ - + @@ -204,7 +204,7 @@ - + diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.java b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.java index 6e37aad9..5ea0df8e 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.java +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.java @@ -16,14 +16,14 @@ package jcs.ui.layout.tiles; import java.awt.Dimension; -import java.awt.Graphics2D; import java.awt.Image; import java.awt.Point; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; +import java.awt.image.BufferedImage; import java.io.File; import javax.swing.ComboBoxModel; import javax.swing.DefaultComboBoxModel; +import javax.swing.ImageIcon; +import javax.swing.JFrame; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import jcs.entities.BlockBean; @@ -38,7 +38,7 @@ * * @author FJA */ -public class UnscaledBlockTileFrame extends javax.swing.JFrame implements PropertyChangeListener { +public class UnscaledBlockTileFrame extends JFrame { //implements PropertyChangeListener { private Tile blockTile; @@ -51,8 +51,8 @@ public UnscaledBlockTileFrame() { this.departureSideCB.setSelectedItem(""); this.stateCB.setModel(createStateComboBoxModel()); - initTile(); - + initBlock(); + setVisible(true); } @@ -82,8 +82,8 @@ private LocomotiveBean createLocomotiveBean() { LocomotiveBean lb = new LocomotiveBean(8L, "NS DHG 6505", 8L, 8, "", "dcc", 100, 0, 0, 1, true, true); String imgPath = System.getProperty("user.home") + File.separator + "jcs" + File.separator + "images" + File.separator + "DHG 6505.png"; lb.setIcon(imgPath); - Image locImage = ImageUtil.readImage(imgPath); - //Image is sized by default so + ImageIcon locIcon = new ImageIcon(getClass().getResource("/images/DHG 6505.png")); + Image locImage = new BufferedImage(locIcon.getIconWidth(), locIcon.getIconHeight(), BufferedImage.TYPE_INT_RGB); locImage = ImageUtil.scaleImage(locImage, 100); lb.setLocIcon(locImage); @@ -96,37 +96,36 @@ private LocomotiveBean createLocomotiveBean() { return lb; } - private void initTile() { - Dimension vps = this.blockTileCanvas.getPreferredSize(); + private void initBlock() { + Dimension vps = this.canvas.getPreferredSize(); + Logger.trace("Canvas size w: " + canvas.getWidth() + " h: " + canvas.getHeight()); blockTile = new Block(TileBean.Orientation.EAST, vps.width / 2, vps.height / 2); + blockTile.setId("bk-1"); - BlockBean bbe = new BlockBean(); - bbe.setId(blockTile.getId()); - bbe.setTileId(blockTile.getId()); - bbe.setDescription("Blok"); + BlockBean blockBean = new BlockBean(); + blockBean.setId(blockTile.getId()); + blockBean.setTileId(blockTile.getId()); + blockBean.setDescription("Blok 1"); //bbe.setArrivalSuffix((String) this.incomingSideCB.getSelectedItem()); - bbe.setDepartureSuffix(null); + blockBean.setDepartureSuffix(null); - bbe.setBlockState((BlockState) this.stateCB.getSelectedItem()); - bbe.setReverseArrival(this.reverseArrivalCB.isSelected()); + blockBean.setBlockState((BlockState) this.stateCB.getSelectedItem()); + blockBean.setReverseArrival(this.reverseArrivalCB.isSelected()); if (this.showLocCB.isSelected()) { - bbe.setLocomotive(createLocomotiveBean()); + blockBean.setLocomotive(createLocomotiveBean()); } else { - bbe.setLocomotive(null); + blockBean.setLocomotive(null); } - ((Block) blockTile).setBlockBean(bbe); + blockTile.setBlockBean(blockBean); - if (this.scaleCB.isSelected()) { - blockTile.setScaleImage(false); - } else { - blockTile.setScaleImage(true); - } + blockTile.setScaleImage(!scaleCB.isSelected()); + canvas.setExpanded(scaleCB.isSelected()); - blockTileCanvas.addTile(blockTile); + canvas.add(blockTile); centerSP.getViewport().validate(); } @@ -148,7 +147,7 @@ private void changeOrientation() { // } // // blockTile.drawTile((Graphics2D) getGraphics(), this.showCenterCB.isSelected()); - Dimension vps = this.blockTileCanvas.getPreferredSize(); + Dimension vps = this.canvas.getPreferredSize(); Point cc = new Point(Math.abs(vps.width / 2), Math.abs(vps.height / 2)); blockTile.setCenter(cc); @@ -167,19 +166,19 @@ private void initComponents() { locDirectionBG = new javax.swing.ButtonGroup(); nPanel = new javax.swing.JPanel(); scaleCB = new javax.swing.JCheckBox(); + rotateButton = new javax.swing.JButton(); orientationLabel = new javax.swing.JLabel(); orientationCB = new javax.swing.JComboBox<>(); + stateCB = new javax.swing.JComboBox<>(); incomingSuffix = new javax.swing.JLabel(); departureSideCB = new javax.swing.JComboBox<>(); - stateCB = new javax.swing.JComboBox<>(); reverseArrivalCB = new javax.swing.JCheckBox(); - rotateButton = new javax.swing.JButton(); showLocCB = new javax.swing.JCheckBox(); backwardsRB = new javax.swing.JRadioButton(); forwardsRB = new javax.swing.JRadioButton(); showCenterCB = new javax.swing.JCheckBox(); centerSP = new javax.swing.JScrollPane(); - blockTileCanvas = new jcs.ui.layout.tiles.UnscaledBlockCanvas(); + canvas = new jcs.ui.layout.tiles.UnscaledBlockCanvas(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); setPreferredSize(new java.awt.Dimension(1250, 500)); @@ -194,6 +193,14 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { }); nPanel.add(scaleCB); + rotateButton.setText("Rotate"); + rotateButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + rotateButtonActionPerformed(evt); + } + }); + nPanel.add(rotateButton); + orientationLabel.setText("Orientation"); nPanel.add(orientationLabel); @@ -205,6 +212,14 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { }); nPanel.add(orientationCB); + stateCB.setPreferredSize(new java.awt.Dimension(150, 22)); + stateCB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + stateCBActionPerformed(evt); + } + }); + nPanel.add(stateCB); + incomingSuffix.setText("Departure Suffix"); nPanel.add(incomingSuffix); @@ -217,14 +232,6 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { }); nPanel.add(departureSideCB); - stateCB.setPreferredSize(new java.awt.Dimension(150, 22)); - stateCB.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - stateCBActionPerformed(evt); - } - }); - nPanel.add(stateCB); - reverseArrivalCB.setText("Reverse Arrival Side"); reverseArrivalCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -233,14 +240,6 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { }); nPanel.add(reverseArrivalCB); - rotateButton.setText("Rotate"); - rotateButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - rotateButtonActionPerformed(evt); - } - }); - nPanel.add(rotateButton); - showLocCB.setLabel("Show Locomotive"); showLocCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -282,33 +281,33 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { centerSP.setDoubleBuffered(true); centerSP.setMinimumSize(new java.awt.Dimension(1250, 440)); centerSP.setPreferredSize(new java.awt.Dimension(1250, 440)); - centerSP.setViewportView(blockTileCanvas); + centerSP.setViewportView(canvas); centerSP.addComponentListener(new java.awt.event.ComponentAdapter() { public void componentResized(java.awt.event.ComponentEvent evt) { centerSPComponentResized(evt); } }); - blockTileCanvas.setAutoscrolls(true); - blockTileCanvas.setPreferredSize(null); - blockTileCanvas.addComponentListener(new java.awt.event.ComponentAdapter() { + canvas.setAutoscrolls(true); + canvas.setPreferredSize(null); + canvas.addComponentListener(new java.awt.event.ComponentAdapter() { public void componentResized(java.awt.event.ComponentEvent evt) { - blockTileCanvasComponentResized(evt); + canvasComponentResized(evt); } }); - javax.swing.GroupLayout blockTileCanvasLayout = new javax.swing.GroupLayout(blockTileCanvas); - blockTileCanvas.setLayout(blockTileCanvasLayout); - blockTileCanvasLayout.setHorizontalGroup( - blockTileCanvasLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + javax.swing.GroupLayout canvasLayout = new javax.swing.GroupLayout(canvas); + canvas.setLayout(canvasLayout); + canvasLayout.setHorizontalGroup( + canvasLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGap(0, 1248, Short.MAX_VALUE) ); - blockTileCanvasLayout.setVerticalGroup( - blockTileCanvasLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + canvasLayout.setVerticalGroup( + canvasLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGap(0, 498, Short.MAX_VALUE) ); - centerSP.setViewportView(blockTileCanvas); + centerSP.setViewportView(canvas); getContentPane().add(centerSP, java.awt.BorderLayout.CENTER); @@ -411,7 +410,7 @@ private void centerSPComponentResized(java.awt.event.ComponentEvent evt) {//GEN- //wordt bij init aangeroepen }//GEN-LAST:event_centerSPComponentResized - private void blockTileCanvasComponentResized(java.awt.event.ComponentEvent evt) {//GEN-FIRST:event_blockTileCanvasComponentResized + private void canvasComponentResized(java.awt.event.ComponentEvent evt) {//GEN-FIRST:event_canvasComponentResized //Logger.trace(evt); //this.centerSP.setLocation(0, 0); //this.centerSP.getViewport().revalidate(); @@ -437,8 +436,9 @@ private void blockTileCanvasComponentResized(java.awt.event.ComponentEvent evt) //JViewport vp = scrollpane.getViewport(); //vp.setViewSize(newsize); // revalidate(); +//jcs.ui.layout.tiles.UnscaledBlockTileFrame.GridCanvas - }//GEN-LAST:event_blockTileCanvasComponentResized + }//GEN-LAST:event_canvasComponentResized /** * @param args the command line arguments @@ -456,23 +456,22 @@ public static void main(String args[]) { app.setTitle("Unscaled Tile Tester"); app.pack(); app.setLocationRelativeTo(null); - //app.setVisible(true); - }); - } - @Override - public void propertyChange(PropertyChangeEvent evt) { - if ("repaintTile".equals(evt.getPropertyName())) { - Tile t = (Tile) evt.getNewValue(); - Logger.trace("Tile: " + t); - this.repaint(); - } + }); } +// @Override +// public void propertyChange(PropertyChangeEvent evt) { +// if ("repaintTile".equals(evt.getPropertyName())) { +// Tile t = (Tile) evt.getNewValue(); +// Logger.trace("Tile: " + t); +// this.repaint(); +// } +// } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JRadioButton backwardsRB; - private jcs.ui.layout.tiles.UnscaledBlockCanvas blockTileCanvas; + private jcs.ui.layout.tiles.UnscaledBlockCanvas canvas; private javax.swing.JScrollPane centerSP; private javax.swing.JComboBox departureSideCB; private javax.swing.JRadioButton forwardsRB; From fe9aa690ef917c97c6a212db26b8afc115a93b1b Mon Sep 17 00:00:00 2001 From: Frans Jacobs <41232225+fransjacobs@users.noreply.github.com> Date: Mon, 20 Jan 2025 20:13:41 +0100 Subject: [PATCH 03/70] Fix rotating of Block --- src/main/java/jcs/ui/layout/tiles/Block.java | 111 ++++++++++-------- src/main/java/jcs/ui/layout/tiles/Tile.java | 35 +++--- .../ui/layout/tiles/UnscaledBlockCanvas.java | 4 +- ...ileFrame.form => UnscaledBlockTester.form} | 3 - ...ileFrame.java => UnscaledBlockTester.java} | 81 +++++-------- 5 files changed, 117 insertions(+), 117 deletions(-) rename src/test/java/jcs/ui/layout/tiles/{UnscaledBlockTileFrame.form => UnscaledBlockTester.form} (98%) rename src/test/java/jcs/ui/layout/tiles/{UnscaledBlockTileFrame.java => UnscaledBlockTester.java} (88%) diff --git a/src/main/java/jcs/ui/layout/tiles/Block.java b/src/main/java/jcs/ui/layout/tiles/Block.java index 780c3907..ea23a0c8 100755 --- a/src/main/java/jcs/ui/layout/tiles/Block.java +++ b/src/main/java/jcs/ui/layout/tiles/Block.java @@ -72,14 +72,7 @@ private static int blockHeight(Orientation orientation) { public Block(TileBean tileBean) { super(tileBean, blockWidth(tileBean.getOrientation()), blockHeight(tileBean.getOrientation())); setModel(new DefaultTileModel()); - - if (Orientation.EAST == tileBean.getOrientation() || Orientation.WEST == tileBean.getOrientation()) { - this.renderWidth = RENDER_WIDTH * 3; - this.renderHeight = RENDER_HEIGHT; - } else { - this.renderWidth = RENDER_WIDTH; - this.renderHeight = RENDER_HEIGHT * 3; - } + changeRenderSize(); } public Block(Orientation orientation, Point center) { @@ -93,8 +86,11 @@ public Block(Orientation orientation, int x, int y) { public Block(Orientation orientation, int x, int y, int width, int height) { super(TileType.BLOCK, orientation, x, y, width, height); setModel(new DefaultTileModel()); + changeRenderSize(); + } - if (Orientation.EAST == orientation || Orientation.WEST == orientation) { + private void changeRenderSize() { + if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { this.renderWidth = RENDER_WIDTH * 3; this.renderHeight = RENDER_HEIGHT; } else { @@ -312,28 +308,28 @@ public String getIdSuffix(Tile other) { } if (match != null) { - if (Orientation.EAST == getOrientation() && Orientation.EAST == match) { + if (Orientation.EAST == tileOrientation && Orientation.EAST == match) { suffix = "+"; } - if (Orientation.WEST == getOrientation() && Orientation.WEST == match) { + if (Orientation.WEST == tileOrientation && Orientation.WEST == match) { suffix = "+"; } - if (Orientation.EAST == getOrientation() && Orientation.WEST == match) { + if (Orientation.EAST == tileOrientation && Orientation.WEST == match) { suffix = "-"; } - if (Orientation.WEST == getOrientation() && Orientation.EAST == match) { + if (Orientation.WEST == tileOrientation && Orientation.EAST == match) { suffix = "-"; } - if (Orientation.NORTH == getOrientation() && Orientation.NORTH == match) { + if (Orientation.NORTH == tileOrientation && Orientation.NORTH == match) { suffix = "+"; } - if (Orientation.NORTH == getOrientation() && Orientation.SOUTH == match) { + if (Orientation.NORTH == tileOrientation && Orientation.SOUTH == match) { suffix = "-"; } - if (Orientation.SOUTH == getOrientation() && Orientation.SOUTH == match) { + if (Orientation.SOUTH == tileOrientation && Orientation.SOUTH == match) { suffix = "+"; } - if (Orientation.SOUTH == getOrientation() && Orientation.NORTH == match) { + if (Orientation.SOUTH == tileOrientation && Orientation.NORTH == match) { suffix = "-"; } } @@ -341,26 +337,24 @@ public String getIdSuffix(Tile other) { } @Override - public void rotate() { - super.rotate(); - Dimension d; - if (Orientation.EAST.equals(getOrientation()) || Orientation.WEST.equals(getOrientation())) { - d = new Dimension(DEFAULT_WIDTH * 3, DEFAULT_HEIGHT); - //this.width = DEFAULT_WIDTH * 3; - //this.height = DEFAULT_HEIGHT; + public Orientation rotate() { + rotate(false); + int w = blockWidth(tileOrientation); + int h = blockHeight(tileOrientation); - this.renderWidth = RENDER_WIDTH * 3; - this.renderHeight = RENDER_HEIGHT; - } else { - d = new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT * 3); - //this.width = DEFAULT_WIDTH; - //this.height = DEFAULT_HEIGHT * 3; + Dimension d = new Dimension(w, h); - this.renderWidth = RENDER_WIDTH; - this.renderHeight = RENDER_HEIGHT * 3; - } - setSize(d); +// if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { +// d = new Dimension(w, h); +// } else { +// d = new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT * 3); +// } setPreferredSize(d); + setSize(d); + changeRenderSize(); + + repaint(); + return tileOrientation; } /** @@ -455,7 +449,7 @@ public void renderTile(Graphics2D g2) { g2.setStroke(new BasicStroke(20, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); g2.setPaint(Color.darkGray); - g2.drawLine(rw + 20, yy - 0, rw + 20, yy + 300); + g2.drawLine(rw + GRID, yy - 0, rw + GRID, yy + 300); //When there is a locomotive in the block mark the direction of travel. //The default, forwards is in the direction of the block orientation, i.e. the + @@ -571,8 +565,7 @@ private void renderRightArrow(Graphics2D g2) { } @Override - public void renderTileRoute(Graphics2D g2d - ) { + public void renderTileRoute(Graphics2D g2d) { if (routeBlockState != null) { backgroundColor = getBlockStateColor(routeBlockState); } @@ -599,7 +592,7 @@ protected void overlayLocImage(Graphics2D g2d) { //Logger.trace("LocImage w: " + w + " h: " + h); //Depending on the block orientation the image needs to be rotated and flipped //Incase the departure suffix is NOT set center the locomotive image - switch (getOrientation()) { + switch (tileOrientation) { case WEST -> { int xx; int w = locImage.getWidth(null); @@ -817,20 +810,46 @@ protected void paintComponent(Graphics g) { long started = System.currentTimeMillis(); super.paintComponent(g); + int w = getWidth(); + int h = getHeight(); + //upon firts initializatien the width and height could still be wrong for reasons unknow to me... + //reset widh or height + boolean reset = false; + if (w != blockWidth(tileOrientation)) { + w = blockWidth(tileOrientation); + reset = true; + } + if (h != blockHeight(tileOrientation)) { + h = blockHeight(tileOrientation); + reset = true; + } + + if (reset) { + Logger.trace(id + " Resetting size... "); + Dimension d = new Dimension(w, h); + setPreferredSize(d); + setSize(d); + } + + int xx, yy; if (tileOrientation == Orientation.EAST || tileOrientation == Orientation.WEST) { - setBounds(this.tileX - GRID - GRID * 2, this.tileY - GRID, this.getWidth(), this.getHeight()); + xx = tileX - GRID - GRID * 2; + yy = tileY - GRID; + setBounds(xx, yy, w, h); } else { - setBounds(this.tileX - GRID, this.tileY - GRID - GRID * 2, this.getWidth(), this.getHeight()); + xx = tileX - GRID; + yy = tileY - GRID - GRID * 2; + setBounds(xx, yy, w, h); } + Logger.trace(id + ": " + tileOrientation + " W: " + getWidth() + " H: " + getHeight() + " tX: " + tileX + ", tY: " + tileY + " xx: " + xx + " yy: " + yy); + Graphics2D g2 = (Graphics2D) g.create(); drawTile(g2); g2.dispose(); g.drawImage(tileImage, 0, 0, null); - Logger.trace(id + ": W: " + getWidth() + " H: " + getHeight() + " oX: " + renderOffsetX + " oY: " + renderOffsetY); - long now = System.currentTimeMillis(); Logger.trace(id + " Duration: " + (now - started) + " ms."); } @@ -853,15 +872,15 @@ protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { dY3 = (renderHeight / 2 - size / 2 / 2); } else { dY1 = (renderWidth / 2 - size / 2 / 2); - + dY2 = (renderWidth / 2 - size / 2 / 2); - + dY3 = (renderWidth / 2 - size / 2 / 2); dX1 = (renderHeight / 3 / 2 - size / 2 / 2); - + dX2 = (renderHeight / 2 - size / 2); - + dX3 = (renderHeight / 3 / 2 + renderHeight / 3 * 2 - size / 2); } diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java index 5274714b..b1794914 100755 --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -167,18 +167,18 @@ protected Tile(TileType tileType, Orientation orientation, Direction direction, } protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height, Color backgroundColor, Color selectedColor) { - this.setLayout(null); this.tileType = tileType; - this.tileOrientation = orientation; this.tileDirection = direction; - this.tileX = x; this.tileY = y; Dimension d = new Dimension(width, height); - this.setSize(d); - this.setPreferredSize(d); + super.setPreferredSize(d); + super.setSize(d); + + int w = getWidth(); + int h = getHeight(); this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT; @@ -193,6 +193,7 @@ protected Tile(TileType tileType, Orientation orientation, Direction direction, if (this.selectedColor == null) { this.selectedColor = DEFAULT_SELECTED_COLOR; } + this.setLayout(null); } protected Tile(Object tileBean) { @@ -531,9 +532,8 @@ public int getRenderHeight() { //@Override public void drawTile(Graphics2D g2d) { // by default and image is rendered in the EAST orientation - Orientation o = getOrientation(); - if (o == null) { - o = Orientation.EAST; + if (tileOrientation == null) { + tileOrientation = Orientation.EAST; } tileImage = createImage(); @@ -554,7 +554,7 @@ public void drawTile(Graphics2D g2d) { int ox = 0, oy = 0; AffineTransform trans = new AffineTransform(); - switch (o) { + switch (tileOrientation) { case SOUTH -> { trans.rotate(Math.PI / 2, renderWidth / 2, renderHeight / 2); ox = (renderHeight - renderWidth) / 2; @@ -590,7 +590,7 @@ public void drawTile(Graphics2D g2d) { } // Scale the image back... - if (this.model.isScaleImage()) { + if (model.isScaleImage()) { tileImage = Scalr.resize(tileImage, Method.AUTOMATIC, Mode.FIT_EXACT, getWidth(), getHeight(), Scalr.OP_ANTIALIAS); } @@ -637,17 +637,21 @@ protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { /** * Rotate the tile clockwise 90 deg + * + * @return */ - public void rotate() { - rotate(true); + public Orientation rotate() { + return rotate(true); } /** * Rotate the tile clockwise 90 deg + * + * @param repaint + * @return */ - void rotate(boolean repaint) { - - switch (getOrientation()) { + protected Orientation rotate(boolean repaint) { + switch (tileOrientation) { case EAST -> setOrientation(Orientation.SOUTH); case SOUTH -> @@ -660,6 +664,7 @@ void rotate(boolean repaint) { if (repaint) { repaint(); } + return tileOrientation; } public void flipHorizontal() { diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java index 39eb21b4..4dce3bf3 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java @@ -28,8 +28,8 @@ public class UnscaledBlockCanvas extends JPanel { //implements PropertyChangeLis public UnscaledBlockCanvas() { setLayout(null); - setOpaque(true); - setDoubleBuffered(false); + setOpaque(false); + setDoubleBuffered(true); } @Override diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.form b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.form similarity index 98% rename from src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.form rename to src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.form index 144e15cd..098f9189 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.form +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.form @@ -199,9 +199,6 @@ - - - diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.java b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.java similarity index 88% rename from src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.java rename to src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.java index 5ea0df8e..10444f86 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.java +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.java @@ -29,8 +29,8 @@ import jcs.entities.BlockBean; import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; -import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; +import jcs.ui.layout.LayoutUtil; import jcs.ui.util.ImageUtil; import org.tinylog.Logger; @@ -38,20 +38,24 @@ * * @author FJA */ -public class UnscaledBlockTileFrame extends JFrame { //implements PropertyChangeListener { +public class UnscaledBlockTester extends JFrame { //implements PropertyChangeListener { private Tile blockTile; /** * Creates new form UnscaledBlockTileFrame */ - public UnscaledBlockTileFrame() { + public UnscaledBlockTester() { initComponents(); + this.orientationCB.setModel(createOrientationComboBoxModel()); this.departureSideCB.setSelectedItem(""); this.stateCB.setModel(createStateComboBoxModel()); - initBlock(); + this.blockTile = initBlock(); + + canvas.add(blockTile); + centerSP.getViewport().validate(); setVisible(true); } @@ -96,64 +100,43 @@ private LocomotiveBean createLocomotiveBean() { return lb; } - private void initBlock() { - Dimension vps = this.canvas.getPreferredSize(); - Logger.trace("Canvas size w: " + canvas.getWidth() + " h: " + canvas.getHeight()); - blockTile = new Block(TileBean.Orientation.EAST, vps.width / 2, vps.height / 2); + private Block initBlock() { + Point center = LayoutUtil.snapToGrid(canvas.getWidth() / 2, canvas.getHeight() / 2); + int cX = center.x; + int cY = center.y; + + Logger.trace("Center X: " + cX + " Y: " + cY); - blockTile.setId("bk-1"); + Block block = new Block(Orientation.EAST, cX, cY); + block.setId("bk-1"); + block.setScaleImage(!scaleCB.isSelected()); + canvas.setExpanded(scaleCB.isSelected()); BlockBean blockBean = new BlockBean(); - blockBean.setId(blockTile.getId()); - blockBean.setTileId(blockTile.getId()); + blockBean.setId(block.getId()); + blockBean.setTileId(block.getId()); blockBean.setDescription("Blok 1"); //bbe.setArrivalSuffix((String) this.incomingSideCB.getSelectedItem()); blockBean.setDepartureSuffix(null); - blockBean.setBlockState((BlockState) this.stateCB.getSelectedItem()); - blockBean.setReverseArrival(this.reverseArrivalCB.isSelected()); + blockBean.setBlockState((BlockState) stateCB.getSelectedItem()); + blockBean.setReverseArrival(reverseArrivalCB.isSelected()); - if (this.showLocCB.isSelected()) { + if (showLocCB.isSelected()) { blockBean.setLocomotive(createLocomotiveBean()); } else { blockBean.setLocomotive(null); } - blockTile.setBlockBean(blockBean); - - blockTile.setScaleImage(!scaleCB.isSelected()); - canvas.setExpanded(scaleCB.isSelected()); + block.setBlockBean(blockBean); - canvas.add(blockTile); - centerSP.getViewport().validate(); + return block; } private void changeOrientation() { Orientation orientation = (Orientation) this.orientationCB.getSelectedItem(); blockTile.setOrientation(orientation); -// if (Orientation.EAST.equals(blockTile.getOrientation()) || Orientation.WEST.equals(blockTile.getOrientation())) { -// ((Block) blockTile).setWidth(Tile.DEFAULT_WIDTH * 3); -// ((Block) blockTile).setHeight(Tile.DEFAULT_HEIGHT); -// -// ((Block) blockTile).setRenderWidth(Tile.RENDER_WIDTH * 3); -// ((Block) blockTile).setRenderHeight(Tile.RENDER_HEIGHT); -// } else { -// ((Block) blockTile).setWidth(Tile.DEFAULT_WIDTH); -// ((Block) blockTile).setHeight(Tile.DEFAULT_HEIGHT * 3); -// -// ((Block) blockTile).setRenderWidth(Tile.RENDER_WIDTH); -// ((Block) blockTile).setRenderHeight(Tile.RENDER_HEIGHT * 3); -// } -// -// blockTile.drawTile((Graphics2D) getGraphics(), this.showCenterCB.isSelected()); - Dimension vps = this.canvas.getPreferredSize(); - - Point cc = new Point(Math.abs(vps.width / 2), Math.abs(vps.height / 2)); - blockTile.setCenter(cc); - - this.centerSP.getViewport().revalidate(); - repaint(); } /** @@ -289,7 +272,6 @@ public void componentResized(java.awt.event.ComponentEvent evt) { }); canvas.setAutoscrolls(true); - canvas.setPreferredSize(null); canvas.addComponentListener(new java.awt.event.ComponentAdapter() { public void componentResized(java.awt.event.ComponentEvent evt) { canvasComponentResized(evt); @@ -315,12 +297,9 @@ public void componentResized(java.awt.event.ComponentEvent evt) { }// //GEN-END:initComponents private void rotateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rotateButtonActionPerformed - this.blockTile.rotate(); - - Orientation orientation = blockTile.getOrientation(); + Orientation orientation = blockTile.rotate(); this.orientationCB.setSelectedItem(orientation); - Logger.trace("Blok is rotated to " + blockTile.getOrientation()); - repaint(); + Logger.trace("Blok is rotated to " + orientation); }//GEN-LAST:event_rotateButtonActionPerformed private void showLocCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showLocCBActionPerformed @@ -436,7 +415,7 @@ private void canvasComponentResized(java.awt.event.ComponentEvent evt) {//GEN-FI //JViewport vp = scrollpane.getViewport(); //vp.setViewSize(newsize); // revalidate(); -//jcs.ui.layout.tiles.UnscaledBlockTileFrame.GridCanvas +//jcs.ui.layout.tiles.UnscaledBlockTester.GridCanvas }//GEN-LAST:event_canvasComponentResized @@ -452,10 +431,10 @@ public static void main(String args[]) { /* Create and display the form */ java.awt.EventQueue.invokeLater(() -> { - UnscaledBlockTileFrame app = new UnscaledBlockTileFrame(); + UnscaledBlockTester app = new UnscaledBlockTester(); app.setTitle("Unscaled Tile Tester"); - app.pack(); app.setLocationRelativeTo(null); + app.pack(); }); } From 8db4c879cf198cbeae45f6f9fdb8955943def7fb Mon Sep 17 00:00:00 2001 From: Frans Jacobs <41232225+fransjacobs@users.noreply.github.com> Date: Wed, 22 Jan 2025 20:10:03 +0100 Subject: [PATCH 04/70] More refactoring for Block --- src/main/java/jcs/ui/layout/LayoutUtil.java | 492 +--------------- src/main/java/jcs/ui/layout/tiles/Block.java | 153 ++--- src/main/java/jcs/ui/layout/tiles/Cross.java | 10 +- .../jcs/ui/layout/tiles/DefaultTileModel.java | 80 +++ src/main/java/jcs/ui/layout/tiles/Tile.java | 534 ++++++++++-------- .../java/jcs/ui/layout/tiles/TileModel.java | 28 +- src/test/java/jcs/ui/layout/TileTest.java | 32 +- .../jcs/ui/layout/tiles/DotGridCanvas.java | 4 - .../ui/layout/tiles/UnscaledBlockCanvas.java | 14 +- .../ui/layout/tiles/UnscaledBlockTester.form | 5 +- .../ui/layout/tiles/UnscaledBlockTester.java | 118 ++-- 11 files changed, 522 insertions(+), 948 deletions(-) diff --git a/src/main/java/jcs/ui/layout/LayoutUtil.java b/src/main/java/jcs/ui/layout/LayoutUtil.java index d8525e07..a1e723a2 100644 --- a/src/main/java/jcs/ui/layout/LayoutUtil.java +++ b/src/main/java/jcs/ui/layout/LayoutUtil.java @@ -17,17 +17,14 @@ import jcs.ui.layout.tiles.Tile; import java.awt.Point; +import jcs.entities.TileBean.Orientation; +import static jcs.ui.layout.tiles.Block.BLOCK_HEIGHT; +import static jcs.ui.layout.tiles.Block.BLOCK_WIDTH; +import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; +import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; -/** - * - * @author frans - */ public class LayoutUtil { -// private final static Map tiles = new HashMap<>(); -// private final static Map altTilesLookup = new HashMap<>(); -// private final static Map tileLookup = new HashMap<>(); - private LayoutUtil() { } @@ -66,159 +63,6 @@ public static int getGridY(int y) { return (sy - Tile.GRID) / (Tile.GRID * 2); } -// private static void addRelatedBeans(TileBean tileBean) { -// TileType tileType = tileBean.getTileType(); -// switch (tileType) { -// case STRAIGHT -> { -// } -// case STRAIGHT_DIR -> { -// } -// case END -> { -// } -// case CURVED -> { -// } -// case SWITCH -> { -// if (tileBean.getAccessoryBean() != null) { -// tileBean.setAccessoryBean(PersistenceFactory.getService().getAccessoryById(tileBean.getAccessoryId())); -// } -// } -// case CROSS -> { -// if (tileBean.getAccessoryBean() != null) { -// tileBean.setAccessoryBean(PersistenceFactory.getService().getAccessoryById(tileBean.getAccessoryId())); -// } -// } -// case SIGNAL -> { -// if (tileBean.getAccessoryBean() != null) { -// tileBean.setAccessoryBean(PersistenceFactory.getService().getAccessoryById(tileBean.getAccessoryId())); -// } -// } -// case SENSOR -> { -// if (tileBean.getSensorId() != null) { -// tileBean.setSensorBean(PersistenceFactory.getService().getSensor(tileBean.getSensorId())); -// } -// } -// case BLOCK -> { -// } -// default -> -// Logger.warn("Unknown Tile Type " + tileType); -// } -// } - -// public static final Map loadLayout(boolean drawGridLines, boolean showValues) { -// return loadLayout(drawGridLines, null, showValues); -// } - - /** - * Load Tiles from the persistent store - * - * @param drawGridLines - * @param listener - * @param showValues - * @return A Map of tiles, key is the center point of the tile - */ -// public static final Map loadLayout(boolean drawGridLines, PropertyChangeListener listener, boolean showValues) { -// //synchronized (LayoutUtil.tiles) { -// LayoutUtil.tiles.clear(); -// LayoutUtil.altTilesLookup.clear(); -// LayoutUtil.tileLookup.clear(); -// -// if (PersistenceFactory.getService() != null) { -// List tbl = PersistenceFactory.getService().getTiles(); -// -// Set beans = new HashSet<>(tbl); -// -// for (TileBean tb : beans) { -// addRelatedBeans(tb); -// Tile tile = TileFactory.createTile(tb, drawGridLines, showValues); -// -// if (listener != null) { -// tile.setPropertyChangeListener(listener); -// } -// -// registerAsEventListener(tile); -// -// LayoutUtil.tiles.put(tile.getCenter(), tile); -// for (Point ap : tile.getAltPoints()) { -// LayoutUtil.altTilesLookup.put(ap, tile); -// } -// -// LayoutUtil.tileLookup.put(tile.getId(), tile); -// } -// -// Logger.debug("Loaded " + tiles.size() + " Tiles..."); -// } else { -// Logger.error("Can't load tiles, no PersistenceService available"); -// } -// //} -// return LayoutUtil.tiles; -// } - -// private static void registerAsEventListener(Tile tile) { -// -//// switch (tile.getTileType()) { -//// case SENSOR: -//// TrackServiceFactory.getTrackService().addSensorListener((SensorListener) tile); -//// break; -//// case SWITCH: -//// TrackServiceFactory.getTrackService().addAccessoryListener((AccessoryListener) tile); -//// break; -//// case SIGNAL: -//// TrackServiceFactory.getTrackService().addAccessoryListener((AccessoryListener) tile); -//// break; -//// -//// default: -//// //Do nothing -//// break; -//// } -// } - -// private static boolean isNotLoaded() { -// return LayoutUtil.tiles == null || LayoutUtil.tiles.isEmpty(); -// } - -// public static Tile findTile(Point cp) { -// if (LayoutUtil.tiles == null || LayoutUtil.tiles.isEmpty()) { -// LayoutUtil.loadLayout(true, false); -// } -// Tile result = LayoutUtil.tiles.get(cp); -// -// if (result == null) { -// result = LayoutUtil.altTilesLookup.get(cp); -// if (result != null) { -// } -// } -// return result; -// } - -// public static boolean isTile(Point cp) { -// return findTile(cp) != null; -// } - -// public static boolean isBlock(Point cp) { -// Tile t = findTile(cp); -// if (t == null) { -// return false; -// } -// return TileType.BLOCK.equals(t.getTileType()); -// } - -// public static boolean isTrack(Point cp) { -// Tile t = findTile(cp); -// if (t == null) { -// return false; -// } -// TileType tt = t.getTileType(); -// return TileType.CURVED.equals(tt) || TileType.CURVED.equals(tt) || TileType.SENSOR.equals(tt) || TileType.SIGNAL.equals(tt) || TileType.STRAIGHT.equals(tt); -// } - -// public static final Map getTiles() { -// if (LayoutUtil.tiles == null || LayoutUtil.tiles.isEmpty()) { -// LayoutUtil.loadLayout(true, false); -// } -// -// return LayoutUtil.tiles; -// } - /** * Returns the euclidean distance of 2 Points * @@ -233,314 +77,20 @@ public static double euclideanDistance(Point p1, Point p2) { return d; } -// public static Set adjacentPointsFor(Tile tile) { -// return adjacentPointsFor(tile, AccessoryValue.OFF); -// } -// public static Set adjacentPointsFor(Tile tile, AccessoryValue accessoryValue) { -// Set adjacent = new HashSet<>(); -// int x = tile.getCenterX(); -// int y = tile.getCenterY(); -// int w = tile.getWidth(); -// int h = tile.getHeight(); -// Orientation orientation = tile.getOrientation(); -// Direction direction = tile.getDirection(); -// -// int oX = w / 2 + Tile.GRID; -// int oY = h / 2 + Tile.GRID; -// -// switch (tile.getTileType()) { -// case CURVED -> { -// switch (orientation) { -// case SOUTH -> { -// adjacent.add(new Point(x - oX, y)); -// adjacent.add(new Point(x, y + oY)); -// } -// case WEST -> { -// adjacent.add(new Point(x - oX, y)); -// adjacent.add(new Point(x, y - oY)); -// } -// case NORTH -> { -// adjacent.add(new Point(x + oX, y)); -// adjacent.add(new Point(x, y - oY)); -// } -// default -> { -// //EAST -// adjacent.add(new Point(x + oX, y)); -// adjacent.add(new Point(x, y + oY)); -// } -// } -// } -// case CROSS -> { -// if (Orientation.EAST.equals(orientation) || Orientation.WEST.equals(orientation)) { -// adjacent.add(new Point(x + oX, y)); -// adjacent.add(new Point(x - oX, y)); -// } else { -// adjacent.add(new Point(x, y + oY)); -// adjacent.add(new Point(x, y - oY)); -// } -// } -// case SWITCH -> { -// switch (orientation) { -// case SOUTH: -// switch (accessoryValue) { -// case GREEN: -// adjacent.add(new Point(x, y - oY)); -// break; -// case RED: -// if (Direction.LEFT.equals(direction)) { -// adjacent.add(new Point(x - oX, y)); -// } else { -// adjacent.add(new Point(x + oX, y)); -// } -// break; -// default: -// adjacent.add(new Point(x, y + oY)); -// } -// break; -// case WEST: -// switch (accessoryValue) { -// case GREEN: -// adjacent.add(new Point(x + oX, y)); -// break; -// case RED: -// if (Direction.LEFT.equals(direction)) { -// adjacent.add(new Point(x, y - oY)); -// } else { -// adjacent.add(new Point(x, y + oY)); -// } -// break; -// default: -// adjacent.add(new Point(x - oX, y)); -// break; -// } -// break; -// case NORTH: -// switch (accessoryValue) { -// case GREEN: -// adjacent.add(new Point(x, y + oY)); -// break; -// case RED: -// if (Direction.LEFT.equals(direction)) { -// adjacent.add(new Point(x + oX, y)); -// } else { -// adjacent.add(new Point(x - oX, y)); -// } -// break; -// default: -// adjacent.add(new Point(x, y - oY)); -// break; -// } -// break; -// default: -// //EAST -// switch (accessoryValue) { -// case GREEN: -// adjacent.add(new Point(x - oX, y)); -// break; -// case RED: -// if (Direction.LEFT.equals(direction)) { -// adjacent.add(new Point(x, y + oY)); -// } else { -// adjacent.add(new Point(x, y - oY)); -// } -// break; -// default: -// adjacent.add(new Point(x + oX, y)); -// break; -// } -// break; -// } -// } -// default -> { -// if (Orientation.EAST.equals(orientation) || Orientation.WEST.equals(orientation)) { -// adjacent.add(new Point(x + oX, y)); -// adjacent.add(new Point(x - oX, y)); -// } else { -// adjacent.add(new Point(x, y + oY)); -// adjacent.add(new Point(x, y - oY)); -// } -// } -// } -// return adjacent; -// } -// private static Point getAdjacentPoint(Tile block, String plusMinus) { -// int x = block.getCenterX(); -// int y = block.getCenterY(); -// int w = block.getWidth(); -// int h = block.getHeight(); -// Orientation o = block.getOrientation(); -// -// Point neighborPlus, neighborMin; -// switch (o) { -// case SOUTH: -// neighborPlus = new Point(x, y + h / 3 + Tile.GRID * 2); -// neighborMin = new Point(x, y - h / 3 - Tile.GRID * 2); -// break; -// case WEST: -// neighborPlus = new Point(x - w / 3 - Tile.GRID * 2, y); -// neighborMin = new Point(x + w / 3 + Tile.GRID * 2, y); -// break; -// case NORTH: -// neighborPlus = new Point(x, y - h / 3 - Tile.GRID * 2); -// neighborMin = new Point(x, y + h / 3 + Tile.GRID * 2); -// break; -// default: -// //East -// neighborPlus = new Point(x + w / 3 + Tile.GRID * 2, y); -// neighborMin = new Point(x - w / 3 - Tile.GRID * 2, y); -// break; -// } -// if ("+".equals(plusMinus)) { -// return neighborPlus; -// } else { -// return neighborMin; -// } -// } -// public static boolean isPlusAdjacent(Tile block, Point point) { -// Point p = getAdjacentPoint(block, "+"); -// return p.equals(point); -// } -// public static Point getPlusAdjacent(Tile block) { -// Point p = getAdjacentPoint(block, "+"); -// return p; -// } -// public static Point getMinusAdjacent(Tile block) { -// Point p = getAdjacentPoint(block, "-"); -// return p; -// } -// public static boolean isMinusAdjacent(Tile block, Point point) { -// Point p = getAdjacentPoint(block, "-"); -// return p.equals(point); -// } -// private static Point getPlusMinus(Tile block, String plusMinus) { -// int x = block.getCenterX(); -// int y = block.getCenterY(); -// int w = block.getWidth(); -// int h = block.getHeight(); -// Orientation o = block.getOrientation(); -// -// Point cpPlus, cpMin; -// switch (o) { -// case SOUTH -> { -// cpPlus = new Point(x, y + h / 3); -// cpMin = new Point(x, y - h / 3); -// } -// case WEST -> { -// cpPlus = new Point(x - w / 3, y); -// cpMin = new Point(x + w / 3, y); -// } -// case NORTH -> { -// cpPlus = new Point(x, y - h / 3); -// cpMin = new Point(x, y + h / 3); -// } -// default -> { -// //East -// cpPlus = new Point(x + w / 3, y); -// cpMin = new Point(x - w / 3, y); -// } -// } -// if ("+".equals(plusMinus)) { -// return cpPlus; -// } else { -// return cpMin; -// } -// } - /** - * Obtain the "center" of the plus (+) of a Block Tile - * - * @param block the block - * @return a Point - */ -// public static Point getPlusCenter(Tile block) { -// return getPlusMinus(block, "+"); -// } - /** - * Obtain the "center" of the minus (-) of a Block Tile - * - * @param block the block - * @return a Point - */ -// public static Point getMinusCenter(Tile block) { -// return getPlusMinus(block, "-"); -// } - /** - * The Adjacent Ids depend on the direction of the switch. The common point has 2 Ids one for R and one for G The opposite side has one id for G, the fork side the R - * - * @param tile the "from" - * @param switchTile the "target" - * @return a List with the nodeIds which are adjacent nodes - */ -// public static List getNodeIdsForAdjacentSwitch(Tile tile, Tile switchTile) { -// List nodeIds = new ArrayList<>(); -// Orientation o = switchTile.getOrientation(); -// int tileX = tile.getCenterX(); -// int tileY = tile.getCenterY(); -// int adjX = switchTile.getCenterX(); -// int adjY = switchTile.getCenterY(); -// switch (o) { -// case SOUTH -> { -// if (adjX == tileX && adjY != tileY) { -// //North or South -// if (adjX < tileX) { -// //Common -// nodeIds.add(switchTile.getId()); -// } else { -// //Green -// nodeIds.add(switchTile.getId() + "-G"); -// } -// } else { -// //Red -// nodeIds.add(switchTile.getId() + "-R"); -// } -// } -// case WEST -> { -// //East -// if (adjX != tileX && adjY == tileY) { -// //The common of a East L or R Switch -// if (adjX > tileX) { -// //Common -// nodeIds.add(switchTile.getId()); -// } else { -// //Green -// nodeIds.add(switchTile.getId() + "-G"); -// } -// } else { -// //Red -// nodeIds.add(switchTile.getId() + "-R"); -// } -// } -// case NORTH -> { -// if (adjX == tileX && adjY != tileY) { -// //North or South -// if (adjX > tileX) { -// //Common -// nodeIds.add(switchTile.getId()); -// } else { -// //Green -// nodeIds.add(switchTile.getId() + "-G"); -// } -// } else { -// //Red -// nodeIds.add(switchTile.getId() + "-R"); -// } -// } -// default -> { -// //East -// if (adjX != tileX && adjY == tileY) { -// //The common of a East L or R Switch -// if (adjX < tileX) { -// //Common -// nodeIds.add(switchTile.getId()); -// } else { -// //Green -// nodeIds.add(switchTile.getId() + "-G"); -// } -// } else { -// //Red -// nodeIds.add(switchTile.getId() + "-R"); -// } -// } -// } -// return nodeIds; -// } + public static int blockWidth(Orientation orientation) { + if (Orientation.EAST == orientation || Orientation.WEST == orientation) { + return BLOCK_WIDTH; + } else { + return DEFAULT_WIDTH; + } + } + + public static int blockHeight(Orientation orientation) { + if (Orientation.EAST == orientation || Orientation.WEST == orientation) { + return DEFAULT_HEIGHT; + } else { + return BLOCK_HEIGHT; + } + } + } diff --git a/src/main/java/jcs/ui/layout/tiles/Block.java b/src/main/java/jcs/ui/layout/tiles/Block.java index ea23a0c8..0e315910 100755 --- a/src/main/java/jcs/ui/layout/tiles/Block.java +++ b/src/main/java/jcs/ui/layout/tiles/Block.java @@ -38,6 +38,9 @@ import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; +import jcs.ui.layout.LayoutUtil; +import static jcs.ui.layout.LayoutUtil.blockHeight; +import static jcs.ui.layout.LayoutUtil.blockWidth; import jcs.ui.layout.events.TileEvent; import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; @@ -53,24 +56,8 @@ public class Block extends Tile { protected BlockState routeBlockState; - private static int blockWidth(Orientation orientation) { - if (Orientation.EAST == orientation || Orientation.WEST == orientation) { - return BLOCK_WIDTH; - } else { - return DEFAULT_WIDTH; - } - } - - private static int blockHeight(Orientation orientation) { - if (Orientation.EAST == orientation || Orientation.WEST == orientation) { - return DEFAULT_HEIGHT; - } else { - return BLOCK_HEIGHT; - } - } - public Block(TileBean tileBean) { - super(tileBean, blockWidth(tileBean.getOrientation()), blockHeight(tileBean.getOrientation())); + super(tileBean, LayoutUtil.blockWidth(tileBean.getOrientation()), LayoutUtil.blockHeight(tileBean.getOrientation())); setModel(new DefaultTileModel()); changeRenderSize(); } @@ -80,7 +67,7 @@ public Block(Orientation orientation, Point center) { } public Block(Orientation orientation, int x, int y) { - this(orientation, x, y, blockWidth(orientation), blockHeight(orientation)); + this(orientation, x, y, LayoutUtil.blockWidth(orientation), LayoutUtil.blockHeight(orientation)); } public Block(Orientation orientation, int x, int y, int width, int height) { @@ -99,43 +86,6 @@ private void changeRenderSize() { } } -// Block(TileBean tileBean) { -// super(tileBean); -// if (Orientation.EAST.equals(getOrientation()) || Orientation.WEST.equals(getOrientation())) { -// this.width = BLOCK_WIDTH; -// this.renderWidth = RENDER_WIDTH * 3; -// this.height = DEFAULT_HEIGHT; -// this.renderHeight = RENDER_HEIGHT; -// } else { -// this.width = DEFAULT_WIDTH; -// this.renderWidth = RENDER_WIDTH; -// this.height = BLOCK_HEIGHT; -// this.renderHeight = RENDER_HEIGHT * 3; -// } -// this.blockBean = tileBean.getBlockBean(); -// this.tileType = tileBean.getTileType(); -// this.setLayout(null); -// } -// Block(Orientation orientation, Point center) { -// this(orientation, center.x, center.y); -// } -// Block(Orientation orientation, int x, int y) { -// super(orientation, Direction.CENTER, x, y); -// -// if (Orientation.EAST == getOrientation() || Orientation.WEST == getOrientation()) { -// this.width = BLOCK_WIDTH; -// this.renderWidth = RENDER_WIDTH * 3; -// this.height = DEFAULT_HEIGHT; -// this.renderHeight = RENDER_HEIGHT; -// } else { -// this.width = DEFAULT_WIDTH; -// this.renderWidth = RENDER_WIDTH; -// this.height = BLOCK_HEIGHT; -// this.renderHeight = RENDER_HEIGHT * 3; -// } -// this.tileType = TileType.BLOCK; -// this.setLayout(null); -// } @Override public Set getAltPoints() { int xx = this.tileX; @@ -339,16 +289,10 @@ public String getIdSuffix(Tile other) { @Override public Orientation rotate() { rotate(false); - int w = blockWidth(tileOrientation); - int h = blockHeight(tileOrientation); + int w = LayoutUtil.blockWidth(tileOrientation); + int h = LayoutUtil.blockHeight(tileOrientation); Dimension d = new Dimension(w, h); - -// if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { -// d = new Dimension(w, h); -// } else { -// d = new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT * 3); -// } setPreferredSize(d); setSize(d); changeRenderSize(); @@ -810,41 +754,26 @@ protected void paintComponent(Graphics g) { long started = System.currentTimeMillis(); super.paintComponent(g); - int w = getWidth(); - int h = getHeight(); - //upon firts initializatien the width and height could still be wrong for reasons unknow to me... - //reset widh or height - boolean reset = false; - if (w != blockWidth(tileOrientation)) { - w = blockWidth(tileOrientation); - reset = true; - } - if (h != blockHeight(tileOrientation)) { - h = blockHeight(tileOrientation); - reset = true; - } - - if (reset) { - Logger.trace(id + " Resetting size... "); - Dimension d = new Dimension(w, h); - setPreferredSize(d); - setSize(d); - } - + int multiplier = (model.isScaleImage() ? 1 : 10); int xx, yy; if (tileOrientation == Orientation.EAST || tileOrientation == Orientation.WEST) { - xx = tileX - GRID - GRID * 2; - yy = tileY - GRID; - setBounds(xx, yy, w, h); + xx = tileX - GRID * multiplier - GRID * multiplier * 2; + yy = tileY - GRID * multiplier; + } else { + xx = tileX - GRID * multiplier; + yy = tileY - GRID * multiplier - GRID * multiplier * 2; + } + + if (model.isScaleImage()) { + setBounds(xx, yy, LayoutUtil.blockWidth(tileOrientation), LayoutUtil.blockHeight(tileOrientation)); } else { - xx = tileX - GRID; - yy = tileY - GRID - GRID * 2; - setBounds(xx, yy, w, h); + setBounds(xx, yy, renderWidth, renderHeight); } - Logger.trace(id + ": " + tileOrientation + " W: " + getWidth() + " H: " + getHeight() + " tX: " + tileX + ", tY: " + tileY + " xx: " + xx + " yy: " + yy); + Logger.trace(id + ": " + tileOrientation + " W: " + getWidth() + " H: " + getHeight() + " tX: " + tileX + ", tY: " + tileY + " xx: " + xx + " yy: " + yy + " Scale factor: " + multiplier); Graphics2D g2 = (Graphics2D) g.create(); + //Graphics2D g2 = (Graphics2D) g; drawTile(g2); g2.dispose(); @@ -856,45 +785,39 @@ protected void paintComponent(Graphics g) { @Override protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { - //super.drawCenterPoint(g2d, color, size); - //A block has 2 alternate points //1st square //2nd square holds the centerpoint //3rd square double dX1, dX2, dX3, dY1, dY2, dY3; - if (Orientation.EAST == this.tileOrientation || Orientation.WEST == tileOrientation) { - dX1 = (renderWidth / 3 / 2 - size / 2 / 2); - dX2 = (renderWidth / 2 - size / 2); - dX3 = (renderWidth / 3 / 2 + renderWidth / 3 * 2 - size / 2); - dY1 = (renderHeight / 2 - size / 2 / 2); - dY2 = (renderHeight / 2 - size / 2 / 2); - dY3 = (renderHeight / 2 - size / 2 / 2); + if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { + dX1 = renderWidth / 3 / 2 - size / 2 / 2; + dY1 = renderHeight / 2 - size / 2 / 2; + dX2 = renderWidth / 2 - size / 2; + dY2 = renderHeight / 2 - size / 2; + dX3 = renderWidth - renderWidth / 3 / 2 - size / 2 / 2; + dY3 = renderHeight / 2 - size / 2 / 2; } else { - dY1 = (renderWidth / 2 - size / 2 / 2); - - dY2 = (renderWidth / 2 - size / 2 / 2); - - dY3 = (renderWidth / 2 - size / 2 / 2); - - dX1 = (renderHeight / 3 / 2 - size / 2 / 2); - - dX2 = (renderHeight / 2 - size / 2); - - dX3 = (renderHeight / 3 / 2 + renderHeight / 3 * 2 - size / 2); - + dX1 = renderWidth / 2 - size / 2 / 2; + dY1 = renderHeight / 3 / 2 - size / 2 / 2; + dX2 = renderHeight / 2 - size / 2; + dY2 = renderWidth / 2 - size / 2; + dY3 = renderWidth / 2 - size / 2 / 2; + dX3 = renderHeight - renderHeight / 3 / 2 - size / 2 / 2; } g2d.setColor(color); - g2d.fill(new Ellipse2D.Double(dX1, dY1, size / 2, size / 2)); g2d.fill(new Ellipse2D.Double(dX2, dY2, size, size)); g2d.fill(new Ellipse2D.Double(dX3, dY3, size / 2, size / 2)); - Logger.trace(id + " dX2: " + dX2 + " dY2: " + dY2 + " O: " + tileOrientation + " rW: " + renderWidth + " rH:" + renderHeight); +// g2d.setPaint(Color.black); +// g2d.setStroke(new BasicStroke(2, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); +// g2d.drawOval(renderWidth / 2 - 5, renderHeight / 2 - 5, 10, 10); + + Logger.trace(id + " dX2: " + dX2 + " dY2: " + dY2 + " O: " + tileOrientation + " rW: " + renderWidth + " rH:" + renderHeight + " Size: " + size); Logger.trace(id + " dX1: " + dX1 + " dY1: " + dY1); Logger.trace(id + " dX3: " + dX3 + " dY3: " + dY3); - } } diff --git a/src/main/java/jcs/ui/layout/tiles/Cross.java b/src/main/java/jcs/ui/layout/tiles/Cross.java index d5153674..170114d6 100644 --- a/src/main/java/jcs/ui/layout/tiles/Cross.java +++ b/src/main/java/jcs/ui/layout/tiles/Cross.java @@ -242,11 +242,11 @@ public Map getEdgePoints() { return edgeConnections; } - @Override - public void rotate() { - super.rotate(); - setWidthHeightAndOffsets(); - } +// @Override +// public void rotate() { +// super.rotate(); +// setWidthHeightAndOffsets(); +// } final void setWidthHeightAndOffsets() { //Reset offsets diff --git a/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java b/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java index 3a60e1a4..c766c6d2 100644 --- a/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java +++ b/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java @@ -22,6 +22,7 @@ import javax.swing.event.ChangeListener; import javax.swing.event.EventListenerList; import jcs.entities.BlockBean.BlockState; +import jcs.entities.LocomotiveBean; /** * @@ -49,6 +50,10 @@ public class DefaultTileModel implements TileModel { protected boolean showOutline = false; protected BlockState blockState; + protected boolean reverseArrival; + protected String arrivalSuffix; + protected LocomotiveBean.Direction logicalDirection; + protected LocomotiveBean locomotive; public DefaultTileModel() { @@ -167,6 +172,81 @@ public void setBlockState(BlockState blockState) { fireStateChanged(); } + @Override + public String getArrivalSuffix() { + return arrivalSuffix; + } + + @Override + public void setArrivalSuffix(String arrivalSuffix) { + this.arrivalSuffix = arrivalSuffix; + fireStateChanged(); + } + + @Override + public void setDepartureSuffix(String suffix) { + if (null == suffix) { + setArrivalSuffix(null); + } else { + switch (suffix) { + case "-" -> + setArrivalSuffix("+"); + default -> + setArrivalSuffix("-"); + } + } + } + + @Override + public String getDepartureSuffix() { + String departureSuffix = null; + if (arrivalSuffix != null) { + if ("-".equals(arrivalSuffix)) { + departureSuffix = "+"; + } else { + departureSuffix = "-"; + } + } + + return departureSuffix; + } + + @Override + public boolean isReverseArrival() { + return reverseArrival; + } + + @Override + public void setReverseArrival(boolean reverseArrival) { + this.reverseArrival = reverseArrival; + fireStateChanged(); + } + + @Override + public LocomotiveBean.Direction getLogicalDirection() { + return logicalDirection; + } + + @Override + public void setLogicalDirection(LocomotiveBean.Direction logicalDirection) { + this.logicalDirection = logicalDirection; + fireStateChanged(); + } + + @Override + public LocomotiveBean getLocomotive() { + return locomotive; + } + + @Override + public void setLocomotive(LocomotiveBean locomotive) { + this.locomotive = locomotive; + fireStateChanged(); + } + + + + @Override public void addChangeListener(ChangeListener l) { listenerList.add(ChangeListener.class, l); diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java index b1794914..dd068616 100755 --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -45,6 +45,7 @@ import jcs.entities.AccessoryBean.SignalType; import jcs.entities.BlockBean; import jcs.entities.BlockBean.BlockState; +import jcs.entities.LocomotiveBean; import jcs.entities.SensorBean; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; @@ -80,16 +81,16 @@ public abstract class Tile extends JComponent implements TileEventListener { //, public static final int GRID = 20; public static final int DEFAULT_WIDTH = GRID * 2; public static final int DEFAULT_HEIGHT = GRID * 2; - + static final int RENDER_GRID = GRID * 10; static final int RENDER_WIDTH = RENDER_GRID * 2; static final int RENDER_HEIGHT = RENDER_GRID * 2; - + public static final Color DEFAULT_BACKGROUND_COLOR = Color.white; public static final Color DEFAULT_TRACK_COLOR = Color.lightGray; public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.blue; public static final Color DEFAULT_SELECTED_COLOR = Color.yellow; - + public static final String MODEL_CHANGED_PROPERTY = "model"; public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled"; @@ -97,123 +98,123 @@ public abstract class Tile extends JComponent implements TileEventListener { //, * The data model that determines the button's state. */ protected TileModel model = null; - + protected String id; protected Integer tileX; protected Integer tileY; - + protected int renderWidth; protected int renderHeight; - + protected Orientation tileOrientation; protected Direction tileDirection; - + protected TileType tileType; protected String accessoryId; protected String sensorId; - + protected AccessoryValue accessoryValue; protected AccessoryValue routeValue; - + protected SignalType signalType; protected AccessoryBean.SignalValue signalValue; - + protected AccessoryBean accessoryBean; protected SensorBean sensorBean; protected BlockBean blockBean; - + protected List neighbours; - + protected int offsetX = 0; protected int offsetY = 0; - + protected int renderOffsetX = 0; protected int renderOffsetY = 0; - + protected Color selectedColor; protected Color trackColor; protected Color trackRouteColor; protected Orientation incomingSide; - + protected Color backgroundColor; protected boolean drawName = true; - + protected BufferedImage tileImage; - + protected PropertyChangeListener propertyChangeListener; - + protected ChangeListener changeListener = null; protected ActionListener actionListener = null; //protected ItemListener itemListener = null; protected transient ChangeEvent changeEvent; - + private Handler handler; - protected Tile(TileType tileType, Point center) { - this(tileType, Orientation.EAST, Direction.CENTER, center.x, center.y, DEFAULT_WIDTH, DEFAULT_HEIGHT); - } - + //protected Tile(TileType tileType, Point center) { + // this(tileType, Orientation.EAST, Direction.CENTER, center.x, center.y, DEFAULT_WIDTH, DEFAULT_HEIGHT); + //} protected Tile(TileType tileType, Orientation orientation, Point center, int width, int height) { this(tileType, orientation, Direction.CENTER, center.x, center.y, width, height); } - + protected Tile(TileType tileType, Orientation orientation, int x, int y, int width, int height) { this(tileType, orientation, Direction.CENTER, x, y, width, height); } - + protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { this(tileType, orientation, direction, x, y, width, height, null, null); } - + protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height, Color backgroundColor, Color selectedColor) { this.tileType = tileType; this.tileOrientation = orientation; this.tileDirection = direction; this.tileX = x; this.tileY = y; - + + setLayout(null); Dimension d = new Dimension(width, height); - super.setPreferredSize(d); - super.setSize(d); - + setSize(d); + setPreferredSize(d); + int w = getWidth(); int h = getHeight(); - + this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT; - + this.trackColor = DEFAULT_TRACK_COLOR; this.backgroundColor = backgroundColor; this.selectedColor = selectedColor; - + if (this.backgroundColor == null) { this.backgroundColor = DEFAULT_BACKGROUND_COLOR; } if (this.selectedColor == null) { this.selectedColor = DEFAULT_SELECTED_COLOR; } - this.setLayout(null); + } - + protected Tile(Object tileBean) { this(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); } - + protected Tile(Object tileBean, int width, int height) { copyInto(tileBean); setLayout(null); Dimension d = new Dimension(width, height); - this.setSize(d); - this.setPreferredSize(d); - + setSize(d); + setPreferredSize(d); + this.trackColor = DEFAULT_TRACK_COLOR; this.backgroundColor = DEFAULT_BACKGROUND_COLOR; this.selectedColor = DEFAULT_SELECTED_COLOR; this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT; } - + private void copyInto(Object object) { if (object instanceof TileBean other) { this.id = other.getId(); @@ -224,28 +225,28 @@ private void copyInto(Object object) { this.tileDirection = other.getDirection(); this.tileX = other.getX(); this.tileY = other.getY(); - + this.signalType = other.getSignalType(); this.accessoryId = other.getAccessoryId(); this.sensorId = other.getSensorId(); this.accessoryBean = other.getAccessoryBean(); this.sensorBean = other.getSensorBean(); this.blockBean = other.getBlockBean(); - + if (other.getAccessoryBean() != null) { AccessoryBean ab = other.getAccessoryBean(); this.signalType = SignalType.getSignalType(ab.getType()); } - + } - + if (object instanceof Tile tile) { this.renderWidth = tile.renderWidth; this.renderHeight = tile.renderHeight; } - + } - + public TileBean getTileBean() { TileBean tb = new TileBean(); tb.setId(this.id); @@ -260,116 +261,162 @@ public TileBean getTileBean() { tb.setAccessoryBean(this.accessoryBean); tb.setSensorBean(this.sensorBean); tb.setBlockBean(this.blockBean); - + return tb; } - + public boolean isSelected() { return model.isSelected(); } - + public void setSelected(boolean b) { //boolean oldValue = isSelected(); model.setSelected(b); } - + @Override public String getId() { return id; } - + public void setId(String id) { this.id = id; } - + public SignalType getSignalType() { - return this.signalType; + return signalType; } - + public void setSignalType(SignalType signalType) { this.signalType = signalType; } - + public Integer getTileX() { return tileX; } - public void setTileX(Integer x) { - this.tileX = x; - } - +// public void setTileX(Integer x) { +// this.tileX = x; +// } public Integer getTileY() { return tileY; } - public void setTileY(Integer y) { - this.tileY = y; - } - +// public void setTileY(Integer y) { +// this.tileY = y; +// } public Point getCenter() { return new Point(this.tileX, this.tileY); } - + public void setCenter(Point center) { - this.tileX = center.x; - this.tileY = center.y; + tileX = center.x; + tileY = center.y; } - + public Orientation getOrientation() { return tileOrientation; } - + public void setOrientation(Orientation orientation) { this.tileOrientation = orientation; } - + public Direction getDirection() { return tileDirection; } - + public void setDirection(Direction direction) { this.tileDirection = direction; } - + public String getAccessoryId() { return accessoryId; } - + public void setAccessoryId(String accessoryId) { this.accessoryId = accessoryId; } - + public String getSensorId() { return sensorId; } - + public void setSensorId(String sensorId) { this.sensorId = sensorId; } - + public boolean isActive() { return model.isSensorActive(); } - + public void setActive(boolean active) { - this.model.setSensorActive(active); + model.setSensorActive(active); } - + public BlockState getBlockState() { - return this.model.getBlockState(); + return model.getBlockState(); } - + public void setBlockState(BlockState blockState) { - this.model.setBlockState(blockState); + if (blockBean != null) { + blockBean.setBlockState(blockState); + } + model.setBlockState(blockState); } - + + public String getDepartureSuffix() { + return model.getDepartureSuffix(); + } + + public void setDepartureSuffix(String suffix) { + if (blockBean != null) { + blockBean.setDepartureSuffix(suffix); + } + model.setDepartureSuffix(suffix); + } + + public boolean isReverseArrival() { + return model.isReverseArrival(); + } + + public void setReverseArrival(boolean reverseArrival) { + if (blockBean != null) { + blockBean.setReverseArrival(reverseArrival); + } + model.setReverseArrival(reverseArrival); + } + + public LocomotiveBean.Direction getLogicalDirection() { + return model.getLogicalDirection(); + } + + public void setLogicalDirection(LocomotiveBean.Direction logicalDirection) { + if (blockBean != null) { + blockBean.setLogicalDirection(logicalDirection.getDirection()); + } + model.setLogicalDirection(logicalDirection); + } + + public LocomotiveBean getLocomotive() { + return model.getLocomotive(); + } + + public void setLocomotive(LocomotiveBean locomotive) { + if (blockBean != null) { + blockBean.setLocomotive(locomotive); + } + + this.model.setLocomotive(locomotive); + } + public AccessoryBean getAccessoryBean() { return accessoryBean; } - + public void setAccessoryBean(AccessoryBean accessoryBean) { this.accessoryBean = accessoryBean; - + if (accessoryBean != null) { this.accessoryId = accessoryBean.getId(); this.signalValue = accessoryBean.getSignalValue(); @@ -380,7 +427,7 @@ public void setAccessoryBean(AccessoryBean accessoryBean) { this.signalValue = AccessoryBean.SignalValue.OFF; } } - + public AccessoryValue getAccessoryValue() { if (this.accessoryValue == null) { return AccessoryValue.OFF; @@ -388,12 +435,12 @@ public AccessoryValue getAccessoryValue() { return accessoryValue; } } - + public void setAccessoryValue(AccessoryValue value) { this.accessoryValue = value; repaint(); } - + public AccessoryValue getRouteValue() { if (routeValue == null) { return AccessoryValue.OFF; @@ -401,127 +448,127 @@ public AccessoryValue getRouteValue() { return routeValue; } } - + public void setRouteValue(AccessoryValue value) { this.routeValue = value; repaint(); } - + public AccessoryBean.SignalValue getSignalValue() { return signalValue; } - + public void setSignalValue(AccessoryBean.SignalValue signalValue) { this.signalValue = signalValue; this.repaint(); } - + public SensorBean getSensorBean() { return sensorBean; } - + public void setSensorBean(SensorBean sensorBean) { this.sensorBean = sensorBean; } - + public BlockBean getBlockBean() { return blockBean; } - + public void setBlockBean(BlockBean blockBean) { this.blockBean = blockBean; } - + public void setRenderWidth(int renderWidth) { this.renderWidth = renderWidth; } - + public void setRenderHeight(int renderHeight) { this.renderHeight = renderHeight; } - + public int getRenderOffsetX() { return renderOffsetX; } - + public void setRenderOffsetX(int renderOffsetX) { this.renderOffsetX = renderOffsetX; } - + public int getRenderOffsetY() { return renderOffsetY; } - + public void setRenderOffsetY(int renderOffsetY) { this.renderOffsetY = renderOffsetY; } - + public TileBean.TileType getTileType() { return this.tileType; } - + public final void setTileType(TileType tileType) { this.tileType = tileType; } - + public Color getTrackColor() { return trackColor; } - + public final void setTrackColor(Color trackColor) { this.trackColor = trackColor; } - + public Color getTrackRouteColor() { return trackRouteColor; } - + public void setTrackRouteColor(Color trackRouteColor) { this.trackRouteColor = trackRouteColor; } - + public Color getSelectedColor() { return selectedColor; } - + public void setSelectedColor(Color selectedColor) { this.selectedColor = selectedColor; } - + public Orientation getIncomingSide() { return incomingSide; } - + public void setIncomingSide(Orientation incomingSide) { this.incomingSide = incomingSide; } - + public Color getBackgroundColor() { return backgroundColor; } - + public void setBackgroundColor(Color backgroundColor) { this.backgroundColor = backgroundColor; } - + public boolean isDrawRoute() { - return this.model.isShowRoute(); + return model.isShowRoute(); } - + public void setDrawRoute(boolean drawRoute) { this.model.setShowRoute(drawRoute); } - + public int getRenderWidth() { return renderWidth; } - + public int getRenderHeight() { return renderHeight; } - + abstract void renderTile(Graphics2D g2d); - + abstract void renderTileRoute(Graphics2D g2d); /** @@ -535,7 +582,7 @@ public void drawTile(Graphics2D g2d) { if (tileOrientation == null) { tileOrientation = Orientation.EAST; } - + tileImage = createImage(); Graphics2D g2di = tileImage.createGraphics(); @@ -543,16 +590,16 @@ public void drawTile(Graphics2D g2d) { if (model.isShowRoute() && incomingSide == null) { incomingSide = getOrientation(); } - + if (model.isSelected()) { g2di.setBackground(selectedColor); } else { g2di.setBackground(backgroundColor); } - + g2di.clearRect(0, 0, renderWidth, renderHeight); int ox = 0, oy = 0; - + AffineTransform trans = new AffineTransform(); switch (tileOrientation) { case SOUTH -> { @@ -572,19 +619,22 @@ public void drawTile(Graphics2D g2d) { trans.translate(-ox, -oy); } default -> { - //trans.rotate(0.0, this.renderWidth / 2, this.renderHeight / 2); - //trans.translate(ox, oy); + trans.rotate(0.0, this.renderWidth / 2, this.renderHeight / 2); + trans.translate(ox, oy); } } - + + Logger.trace(tileOrientation.getOrientation() + " renderWidth: " + renderWidth + " renderHeight: " + renderHeight + " CP: (" + renderWidth / 2 + "," + renderHeight / 2 + ")"); + Logger.trace(tileOrientation.getOrientation() + " ox: " + ox + " oy: " + oy); + g2di.setTransform(trans); - + renderTile(g2di); - + if (model.isShowRoute()) { renderTileRoute(g2di); } - + if (model.isShowCenter()) { drawCenterPoint(g2di); } @@ -593,7 +643,7 @@ public void drawTile(Graphics2D g2d) { if (model.isScaleImage()) { tileImage = Scalr.resize(tileImage, Method.AUTOMATIC, Mode.FIT_EXACT, getWidth(), getHeight(), Scalr.OP_ANTIALIAS); } - + g2di.dispose(); // int oxx, oyy; @@ -606,7 +656,7 @@ public void drawTile(Graphics2D g2d) { // } //g2d.drawImage(tileImage, (tileX - tileImage.getWidth() / 2) + oxx, (tileY - tileImage.getHeight() / 2) + oyy, null); } - + public BufferedImage getTileImage() { return tileImage; } @@ -618,19 +668,19 @@ public BufferedImage getTileImage() { */ public void drawName(Graphics2D g2) { } - + protected void drawCenterPoint(Graphics2D g2d) { drawCenterPoint(g2d, Color.magenta); } - + protected void drawCenterPoint(Graphics2D g2, Color color) { drawCenterPoint(g2, color, 60); } - + protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { double dX = (renderWidth / 2 - size / 2); double dY = (renderHeight / 2 - size / 2); - + g2d.setColor(color); g2d.fill(new Ellipse2D.Double(dX, dY, size, size)); } @@ -648,7 +698,7 @@ public Orientation rotate() { * Rotate the tile clockwise 90 deg * * @param repaint - * @return + * @return */ protected Orientation rotate(boolean repaint) { switch (tileOrientation) { @@ -666,27 +716,27 @@ protected Orientation rotate(boolean repaint) { } return tileOrientation; } - + public void flipHorizontal() { if (Orientation.NORTH.equals(getOrientation()) || Orientation.SOUTH.equals(getOrientation())) { rotate(false); rotate(true); } } - + public void flipVertical() { if (Orientation.EAST.equals(getOrientation()) || Orientation.WEST.equals(getOrientation())) { rotate(false); rotate(true); } } - + @Override public void move(int newX, int newY) { Point cs = LayoutUtil.snapToGrid(newX, newY); setCenter(cs); } - + protected static void drawRotate(Graphics2D g2d, double x, double y, int angle, String text) { g2d.translate((float) x, (float) y); g2d.rotate(Math.toRadians(angle)); @@ -694,83 +744,83 @@ protected static void drawRotate(Graphics2D g2d, double x, double y, int angle, g2d.rotate(-Math.toRadians(angle)); g2d.translate(-x, -y); } - + public static BufferedImage flipHorizontally(BufferedImage source) { BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); - + AffineTransform flip = AffineTransform.getScaleInstance(1, -1); flip.translate(0, -source.getHeight()); AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); - + op.filter(source, output); - + return output; } - + public static BufferedImage flipVertically(BufferedImage source) { BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); - + AffineTransform flip = AffineTransform.getScaleInstance(-1, 1); flip.translate(-source.getWidth(), 0); AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); - + op.filter(source, output); - + return output; } - + public Set getAltPoints() { return Collections.EMPTY_SET; } - + public final int getOffsetX() { return offsetX; } - + public void setOffsetX(int offsetX) { this.offsetX = offsetX; } - + public final int getOffsetY() { return offsetY; } - + public void setOffsetY(int offsetY) { this.offsetY = offsetY; } - + protected BufferedImage createImage() { return new BufferedImage(renderWidth, renderHeight, BufferedImage.TYPE_INT_RGB); } - + public int getCenterX() { - if (this.tileX > 0) { + if (tileX > 0) { return this.tileX; } else { return GRID; } } - + public int getCenterY() { - if (this.tileY > 0) { + if (tileY > 0) { return this.tileY; } else { return GRID; } } - + public boolean isDrawName() { return drawName; } - + public void setDrawName(boolean drawName) { this.drawName = drawName; } - + public boolean isScaleImage() { return model.isScaleImage(); } - + public void setScaleImage(boolean scaleImage) { Dimension d; if (scaleImage) { @@ -778,21 +828,21 @@ public void setScaleImage(boolean scaleImage) { } else { d = new Dimension(renderWidth, renderHeight); } - + setSize(d); setPreferredSize(d); - + model.setScaleImage(scaleImage); } - + public boolean isDrawCenterPoint() { return model.isShowCenter(); } - + public void setDrawCenterPoint(boolean drawCenterPoint) { model.setShowCenter(drawCenterPoint); } - + @Override public String toString() { return this.getClass().getSimpleName() @@ -806,7 +856,7 @@ public String toString() { + xyToString() + "}"; } - + @Override public Rectangle getBounds() { int w, h, cx, cy; @@ -821,7 +871,7 @@ public Rectangle getBounds() { w = DEFAULT_WIDTH; h = DEFAULT_HEIGHT; } - + if (this.tileX > 0 && this.tileY > 0) { cx = this.tileX + this.offsetX; cy = this.tileY + this.offsetY; @@ -829,16 +879,16 @@ public Rectangle getBounds() { cx = w / 2; cy = h / 2; } - + int ltx = cx - w / 2; int lty = cy - h / 2; return new Rectangle(ltx, lty, w, h); } - + public Rectangle2D getBounds2D() { return getBounds().getBounds2D(); } - + public boolean contains(double x, double y) { int w, h, cx, cy, tlx, tly; if (this.getWidth() > 0 & this.getHeight() > 0) { @@ -847,12 +897,12 @@ public boolean contains(double x, double y) { // h = this.height; w = this.getPreferredSize().width; h = this.getPreferredSize().height; - + } else { w = DEFAULT_WIDTH; h = DEFAULT_HEIGHT; } - + if (this.getWidth() > 0 & this.getHeight() > 0) { //if (this.width > 0 & this.height > 0) { cx = this.tileX; @@ -869,56 +919,56 @@ public boolean contains(double x, double y) { // Check if X and Y range is ok return !(x < tlx || x > (tlx + w) || y < tly || y > (tly + h)); } - + public String xyToString() { return "(" + this.tileX + "," + this.tileY + ")"; } - + public boolean contains(Point2D p) { return this.contains(p.getX(), p.getY()); } - + public boolean intersects(double x, double y, double w, double h) { return getBounds().intersects(x, y, w, h); } - + public boolean intersects(Rectangle2D r2d) { return getBounds().intersects(r2d); } - + public boolean contains(double x, double y, double w, double h) { return getBounds().contains(x, y, w, h); } - + public boolean contains(Rectangle2D r2d) { return getBounds().contains(r2d); } - + public PathIterator getPathIterator(AffineTransform at) { return getBounds().getPathIterator(at); } - + public PathIterator getPathIterator(AffineTransform at, double flatness) { return getBounds().getPathIterator(at, flatness); } - + @Deprecated public PropertyChangeListener getPropertyChangeListener() { return this.propertyChangeListener; } - + @Deprecated public void setPropertyChangeListener(PropertyChangeListener propertyChangeListener) { this.propertyChangeListener = propertyChangeListener; } - + @Deprecated public void repaintTile() { // if (this.propertyChangeListener != null) { // this.propertyChangeListener.propertyChange(new PropertyChangeEvent(this, "repaintTile", this, this)); // } } - + @Override @Deprecated public void onTileChange(TileEvent tileEvent) { @@ -926,27 +976,27 @@ public void onTileChange(TileEvent tileEvent) { if (tileEvent.isEventFor(this)) { boolean drawRoute = tileEvent.isShowRoute(); setIncomingSide(tileEvent.getIncomingSide()); - + if (isJunction()) { // setRouteValue(tileEvent.getRouteState()); } - + if (tileEvent.getBlockBean() != null) { this.setBlockBean(tileEvent.getBlockBean()); } - + if (tileEvent.getTileBean() != null) { TileBean other = tileEvent.getTileBean(); this.copyInto(other); } - + if (isBlock()) { // ((Block) this).setRouteBlockState(tileEvent.getBlockState()); if (!drawRoute) { // ((Block) this).setRouteBlockState(null); } } - + setBackgroundColor(tileEvent.getBackgroundColor()); setTrackColor(tileEvent.getTrackColor()); setTrackRouteColor(tileEvent.getTrackRouteColor()); @@ -958,21 +1008,13 @@ public void onTileChange(TileEvent tileEvent) { } } - public int getGridX() { - return (getCenterX() - Tile.GRID) / (Tile.GRID * 2); - } - - public int getGridY() { - return (getCenterY() - Tile.GRID) / (Tile.GRID * 2); - } - /** * The main route of the tile is horizontal * * @return true when main route goes from East to West or vv */ public boolean isHorizontal() { - return (Orientation.EAST == getOrientation() || Orientation.WEST == getOrientation()) && TileType.CURVED != getTileType(); + return (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) && TileType.CURVED != tileType; } /** @@ -981,19 +1023,19 @@ public boolean isHorizontal() { * @return true when main route goes from North to South or vv */ public boolean isVertical() { - return (Orientation.NORTH == getOrientation() || Orientation.SOUTH == getOrientation()) && TileType.CURVED != getTileType(); + return (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) && TileType.CURVED != tileType; } - + public boolean isJunction() { - return false; + return TileType.SWITCH == tileType || TileType.CROSS == tileType; } - + public boolean isBlock() { - return false; + return TileType.BLOCK == tileType; } - + public boolean isDirectional() { - return false; + return TileType.STRAIGHT_DIR == tileType; } /** @@ -1002,54 +1044,54 @@ public boolean isDirectional() { * @return true when main route goes from North to East or West to South and vv */ public boolean isDiagonal() { - return TileType.CURVED == getTileType(); + return TileType.CURVED == tileType; } - + public boolean isCrossing() { - return TileType.CROSSING == getTileType(); + return TileType.CROSSING == tileType; } - + public List getNeighbours() { - return this.neighbours; + return neighbours; } - + public void setNeighbours(List neighbours) { this.neighbours = neighbours; } - + public String getIdSuffix(Tile other) { return ""; } - + public Map getNeighborOrientations() { Map edgeOrientations = new HashMap<>(); - + Map neighborPoints = getNeighborPoints(); - + for (Orientation o : Orientation.values()) { edgeOrientations.put(neighborPoints.get(o), o); } return edgeOrientations; } - + public Map getEdgeOrientations() { Map edgeOrientations = new HashMap<>(); - + Map edgeConnections = getEdgePoints(); - + for (Orientation o : Orientation.values()) { edgeOrientations.put(edgeConnections.get(o), o); } return edgeOrientations; } - + public boolean isAdjacent(Tile other) { boolean adjacent = false; - + if (other != null) { Collection thisEdgePoints = getEdgePoints().values(); Collection otherEdgePoints = other.getEdgePoints().values(); - + for (Point p : thisEdgePoints) { adjacent = otherEdgePoints.contains(p); if (adjacent) { @@ -1057,7 +1099,7 @@ public boolean isAdjacent(Tile other) { } } } - + return adjacent; } @@ -1071,11 +1113,11 @@ public boolean isAdjacent(Tile other) { public boolean isArrowDirection(Tile other) { return true; } - + public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { return AccessoryValue.OFF; } - + @Deprecated protected StringBuilder getImageKeyBuilder() { StringBuilder sb = new StringBuilder(); @@ -1135,37 +1177,37 @@ protected StringBuilder getImageKeyBuilder() { //Logger.trace(sb); return sb; } - + public abstract Map getNeighborPoints(); - + public abstract Map getEdgePoints(); - + public abstract Set getAllPoints(); - + public TileModel getModel() { return model; } - + public void setModel(TileModel newModel) { TileModel oldModel = getModel(); - + if (oldModel != null) { oldModel.removeChangeListener(changeListener); oldModel.removeActionListener(actionListener); changeListener = null; actionListener = null; } - + model = newModel; - + if (newModel != null) { changeListener = createChangeListener(); actionListener = createActionListener(); - + newModel.addChangeListener(changeListener); newModel.addActionListener(actionListener); } - + firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel); if (newModel != oldModel) { revalidate(); @@ -1182,38 +1224,38 @@ public void setModel(TileModel newModel) { @Override public void updateUI() { } - + protected ChangeListener createChangeListener() { return getHandler(); } - + protected ActionListener createActionListener() { return getHandler(); } - + private Handler getHandler() { if (handler == null) { handler = new Handler(); } return handler; } - + class Handler implements ActionListener, ChangeListener, Serializable { - + @Override public void stateChanged(ChangeEvent e) { Object source = e.getSource(); - + fireStateChanged(); repaint(); } - + @Override public void actionPerformed(ActionEvent event) { fireActionPerformed(event); } } - + protected void fireStateChanged() { Object[] listeners = listenerList.getListenerList(); //reverse order @@ -1227,7 +1269,7 @@ protected void fireStateChanged() { } } } - + protected void fireActionPerformed(ActionEvent event) { Object[] listeners = listenerList.getListenerList(); ActionEvent e = null; @@ -1246,5 +1288,5 @@ protected void fireActionPerformed(ActionEvent event) { } } } - + } diff --git a/src/main/java/jcs/ui/layout/tiles/TileModel.java b/src/main/java/jcs/ui/layout/tiles/TileModel.java index b9f59c2a..3d472126 100644 --- a/src/main/java/jcs/ui/layout/tiles/TileModel.java +++ b/src/main/java/jcs/ui/layout/tiles/TileModel.java @@ -19,6 +19,7 @@ import java.io.Serializable; import javax.swing.event.ChangeListener; import jcs.entities.BlockBean; +import jcs.entities.LocomotiveBean; /** * @@ -66,12 +67,27 @@ public interface TileModel extends Serializable { public void setBlockState(BlockBean.BlockState blockState); - //boolean isShowOutline(); - //public void setShowOutline(boolean showOutline); - //@Override - //void addItemListener(ItemListener l); - //@Override - //void removeItemListener(ItemListener l); + String getArrivalSuffix(); + + public void setArrivalSuffix(String arrivalSuffix); + + String getDepartureSuffix(); + + public void setDepartureSuffix(String suffix); + + boolean isReverseArrival(); + + public void setReverseArrival(boolean reverseArrival); + + LocomotiveBean.Direction getLogicalDirection(); + + public void setLogicalDirection(LocomotiveBean.Direction logicalDirection); + + LocomotiveBean getLocomotive(); + + public void setLocomotive(LocomotiveBean locomotive); + + // void addChangeListener(ChangeListener l); void removeChangeListener(ChangeListener l); diff --git a/src/test/java/jcs/ui/layout/TileTest.java b/src/test/java/jcs/ui/layout/TileTest.java index 6b634b1c..244a7d39 100644 --- a/src/test/java/jcs/ui/layout/TileTest.java +++ b/src/test/java/jcs/ui/layout/TileTest.java @@ -56,31 +56,33 @@ public void testgetCenterXZero() { assertEquals(expResult, result); } +// public int getGridX() { +// return (getCenterX() - Tile.GRID) / (Tile.GRID * 2); +// } +// public int getGridY() { +// return (getCenterY() - Tile.GRID) / (Tile.GRID * 2); +// } @Test public void testGetGridX() { System.out.println("getGridX"); Tile instance - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 100, 100, false); + = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 100, 100, false); int expResult = 2; - int result = instance.getGridX(); + int result = (instance.getTileX() - Tile.GRID) / (Tile.GRID * 2); + assertEquals(expResult, result); - instance - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 220, 220, false); + instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 220, 220, false); expResult = 5; - result = instance.getGridX(); + result = (instance.getTileX() - Tile.GRID) / (Tile.GRID * 2); assertEquals(expResult, result); } @Test public void testgetCenterY() { System.out.println("getCenterY"); - Tile instance - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 180, 100, false); + Tile instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 180, 100, false); int expResult = 100; int result = instance.getCenterY(); assertEquals(expResult, result); @@ -89,9 +91,7 @@ public void testgetCenterY() { @Test public void testgetCenterYZero() { System.out.println("getCenterY"); - Tile instance - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 0, 0, false); + Tile instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 0, 0, false); int expResult = 20; int result = instance.getCenterY(); assertEquals(expResult, result); @@ -100,11 +100,9 @@ public void testgetCenterYZero() { @Test public void testGetGridY() { System.out.println("getGridY"); - Tile instance - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 100, 140, false); + Tile instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 100, 140, false); int expResult = 3; - int result = instance.getGridY(); + int result = (instance.getTileY() - Tile.GRID) / (Tile.GRID * 2); assertEquals(expResult, result); } diff --git a/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java b/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java index 3fcbfd65..afb7d614 100644 --- a/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java +++ b/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java @@ -22,10 +22,6 @@ import javax.swing.JPanel; import org.tinylog.Logger; -/** - * - * @author fransjacobs - */ public class DotGridCanvas extends JPanel { public DotGridCanvas() { diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java index 4dce3bf3..308362f5 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java @@ -25,20 +25,24 @@ public class UnscaledBlockCanvas extends JPanel { //implements PropertyChangeListener { private boolean expanded; + private int paintCount = 0; public UnscaledBlockCanvas() { setLayout(null); - setOpaque(false); + setOpaque(true); setDoubleBuffered(true); } @Override public void paint(Graphics g) { long started = System.currentTimeMillis(); + paintCount++; //Rectangle r = g.getClipBounds(); //Logger.trace("Rx: " + r.x + " Ry: " + r.y + " Rw: " + r.width + " Rh: " + r.height); - super.paint(g); + if (paintCount > 2) { + super.paint(g); + } paintGrid(g); long now = System.currentTimeMillis(); @@ -59,7 +63,7 @@ private void paintGrid(Graphics g) { int grid; if (expanded) { - grid = 200; + grid = 20; } else { grid = 20; } @@ -72,8 +76,6 @@ private void paintGrid(Graphics g) { gc.setPaint(p); } - - //private boolean showCenter; //private final List tiles; // public UnscaledBlockCanvas() { @@ -228,12 +230,12 @@ private void paintGrid(Graphics g) { // return this.getSize(); // } // } - public boolean isExpanded() { return expanded; } public void setExpanded(boolean expanded) { this.expanded = expanded; + this.repaint(); } } diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.form b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.form index 098f9189..9c565600 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.form +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.form @@ -199,6 +199,9 @@ + + + @@ -212,7 +215,7 @@ - + diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.java b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.java index 10444f86..46d8ce54 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.java +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.java @@ -1,5 +1,5 @@ /* - * Copyright 2024 FJA. + * Copyright 2024 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,9 +15,7 @@ */ package jcs.ui.layout.tiles; -import java.awt.Dimension; import java.awt.Image; -import java.awt.Point; import java.awt.image.BufferedImage; import java.io.File; import javax.swing.ComboBoxModel; @@ -30,17 +28,12 @@ import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; import jcs.entities.TileBean.Orientation; -import jcs.ui.layout.LayoutUtil; import jcs.ui.util.ImageUtil; import org.tinylog.Logger; -/** - * - * @author FJA - */ public class UnscaledBlockTester extends JFrame { //implements PropertyChangeListener { - private Tile blockTile; + private final Tile blockTile; /** * Creates new form UnscaledBlockTileFrame @@ -52,11 +45,12 @@ public UnscaledBlockTester() { this.departureSideCB.setSelectedItem(""); this.stateCB.setModel(createStateComboBoxModel()); - this.blockTile = initBlock(); + blockTile = createBlock(); canvas.add(blockTile); - centerSP.getViewport().validate(); + centerSP.getViewport().validate(); + pack(); setVisible(true); } @@ -79,6 +73,7 @@ private ComboBoxModel createStateComboBoxModel() { blockStateModel.addElement(BlockState.LOCKED); blockStateModel.addElement(BlockState.OUT_OF_ORDER); + blockStateModel.setSelectedItem(BlockState.FREE); return blockStateModel; } @@ -100,28 +95,20 @@ private LocomotiveBean createLocomotiveBean() { return lb; } - private Block initBlock() { - Point center = LayoutUtil.snapToGrid(canvas.getWidth() / 2, canvas.getHeight() / 2); - int cX = center.x; - int cY = center.y; - - Logger.trace("Center X: " + cX + " Y: " + cY); + private Block createBlock() { + Block block = new Block(Orientation.EAST, 640, 280); - Block block = new Block(Orientation.EAST, cX, cY); block.setId("bk-1"); + block.setBlockState((BlockState) stateCB.getSelectedItem()); block.setScaleImage(!scaleCB.isSelected()); - canvas.setExpanded(scaleCB.isSelected()); + //canvas.setExpanded(scaleCB.isSelected()); BlockBean blockBean = new BlockBean(); blockBean.setId(block.getId()); blockBean.setTileId(block.getId()); blockBean.setDescription("Blok 1"); - - //bbe.setArrivalSuffix((String) this.incomingSideCB.getSelectedItem()); blockBean.setDepartureSuffix(null); - - blockBean.setBlockState((BlockState) stateCB.getSelectedItem()); - blockBean.setReverseArrival(reverseArrivalCB.isSelected()); + blockBean.setDepartureSuffix((String) this.departureSideCB.getSelectedItem()); if (showLocCB.isSelected()) { blockBean.setLocomotive(createLocomotiveBean()); @@ -130,7 +117,6 @@ private Block initBlock() { } block.setBlockBean(blockBean); - return block; } @@ -272,6 +258,7 @@ public void componentResized(java.awt.event.ComponentEvent evt) { }); canvas.setAutoscrolls(true); + canvas.setPreferredSize(new java.awt.Dimension(1220, 410)); canvas.addComponentListener(new java.awt.event.ComponentAdapter() { public void componentResized(java.awt.event.ComponentEvent evt) { canvasComponentResized(evt); @@ -286,7 +273,7 @@ public void componentResized(java.awt.event.ComponentEvent evt) { ); canvasLayout.setVerticalGroup( canvasLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 498, Short.MAX_VALUE) + .addGap(0, 445, Short.MAX_VALUE) ); centerSP.setViewportView(canvas); @@ -297,18 +284,17 @@ public void componentResized(java.awt.event.ComponentEvent evt) { }// //GEN-END:initComponents private void rotateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rotateButtonActionPerformed - Orientation orientation = blockTile.rotate(); + Orientation orientation = blockTile.rotate(); this.orientationCB.setSelectedItem(orientation); - Logger.trace("Blok is rotated to " + orientation); + Logger.trace("\nBlok is rotated to " + orientation); }//GEN-LAST:event_rotateButtonActionPerformed private void showLocCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showLocCBActionPerformed if (this.showLocCB.isSelected()) { - ((Block) blockTile).getBlockBean().setLocomotive(this.createLocomotiveBean()); + blockTile.setLocomotive(createLocomotiveBean()); } else { - ((Block) blockTile).getBlockBean().setLocomotive(null); + blockTile.setLocomotive(null); } - repaint(); }//GEN-LAST:event_showLocCBActionPerformed private void orientationCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_orientationCBActionPerformed @@ -316,71 +302,49 @@ private void orientationCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN }//GEN-LAST:event_orientationCBActionPerformed private void departureSideCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_departureSideCBActionPerformed - if (blockTile != null && ((Block) blockTile).getBlockBean() != null) { - if ("".equals(this.departureSideCB.getSelectedItem())) { - ((Block) blockTile).getBlockBean().setDepartureSuffix(null); - } else { - ((Block) blockTile).getBlockBean().setDepartureSuffix((String) this.departureSideCB.getSelectedItem()); - } - repaint(); + if ("".equals(departureSideCB.getSelectedItem())) { + blockTile.setDepartureSuffix(null); + } else { + blockTile.setDepartureSuffix(departureSideCB.getSelectedItem().toString()); } }//GEN-LAST:event_departureSideCBActionPerformed private void stateCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_stateCBActionPerformed - ((Block) blockTile).getBlockBean().setBlockState((BlockState) this.stateCB.getSelectedItem()); - repaint(); + blockTile.setBlockState((BlockState) stateCB.getSelectedItem()); }//GEN-LAST:event_stateCBActionPerformed private void showCenterCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showCenterCBActionPerformed - //Reset the logical direction - ((Block) blockTile).getBlockBean().setLogicalDirection(null); - repaint(); + blockTile.setDrawCenterPoint(this.showCenterCB.isSelected()); }//GEN-LAST:event_showCenterCBActionPerformed - private String getDepartureSuffix() { - if (((Block) blockTile).getBlockBean() != null && ((Block) blockTile).getBlockBean().getDepartureSuffix() != null && !"".equals(((Block) blockTile).getBlockBean().getDepartureSuffix())) { - return ((Block) blockTile).getBlockBean().getDepartureSuffix(); - } else { - return "+"; - } - } +// private String getDepartureSuffix() { +// return this.blockTile.getDepartureSuffix(); +// } private void reverseArrivalCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_reverseArrivalCBActionPerformed - ((Block) blockTile).getBlockBean().setReverseArrival(this.reverseArrivalCB.isSelected()); - - //The Suffix is orientation dependent! -// if ("+".equals(((Block) blockTile).getBlockBean().getArrivalSuffix())) { -// ((Block) blockTile).getBlockBean().setArrivalSuffix("-"); -// } else { -// ((Block) blockTile).getBlockBean().setArrivalSuffix("+"); -// } -// this.departureSideCB.setSelectedItem(((Block) blockTile).getBlockBean().getArrivalSuffix()); - repaint(); + blockTile.setReverseArrival(reverseArrivalCB.isSelected()); }//GEN-LAST:event_reverseArrivalCBActionPerformed private void backwardsRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_backwardsRBActionPerformed - if (((Block) blockTile).getBlockBean().getLocomotive() != null) { - //((Block) blockTile).getBlockBean().getLocomotive().setDispatcherDirection(LocomotiveBean.Direction.BACKWARDS); - ((Block) blockTile).getBlockBean().setLogicalDirection(LocomotiveBean.Direction.BACKWARDS.getDirection()); - repaint(); - } + blockTile.setLogicalDirection(LocomotiveBean.Direction.BACKWARDS); }//GEN-LAST:event_backwardsRBActionPerformed private void forwardsRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_forwardsRBActionPerformed - if (((Block) blockTile).getBlockBean().getLocomotive() != null) { - //((Block) blockTile).getBlockBean().getLocomotive().setDispatcherDirection(LocomotiveBean.Direction.FORWARDS); - ((Block) blockTile).getBlockBean().setLogicalDirection(LocomotiveBean.Direction.FORWARDS.getDirection()); - repaint(); - } + blockTile.setLogicalDirection(LocomotiveBean.Direction.FORWARDS); }//GEN-LAST:event_forwardsRBActionPerformed private void scaleCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_scaleCBActionPerformed - if (this.scaleCB.isSelected()) { - blockTile.setScaleImage(false); - } else { - blockTile.setScaleImage(true); - } - repaint(); + Logger.trace("\nBlok is expanded " + this.scaleCB.isSelected()); + blockTile.setScaleImage(!scaleCB.isSelected()); + canvas.setExpanded(scaleCB.isSelected()); + + //Shift the tile a bit to fit on the canvas +// if(!scaleCB.isSelected()) { +// blockTile.setCenter(new Point(620, 180)); +// } else { +// blockTile.setCenter(new Point(620, 140)); +// } + }//GEN-LAST:event_scaleCBActionPerformed private void centerSPComponentResized(java.awt.event.ComponentEvent evt) {//GEN-FIRST:event_centerSPComponentResized @@ -434,8 +398,8 @@ public static void main(String args[]) { UnscaledBlockTester app = new UnscaledBlockTester(); app.setTitle("Unscaled Tile Tester"); app.setLocationRelativeTo(null); - app.pack(); + //app.pack(); }); } From 14df7ec66e764eaf865c50215a5e05aea32a0f59 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Fri, 24 Jan 2025 23:41:15 +0100 Subject: [PATCH 05/70] More refactoring, Still issue with Block, it is continuously painting --- .../java/jcs/entities/LocomotiveBean.java | 6 +- src/main/java/jcs/ui/layout/LayoutCanvas.form | 4 +- src/main/java/jcs/ui/layout/LayoutCanvas.java | 268 +++--- src/main/java/jcs/ui/layout/LayoutPanel.form | 10 +- src/main/java/jcs/ui/layout/LayoutPanel.java | 3 +- src/main/java/jcs/ui/layout/LayoutUtil.java | 21 - src/main/java/jcs/ui/layout/TileCache.java | 6 +- src/main/java/jcs/ui/layout/tiles/Block.java | 222 ++--- .../java/jcs/ui/layout/tiles/Crossing.java | 32 +- src/main/java/jcs/ui/layout/tiles/Curved.java | 32 +- .../jcs/ui/layout/tiles/DefaultTileModel.java | 14 +- src/main/java/jcs/ui/layout/tiles/End.java | 32 +- .../java/jcs/ui/layout/tiles/Straight.java | 32 +- src/main/java/jcs/ui/layout/tiles/Switch.java | 32 +- src/main/java/jcs/ui/layout/tiles/Tile.java | 905 +++++++++--------- .../java/jcs/ui/layout/tiles/TileModel.java | 4 + .../jcs/ui/layout/tiles/BlockTileTester.java | 10 +- .../jcs/ui/layout/tiles/DotGridCanvas.java | 1 + .../ui/layout/tiles/UnscaledBlockCanvas.java | 6 +- .../ui/layout/tiles/UnscaledBlockTester.java | 46 +- 20 files changed, 831 insertions(+), 855 deletions(-) diff --git a/src/main/java/jcs/entities/LocomotiveBean.java b/src/main/java/jcs/entities/LocomotiveBean.java index a11b8c59..74f66cb8 100644 --- a/src/main/java/jcs/entities/LocomotiveBean.java +++ b/src/main/java/jcs/entities/LocomotiveBean.java @@ -525,7 +525,11 @@ public String getDirection() { } public static Direction get(String direction) { - return ENUM_MAP.get(direction); + if (direction != null) { + return ENUM_MAP.get(direction); + } else { + return null; + } } private static int translate2MarklinValue(String value) { diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.form b/src/main/java/jcs/ui/layout/LayoutCanvas.form index 4a20d061..884eba14 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.form +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.form @@ -194,13 +194,11 @@ - + - - diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.java b/src/main/java/jcs/ui/layout/LayoutCanvas.java index fa7d4a8c..67f95120 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.java +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.java @@ -21,6 +21,7 @@ import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; +import java.awt.Paint; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -35,6 +36,7 @@ import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import javax.swing.DebugGraphics; import javax.swing.JFrame; import javax.swing.JMenuItem; import javax.swing.JPanel; @@ -80,7 +82,7 @@ * This canvas / Panel is used to draw the layout * */ -public class LayoutCanvas extends JPanel implements PropertyChangeListener { +public class LayoutCanvas extends JPanel { //implements PropertyChangeListener { public enum Mode { SELECT, @@ -123,6 +125,10 @@ public LayoutCanvas() { } public LayoutCanvas(boolean readonly) { + setLayout(null); + setOpaque(true); + setDoubleBuffered(true); + this.readonly = readonly; // this.tiles = new HashMap<>(); // this.altTiles = new HashMap<>(); @@ -147,64 +153,85 @@ private void postInit() { } @Override - protected void paintComponent(Graphics g) { + public void paint(Graphics g) { long started = System.currentTimeMillis(); - super.paintComponent(g); - Graphics2D g2 = (Graphics2D) g.create(); - Set snapshot = new HashSet<>(TileCache.tiles.values()); + //for (Tile tile : TileCache.tiles.values()) { + // tile.setSelected(selectedTiles.contains(tile.getCenter())); + //} - if (this.drawGrid) { - if (lineGrid) { - paintLineGrid(g); - } else { - paintDotGrid(g); - } - } else { - paintNullGrid(g); - } - - for (Tile tile : snapshot) { - //for (Tile tile : TileCache.tiles.values()) { - //tile.setDrawOutline(drawGrid); - - if (Mode.CONTROL != mode) { - if (selectedTiles.contains(tile.getCenter())) { - //tile.setBackgroundColor(Color.yellow); - tile.setBackgroundColor(Color.orange); - } else { - tile.setBackgroundColor(Color.white); - } - } + //paintNullGrid(g); + super.paint(g); - tile.drawTile(g2); - //debug -// if (!this.readonly) { -// tile.drawCenterPoint(g2, Color.magenta, 3); -// } + if (drawGrid) { + //if (lineGrid) { + // paintLineGrid(g); + //} else { + paintDotGrid(g); + //} } - if (this.movingTileCenterPoint != null && this.movingTileImage != null) { - int x = movingTileCenterPoint.x; - int y = movingTileCenterPoint.y; - int w = movingTileImage.getWidth(); - int h = movingTileImage.getHeight(); - g2.drawImage(movingTileImage, (x - w / 2), (y - h / 2), null); - } + long now = System.currentTimeMillis(); + Logger.trace("Duration: " + (now - started) + " ms."); + } - g2.dispose(); + @Override + protected void paintComponent(Graphics g) { + long started = System.currentTimeMillis(); + super.paintComponent(g); +// Graphics2D g2 = (Graphics2D) g.create(); +// Set snapshot = new HashSet<>(TileCache.tiles.values()); +// +// if (this.drawGrid) { +// if (lineGrid) { +// paintLineGrid(g); +// } else { +// paintDotGrid(g); +// } +// } else { +// paintNullGrid(g); +// } +// +// for (Tile tile : snapshot) { +// //for (Tile tile : TileCache.tiles.values()) { +// //tile.setDrawOutline(drawGrid); +// +// if (Mode.CONTROL != mode) { +// if (selectedTiles.contains(tile.getCenter())) { +// //tile.setBackgroundColor(Color.yellow); +// tile.setBackgroundColor(Color.orange); +// } else { +// tile.setBackgroundColor(Color.white); +// } +// } +// +// //tile.drawTile(g2); +// //debug +//// if (!this.readonly) { +//// tile.drawCenterPoint(g2, Color.magenta, 3); +//// } +// } +// if (this.movingTileCenterPoint != null && this.movingTileImage != null) { +// int x = movingTileCenterPoint.x; +// int y = movingTileCenterPoint.y; +// int w = movingTileImage.getWidth(); +// int h = movingTileImage.getHeight(); +// g2.drawImage(movingTileImage, (x - w / 2), (y - h / 2), null); +// } +// +// g2.dispose(); long now = System.currentTimeMillis(); Logger.trace("Duration: " + (now - started) + " ms."); } - @Override + //@Override public void propertyChange(PropertyChangeEvent evt) { if ("repaintTile".equals(evt.getPropertyName())) { Tile tile = (Tile) evt.getNewValue(); Logger.trace("Repainting Tile: " + tile.getId()); - repaint(tile.getBounds()); +// repaint(tile.getBounds()); } } @@ -239,40 +266,58 @@ private void paintNullGrid(Graphics g) { } private void paintDotGrid(Graphics g) { - if (this.grid != null) { - int pw = this.getWidth(); - int ph = this.getHeight(); - - int gw = grid.getWidth(); - int gh = grid.getHeight(); - - if (pw != gw || ph != gh) { - //Logger.trace("Changed Canvas: " + pw + " x " + ph + " Grid: " + gw + " x " + gh); - this.grid = null; - } else { - } - } - - if (this.grid == null) { - int width = getSize().width; - int height = getSize().height; - grid = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); - Graphics2D gc = grid.createGraphics(); + int width = this.getWidth(); + int height = this.getHeight(); - gc.setBackground(Color.white); - gc.clearRect(0, 0, width, height); + int xOffset = 0; + int yOffset = 0; - gc.setPaint(Color.black); + //Logger.trace("W: " + width + " H: " + height + " X: " + this.getX() + " Y: " + this.getY()); + Graphics2D gc = (Graphics2D) g; + Paint p = gc.getPaint(); + gc.setPaint(Color.black); - for (int r = 0; r < width; r++) { - for (int c = 0; c < height; c++) { - gc.drawOval(r * Tile.GRID * 2, c * Tile.GRID * 2, 1, 1); - } + for (int r = 0; r < width; r++) { + for (int c = 0; c < height; c++) { + gc.drawOval((r * 20 * 2) + xOffset - 2, (c * 20 * 2) + yOffset - 2, 4, 4); } - gc.dispose(); } - Graphics2D g2 = (Graphics2D) g; - g2.drawImage(grid, null, 0, 0); + gc.setPaint(p); + +// if (this.grid != null) { +// int pw = this.getWidth(); +// int ph = this.getHeight(); +// +// int gw = grid.getWidth(); +// int gh = grid.getHeight(); +// +// if (pw != gw || ph != gh) { +// //Logger.trace("Changed Canvas: " + pw + " x " + ph + " Grid: " + gw + " x " + gh); +// this.grid = null; +// } else { +// } +// } +// +// if (this.grid == null) { +// int width = getSize().width; +// int height = getSize().height; +// grid = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); +// Graphics2D gc = grid.createGraphics(); +// +// gc.setBackground(Color.white); +// gc.clearRect(0, 0, width, height); +// +// gc.setPaint(Color.black); +// +// for (int r = 0; r < width; r++) { +// for (int c = 0; c < height; c++) { +// gc.drawOval(r * Tile.GRID * 2, c * Tile.GRID * 2, 1, 1); +// } +// } +// gc.dispose(); +// } +// Graphics2D g2 = (Graphics2D) g; +// g2.drawImage(grid, null, 0, 0); } private void paintLineGrid(Graphics g) { @@ -347,7 +392,7 @@ void loadLayoutInBackground() { private void loadTiles() { boolean showValues = Mode.CONTROL.equals(mode); - TileCache.loadTiles(this); + TileCache.loadTiles(); TileCache.setShowValues(showValues); //TileCache.setDrawOutline(drawGrid); TileCache.setDrawCenterPoint(!this.readonly); @@ -450,12 +495,21 @@ private Tile getSelectedTile() { private void mousePressedAction(MouseEvent evt) { Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); - Tile tile = TileCache.findTile(snapPoint); //Clear any previous selection + for(Point p : selectedTiles) { + if(TileCache.containsPoint(p)) { + Tile st = TileCache.findTile(p); + st.setSelected(false); + } + } + selectedTiles.clear(); + Tile tile = TileCache.findTile(snapPoint); + if (tile != null) { selectedTiles.addAll(tile.getAllPoints()); + tile.setSelected(true); } switch (mode) { @@ -481,9 +535,11 @@ private void mousePressedAction(MouseEvent evt) { if (addedTile != null) { selectedTiles.addAll(addedTile.getAllPoints()); - if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { - this.saveTile(tile); - } + //if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { + //this.saveTile(tile); + this.add(addedTile); + repaint(); + //} } } else { if (tile != null) { @@ -495,11 +551,17 @@ private void mousePressedAction(MouseEvent evt) { if (MouseEvent.BUTTON3 == evt.getButton() && tile != null) { showOperationsPopupMenu(tile, snapPoint); } - repaint(); + } case DELETE -> { //removeTiles(selectedTiles); - TileCache.removeTiles(selectedTiles); + //TileCache.removeTiles(selectedTiles); + Tile t = (Tile) this.getComponentAt(snapPoint); + if (t != null) { + this.remove(t); + TileCache.deleteTile(t); + } + this.selectedTiles.clear(); repaint(); } @@ -911,34 +973,11 @@ private Tile addTile(Point p) { Tile tile = TileFactory.createTile(tileType, orientation, direction, chkp, drawGrid); //Can the tile be placed, keeping in mind the extra points - boolean canBeAdded = TileCache.checkTileOccupation(tile); + boolean canBeAdded = !TileCache.checkTileOccupation(tile); -// if (!tile.getAltPoints().isEmpty()) { -// //Check if the extra point positions are not occupied -// Set tilePoints = tile.getAllPoints(); -// -// for (Point tp : tilePoints) { -// if (TileCache.containsPoint(tp)) { -// Logger.trace("Point " + p + " occupied by " + TileCache.findTile(p).getId() + " Can't add new Tile: " + tile); -// canBeAdded = false; -// } -// } -// } if (canBeAdded) { TileCache.addTile(tile); -// TileCache.tiles.put(chkp, tile); -// //Alternative point(s) to be able to find all points -// if (!tile.getAltPoints().isEmpty()) { -// Set alt = tile.getAltPoints(); -// for (Point ap : alt) { -// TileCache.altTiles.put(ap, tile); -// } -// } -// -// if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { -// this.saveTile(tile); -// } Logger.trace("Added Tile " + tile.getClass().getSimpleName() + " " + tile.getOrientation() + " @ " + tile.getCenter() + " Full repaint: " + fullRepaint); } @@ -1306,10 +1345,8 @@ public void actionPerformed(ActionEvent evt) { }); blockPopupMenu.add(blockPropertiesMI); - setBackground(new Color(250, 250, 250)); - setAutoscrolls(true); + setBackground(new Color(255, 255, 255)); setMinimumSize(new Dimension(1398, 848)); - setOpaque(false); setPreferredSize(new Dimension(1398, 848)); addMouseMotionListener(new MouseMotionAdapter() { public void mouseDragged(MouseEvent evt) { @@ -1483,7 +1520,7 @@ private void reverseArrivalSideMIActionPerformed(ActionEvent evt) {//GEN-FIRST:e block.getBlockBean().setReverseArrival(!block.getBlockBean().isReverseArrival()); this.executor.execute(() -> { PersistenceFactory.getService().persist(block.getBlockBean()); - block.repaintTile(); + //block.repaintTile(); }); } }//GEN-LAST:event_reverseArrivalSideMIActionPerformed @@ -1504,7 +1541,7 @@ private void toggleLocomotiveDirectionMIActionPerformed(ActionEvent evt) {//GEN- this.executor.execute(() -> { PersistenceFactory.getService().persist(block.getTileBean()); - block.repaintTile(); + //block.repaintTile(); }); } }//GEN-LAST:event_toggleLocomotiveDirectionMIActionPerformed @@ -1512,17 +1549,18 @@ private void toggleLocomotiveDirectionMIActionPerformed(ActionEvent evt) {//GEN- private void toggleOutOfOrderMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_toggleOutOfOrderMIActionPerformed if (this.selectedTile != null) { Block block = (Block) selectedTile; - BlockBean.BlockState currentState = block.getBlockState(); - if (BlockBean.BlockState.FREE == currentState) { - block.setBlockState(BlockBean.BlockState.OUT_OF_ORDER); - } else if (BlockBean.BlockState.OUT_OF_ORDER == currentState) { - block.setBlockState(BlockBean.BlockState.FREE); + BlockState currentState = block.getBlockState(); + if (BlockState.FREE == currentState) { + block.setBlockState(BlockState.OUT_OF_ORDER); + } else if (BlockState.OUT_OF_ORDER == currentState) { + block.setBlockState(BlockState.FREE); } - if (currentState != block.getRouteBlockState()) { + if (currentState != block.getBlockState()) { //getRouteBlockState()) { this.executor.execute(() -> { PersistenceFactory.getService().persist(block.getBlockBean()); - block.repaintTile(); + //block.repaintTile(); + }); } } @@ -1540,7 +1578,7 @@ private void resetGhostMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_res } this.executor.execute(() -> { PersistenceFactory.getService().persist(block.getBlockBean()); - block.repaintTile(); + //block.repaintTile(); }); } } diff --git a/src/main/java/jcs/ui/layout/LayoutPanel.form b/src/main/java/jcs/ui/layout/LayoutPanel.form index 7fc284b9..1386e2e4 100755 --- a/src/main/java/jcs/ui/layout/LayoutPanel.form +++ b/src/main/java/jcs/ui/layout/LayoutPanel.form @@ -1034,13 +1034,21 @@ + + + + + + - + + + diff --git a/src/main/java/jcs/ui/layout/LayoutPanel.java b/src/main/java/jcs/ui/layout/LayoutPanel.java index dc8936c2..8a942a81 100755 --- a/src/main/java/jcs/ui/layout/LayoutPanel.java +++ b/src/main/java/jcs/ui/layout/LayoutPanel.java @@ -811,8 +811,9 @@ public void actionPerformed(ActionEvent evt) { canvasScrollPane.setPreferredSize(new Dimension(1024, 850)); canvasScrollPane.setViewportView(canvas); + canvas.setMinimumSize(new Dimension(800, 700)); canvas.setName(""); // NOI18N - canvas.setLayout(new BorderLayout()); + canvas.setPreferredSize(new Dimension(800, 700)); canvasScrollPane.setViewportView(canvas); add(canvasScrollPane, BorderLayout.CENTER); diff --git a/src/main/java/jcs/ui/layout/LayoutUtil.java b/src/main/java/jcs/ui/layout/LayoutUtil.java index a1e723a2..14a1361b 100644 --- a/src/main/java/jcs/ui/layout/LayoutUtil.java +++ b/src/main/java/jcs/ui/layout/LayoutUtil.java @@ -17,11 +17,6 @@ import jcs.ui.layout.tiles.Tile; import java.awt.Point; -import jcs.entities.TileBean.Orientation; -import static jcs.ui.layout.tiles.Block.BLOCK_HEIGHT; -import static jcs.ui.layout.tiles.Block.BLOCK_WIDTH; -import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; -import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; public class LayoutUtil { @@ -77,20 +72,4 @@ public static double euclideanDistance(Point p1, Point p2) { return d; } - public static int blockWidth(Orientation orientation) { - if (Orientation.EAST == orientation || Orientation.WEST == orientation) { - return BLOCK_WIDTH; - } else { - return DEFAULT_WIDTH; - } - } - - public static int blockHeight(Orientation orientation) { - if (Orientation.EAST == orientation || Orientation.WEST == orientation) { - return DEFAULT_HEIGHT; - } else { - return BLOCK_HEIGHT; - } - } - } diff --git a/src/main/java/jcs/ui/layout/TileCache.java b/src/main/java/jcs/ui/layout/TileCache.java index 28b78f8f..566d9605 100644 --- a/src/main/java/jcs/ui/layout/TileCache.java +++ b/src/main/java/jcs/ui/layout/TileCache.java @@ -113,7 +113,7 @@ public static void setShowValues(boolean showValues) { } } - static void loadTiles(PropertyChangeListener listener) { + static void loadTiles() { List tileBeans = PersistenceFactory.getService().getTileBeans(); tileEventListeners.clear(); @@ -124,7 +124,7 @@ static void loadTiles(PropertyChangeListener listener) { Tile tile = TileFactory.createTile(tb, showValues); //tile.setPropertyChangeListener(listener); tiles.put(tile.getCenter(), tile); - addTileEventListener((TileEventListener) tile); + //addTileEventListener((TileEventListener) tile); //Alternative point(s) to be able to find all points if (!tile.getAltPoints().isEmpty()) { @@ -145,7 +145,7 @@ static List getTiles() { static void addTile(Tile tile) { tiles.put(tile.getCenter(), tile); - addTileEventListener((TileEventListener) tile); + //addTileEventListener((TileEventListener) tile); //Alternative point(s) to be able to find all points if (!tile.getAltPoints().isEmpty()) { diff --git a/src/main/java/jcs/ui/layout/tiles/Block.java b/src/main/java/jcs/ui/layout/tiles/Block.java index 0e315910..d150243c 100755 --- a/src/main/java/jcs/ui/layout/tiles/Block.java +++ b/src/main/java/jcs/ui/layout/tiles/Block.java @@ -24,6 +24,7 @@ import java.awt.Image; import java.awt.Point; import java.awt.geom.Ellipse2D; +import java.awt.image.BufferedImage; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -38,10 +39,6 @@ import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; -import jcs.ui.layout.LayoutUtil; -import static jcs.ui.layout.LayoutUtil.blockHeight; -import static jcs.ui.layout.LayoutUtil.blockWidth; -import jcs.ui.layout.events.TileEvent; import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; import static jcs.ui.layout.tiles.Tile.RENDER_HEIGHT; @@ -54,12 +51,13 @@ public class Block extends Tile { public static final int BLOCK_WIDTH = DEFAULT_WIDTH * 3; public static final int BLOCK_HEIGHT = DEFAULT_HEIGHT * 3; - protected BlockState routeBlockState; - public Block(TileBean tileBean) { - super(tileBean, LayoutUtil.blockWidth(tileBean.getOrientation()), LayoutUtil.blockHeight(tileBean.getOrientation())); + super(tileBean); setModel(new DefaultTileModel()); + changeRenderSize(); + + populateModel(); } public Block(Orientation orientation, Point center) { @@ -67,7 +65,7 @@ public Block(Orientation orientation, Point center) { } public Block(Orientation orientation, int x, int y) { - this(orientation, x, y, LayoutUtil.blockWidth(orientation), LayoutUtil.blockHeight(orientation)); + this(orientation, x, y, tileWidth(orientation, TileType.BLOCK), tileHeight(orientation, TileType.BLOCK)); } public Block(Orientation orientation, int x, int y, int width, int height) { @@ -289,8 +287,8 @@ public String getIdSuffix(Tile other) { @Override public Orientation rotate() { rotate(false); - int w = LayoutUtil.blockWidth(tileOrientation); - int h = LayoutUtil.blockHeight(tileOrientation); + int w = tileWidth(tileOrientation, TileType.BLOCK); + int h = tileHeight(tileOrientation, TileType.BLOCK); Dimension d = new Dimension(w, h); setPreferredSize(d); @@ -334,14 +332,6 @@ protected Color getBlockStateColor(BlockState blockState) { }; } - public void setRouteBlockState(BlockState routeBlockState) { - this.routeBlockState = routeBlockState; - } - - public BlockState getRouteBlockState() { - return routeBlockState; - } - public static String getDepartureSuffix(Orientation tileOrientation, boolean reverseArrival, LocomotiveBean.Direction direction) { if (LocomotiveBean.Direction.FORWARDS == direction) { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { @@ -397,7 +387,7 @@ public void renderTile(Graphics2D g2) { //When there is a locomotive in the block mark the direction of travel. //The default, forwards is in the direction of the block orientation, i.e. the + - if (getBlockBean() != null && getBlockBean().getLocomotive() != null && getBlockBean().getLocomotive().getName() != null) { + if (model.getLocomotive() != null && model.getLocomotive().getName() != null) { renderDirectionArrow(g2); } @@ -406,25 +396,24 @@ public void renderTile(Graphics2D g2) { private void renderDirectionArrow(Graphics2D g2) { //The default, forwards is in the direction of the block orientation, i.e. the + - Orientation orientation = this.getOrientation(); BlockBean bb = this.getBlockBean(); - boolean reverseArrival = bb.isReverseArrival(); + boolean reverseArrival = model.isReverseArrival(); LocomotiveBean.Direction logicalDirection; if (bb.getLogicalDirection() != null) { - logicalDirection = LocomotiveBean.Direction.get(bb.getLogicalDirection()); + logicalDirection = model.getLogicalDirection(); } else { - logicalDirection = bb.getLocomotive().getDirection(); + logicalDirection = model.getLocomotive().getDirection(); } - String departureSuffix = bb.getDepartureSuffix(); + String departureSuffix = model.getDepartureSuffix(); if (departureSuffix == null) { - departureSuffix = Block.getDepartureSuffix(orientation, reverseArrival, logicalDirection); + departureSuffix = Block.getDepartureSuffix(tileOrientation, reverseArrival, logicalDirection); } //Logger.trace(this.getId()+" LogicalDirection is " + (bb.getLogicalDirection() != null ? "Set" : "Not Set") + " Dir: " + logicalDirection.getDirection() + " Orientation: " + orientation.getOrientation() + " departureSuffix: " + departureSuffix); if ("+".equals(departureSuffix)) { - if (Orientation.EAST == orientation || Orientation.SOUTH == orientation) { + if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { switch (logicalDirection) { case LocomotiveBean.Direction.FORWARDS -> { if (reverseArrival) { @@ -460,7 +449,7 @@ private void renderDirectionArrow(Graphics2D g2) { } } } else { - if (Orientation.EAST == orientation || Orientation.SOUTH == orientation) { + if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { switch (logicalDirection) { case LocomotiveBean.Direction.FORWARDS -> { if (reverseArrival) { @@ -510,172 +499,140 @@ private void renderRightArrow(Graphics2D g2) { @Override public void renderTileRoute(Graphics2D g2d) { - if (routeBlockState != null) { - backgroundColor = getBlockStateColor(routeBlockState); + if (model.isShowBlockState()) { + backgroundColor = getBlockStateColor(model.getBlockState()); } } - protected void overlayLocImage(Graphics2D g2d) { - Image locImage = getLocImage(); - String departureSuffix = null; - boolean reverseImage = true; - if (getBlockBean() != null) { - reverseImage = getBlockBean().isReverseArrival(); - } + protected void overlayLocImage() { + int ww = tileImage.getWidth(); + int hh = tileImage.getHeight(); - if (getBlockBean() != null) { - departureSuffix = getBlockBean().getDepartureSuffix(); - } + BufferedImage overlay = new BufferedImage(ww, hh, BufferedImage.TYPE_INT_ARGB); + Graphics2D g2i = overlay.createGraphics(); + + Image locImage = getLocImage(); if (locImage != null) { + String departureSuffix = model.getDepartureSuffix(); + boolean reverseImage = model.isReverseArrival(); + + Logger.trace("LocImage w: " + locImage.getWidth(null) + " h: " + locImage.getHeight(null)); // scale it to max h of 45 int size = 45; float aspect = (float) locImage.getHeight(null) / (float) locImage.getWidth(null); //TODO: Use Scalr? locImage = locImage.getScaledInstance(size, (int) (size * aspect), Image.SCALE_SMOOTH); - //Logger.trace("LocImage w: " + w + " h: " + h); //Depending on the block orientation the image needs to be rotated and flipped //Incase the departure suffix is NOT set center the locomotive image + int w, h, xx, yy; switch (tileOrientation) { case WEST -> { - int xx; - int w = locImage.getWidth(null); - int h = locImage.getHeight(null); + w = locImage.getWidth(null); + h = locImage.getHeight(null); if (null == departureSuffix) { - xx = tileX - getWidth() / 2 + w; + xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w; } else { switch (departureSuffix) { case "+" -> { - xx = tileX - getWidth() / 2 + w - 25; + xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w - 25; } default -> { - xx = tileX - getWidth() / 2 + w + 10; + xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w + 10; } } } - int yy = tileY - h / 2; + yy = DEFAULT_HEIGHT / 2 - h / 2; if (reverseImage) { locImage = ImageUtil.flipVertically(locImage); } - g2d.drawImage(locImage, xx, yy, null); } case SOUTH -> { locImage = ImageUtil.flipHorizontally(locImage); locImage = ImageUtil.rotate(locImage, 90); - int w = locImage.getWidth(null); - int h = locImage.getHeight(null); + w = locImage.getWidth(null); + h = locImage.getHeight(null); + xx = DEFAULT_WIDTH / 2 - w / 2; - int xx = tileX - w / 2; - int yy; if (null == departureSuffix) { - yy = tileY - getHeight() / 2 + h; + yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h; } else { switch (departureSuffix) { case "-" -> { - yy = tileY - getHeight() / 2 + h - 25; + yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h - 25; } default -> { - yy = tileY - getHeight() / 2 + h + 10; + yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h + 10; } } } if (reverseImage) { locImage = ImageUtil.flipHorizontally(locImage); } - g2d.drawImage(locImage, xx, yy, null); + //g2d.drawImage(locImage, xx, yy, null); } case NORTH -> { locImage = ImageUtil.flipHorizontally(locImage); locImage = ImageUtil.rotate(locImage, 90); - int w = locImage.getWidth(null); - int h = locImage.getHeight(null); + w = locImage.getWidth(null); + h = locImage.getHeight(null); + xx = DEFAULT_WIDTH / 2 - w / 2; - int xx = tileX - w / 2; - int yy; if (null == departureSuffix) { - int minY = tileY - getHeight() / 2 + h; + int minY = BLOCK_HEIGHT / 2 - getHeight() / 2 + h; yy = minY; } else { switch (departureSuffix) { case "+" -> { - yy = tileY - getHeight() / 2 + h - 25; + yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h - 25; } default -> { - yy = tileY - getHeight() / 2 + h + 10; + yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h + 10; } } } if (reverseImage) { locImage = ImageUtil.flipHorizontally(locImage); } - g2d.drawImage(locImage, xx, yy, null); } default -> { - //EAST - int xx; - int w = locImage.getWidth(null); - int h = locImage.getHeight(null); - + w = locImage.getWidth(null); + h = locImage.getHeight(null); if (null == departureSuffix) { - xx = tileX - getWidth() / 2 + w; + xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w; } else { switch (departureSuffix) { case "-" -> { - xx = tileX - getWidth() / 2 + w - 25; + xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w - 25; } default -> { - xx = tileX - getWidth() / 2 + w + 10; + xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w + 10; } } } - int yy = tileY - h / 2; + yy = DEFAULT_HEIGHT / 2 - h / 2; if (reverseImage) { locImage = ImageUtil.flipVertically(locImage); } - g2d.drawImage(locImage, xx, yy, null); } } - } - } - /** - * Overridden to overlay a locomotive Icon - * - * @param g2d The graphics handle - */ - @Override - public void drawTile(Graphics2D g2d) { - super.drawTile(g2d); - if (getLocImage() != null) { - overlayLocImage(g2d); + g2i.drawImage(tileImage, 0, 0, null); + g2i.drawImage(locImage, xx, yy, null); + g2i.dispose(); + tileImage = overlay; } - } - @Override - public void onTileChange(TileEvent tileEvent) { - //TODO: Does not yet work for route block status change - Color pb = this.backgroundColor; - super.onTileChange(tileEvent); - if (!pb.equals(backgroundColor)) { - repaint(); - } } private Image getLocImage() { - if (blockBean != null && blockBean.getLocomotive() != null && blockBean.getLocomotive().getLocIcon() != null) { - //Do not show the image in block state FREE, OUT_OF_ORDER and LOCKED - BlockState blockState = blockBean.getBlockState(); - boolean showImage = !(BlockState.FREE == blockState || BlockState.LOCKED == blockState || BlockState.OUT_OF_ORDER == blockState || BlockState.GHOST == blockState); - if (showImage) { - return blockBean.getLocomotive().getLocIcon(); - } else { - return null; - } + if (model.getLocomotive() != null && model.getLocomotive().getLocIcon() != null) { + return model.getLocomotive().getLocIcon(); } else { return null; } @@ -683,20 +640,20 @@ private Image getLocImage() { public String getBlockText() { String blockText; - if (getBlockBean() != null && getBlockBean().getDescription() != null) { + if (blockBean != null && blockBean.getDescription() != null) { if (blockBean.getLocomotive() != null && blockBean.getLocomotive().getName() != null && BlockState.GHOST != blockBean.getBlockState()) { - blockText = getBlockBean().getLocomotive().getName(); + blockText = blockBean.getLocomotive().getName(); } else { - if (getBlockBean().getDescription().length() > 0) { - blockText = getBlockBean().getDescription(); + if (blockBean.getDescription().length() > 0) { + blockText = blockBean.getDescription(); } else { blockText = getId(); } } } else { // Design mode show description when available - if (getBlockBean() != null && getBlockBean().getDescription() != null && getBlockBean().getDescription().length() > 0) { - blockText = getBlockBean().getDescription(); + if (blockBean != null && blockBean.getDescription() != null && blockBean.getDescription().length() > 0) { + blockText = blockBean.getDescription(); } else { blockText = getId(); } @@ -706,9 +663,7 @@ public String getBlockText() { @Override public void drawName(Graphics2D g2d) { - Image locImage = getLocImage(); - - if (locImage == null) { + if (!model.isOverlayImage()) { g2d.setPaint(Color.black); Font currentFont = g2d.getFont(); @@ -729,7 +684,7 @@ public void drawName(Graphics2D g2d) { int textHeight = g2d.getFontMetrics().getHeight(); - switch (getOrientation()) { + switch (tileOrientation) { case EAST -> { drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) - textWidth / 2, RENDER_GRID + textHeight / 3, 0, blockText); } @@ -754,7 +709,7 @@ protected void paintComponent(Graphics g) { long started = System.currentTimeMillis(); super.paintComponent(g); - int multiplier = (model.isScaleImage() ? 1 : 10); + int multiplier = 1; //(model.isScaleImage() ? 1 : 10); int xx, yy; if (tileOrientation == Orientation.EAST || tileOrientation == Orientation.WEST) { xx = tileX - GRID * multiplier - GRID * multiplier * 2; @@ -764,21 +719,34 @@ protected void paintComponent(Graphics g) { yy = tileY - GRID * multiplier - GRID * multiplier * 2; } - if (model.isScaleImage()) { - setBounds(xx, yy, LayoutUtil.blockWidth(tileOrientation), LayoutUtil.blockHeight(tileOrientation)); - } else { - setBounds(xx, yy, renderWidth, renderHeight); - } + //if (model.isScaleImage()) { + setBounds(xx, yy, tileWidth(tileOrientation, TileType.BLOCK), tileHeight(tileOrientation, TileType.BLOCK)); + //setBounds(tileX - 60, tileY - 20, tileWidth(tileOrientation, TileType.BLOCK), tileHeight(tileOrientation, TileType.BLOCK)); + //} else { + //setBounds(xx, yy, renderWidth, renderHeight); + //} + + + //setBounds(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); - Logger.trace(id + ": " + tileOrientation + " W: " + getWidth() + " H: " + getHeight() + " tX: " + tileX + ", tY: " + tileY + " xx: " + xx + " yy: " + yy + " Scale factor: " + multiplier); + //Graphics2D g2 = (Graphics2D) g.create(); + //Graphics2D g2 = (Graphics2D) g.create(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); + + + //Logger.trace(id + ": " + tileOrientation + " W: " + getWidth() + " H: " + getHeight() + " tX: " + tileX + ", tY: " + tileY + " xx: " + xx + " yy: " + yy + " Scale factor: " + multiplier); Graphics2D g2 = (Graphics2D) g.create(); - //Graphics2D g2 = (Graphics2D) g; drawTile(g2); g2.dispose(); + if (model.isOverlayImage()) { + overlayLocImage(); + } + g.drawImage(tileImage, 0, 0, null); + //new Exception().printStackTrace() ; + long now = System.currentTimeMillis(); Logger.trace(id + " Duration: " + (now - started) + " ms."); } @@ -811,13 +779,9 @@ protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { g2d.fill(new Ellipse2D.Double(dX2, dY2, size, size)); g2d.fill(new Ellipse2D.Double(dX3, dY3, size / 2, size / 2)); -// g2d.setPaint(Color.black); -// g2d.setStroke(new BasicStroke(2, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); -// g2d.drawOval(renderWidth / 2 - 5, renderHeight / 2 - 5, 10, 10); - - Logger.trace(id + " dX2: " + dX2 + " dY2: " + dY2 + " O: " + tileOrientation + " rW: " + renderWidth + " rH:" + renderHeight + " Size: " + size); - Logger.trace(id + " dX1: " + dX1 + " dY1: " + dY1); - Logger.trace(id + " dX3: " + dX3 + " dY3: " + dY3); + //Logger.trace(id + " dX2: " + dX2 + " dY2: " + dY2 + " O: " + tileOrientation + " rW: " + renderWidth + " rH:" + renderHeight + " Size: " + size); + //Logger.trace(id + " dX1: " + dX1 + " dY1: " + dY1); + //Logger.trace(id + " dX3: " + dX3 + " dY3: " + dY3); } } diff --git a/src/main/java/jcs/ui/layout/tiles/Crossing.java b/src/main/java/jcs/ui/layout/tiles/Crossing.java index cacf54e1..c9813112 100644 --- a/src/main/java/jcs/ui/layout/tiles/Crossing.java +++ b/src/main/java/jcs/ui/layout/tiles/Crossing.java @@ -129,21 +129,21 @@ protected void renderRouteVertical(Graphics2D g2) { g2.fillRect(xxs, yys, w, h); } - @Override - public void renderTileRoute(Graphics2D g2) { - if (isHorizontal()) { - if (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide) { - renderRouteStraight(g2); - } else { - renderRouteVertical(g2); - } - } else { - if (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide) { - renderRouteStraight(g2); - } else { - renderRouteVertical(g2); - } - } - } +// @Override +// public void renderTileRoute(Graphics2D g2) { +// if (isHorizontal()) { +// if (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide) { +// renderRouteStraight(g2); +// } else { +// renderRouteVertical(g2); +// } +// } else { +// if (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide) { +// renderRouteStraight(g2); +// } else { +// renderRouteVertical(g2); +// } +// } +// } } diff --git a/src/main/java/jcs/ui/layout/tiles/Curved.java b/src/main/java/jcs/ui/layout/tiles/Curved.java index 450c8c06..1aad3e4b 100755 --- a/src/main/java/jcs/ui/layout/tiles/Curved.java +++ b/src/main/java/jcs/ui/layout/tiles/Curved.java @@ -144,21 +144,21 @@ public void renderTileRoute(Graphics2D g2) { g2.fillPolygon(xPoints, yPoints, xPoints.length); } - @Override - protected void paintComponent(Graphics g) { - long started = System.currentTimeMillis(); - super.paintComponent(g); - - setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); - - Graphics2D g2 = (Graphics2D) g.create(); - drawTile(g2); - g2.dispose(); - - g.drawImage(this.tileImage, 0, 0, null); - - long now = System.currentTimeMillis(); - Logger.trace(this.id + " Duration: " + (now - started) + " ms."); - } +// @Override +// protected void paintComponent(Graphics g) { +// long started = System.currentTimeMillis(); +// super.paintComponent(g); +// +// setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); +// +// Graphics2D g2 = (Graphics2D) g.create(); +// drawTile(g2); +// g2.dispose(); +// +// g.drawImage(this.tileImage, 0, 0, null); +// +// long now = System.currentTimeMillis(); +// Logger.trace(this.id + " Duration: " + (now - started) + " ms."); +// } } diff --git a/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java b/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java index c766c6d2..f584c651 100644 --- a/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java +++ b/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java @@ -52,6 +52,7 @@ public class DefaultTileModel implements TileModel { protected BlockState blockState; protected boolean reverseArrival; protected String arrivalSuffix; + protected boolean overlayImage = false; protected LocomotiveBean.Direction logicalDirection; protected LocomotiveBean locomotive; @@ -244,9 +245,16 @@ public void setLocomotive(LocomotiveBean locomotive) { fireStateChanged(); } - - - + @Override + public boolean isOverlayImage() { + return overlayImage; + } + + @Override + public void setOverlayImage(boolean overlayImage) { + this.overlayImage = overlayImage; + } + @Override public void addChangeListener(ChangeListener l) { listenerList.add(ChangeListener.class, l); diff --git a/src/main/java/jcs/ui/layout/tiles/End.java b/src/main/java/jcs/ui/layout/tiles/End.java index 91026af3..fd474844 100644 --- a/src/main/java/jcs/ui/layout/tiles/End.java +++ b/src/main/java/jcs/ui/layout/tiles/End.java @@ -131,21 +131,21 @@ public void renderTile(Graphics2D g2) { public void renderTileRoute(Graphics2D g2d) { } - @Override - protected void paintComponent(Graphics g) { - long started = System.currentTimeMillis(); - super.paintComponent(g); - - setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); - - Graphics2D g2 = (Graphics2D) g.create(); - drawTile(g2); - g2.dispose(); - - g.drawImage(this.tileImage, 0, 0, null); - - long now = System.currentTimeMillis(); - Logger.trace(this.id + " Duration: " + (now - started) + " ms."); - } +// @Override +// protected void paintComponent(Graphics g) { +// long started = System.currentTimeMillis(); +// super.paintComponent(g); +// +// setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); +// +// Graphics2D g2 = (Graphics2D) g.create(); +// drawTile(g2); +// g2.dispose(); +// +// g.drawImage(this.tileImage, 0, 0, null); +// +// long now = System.currentTimeMillis(); +// Logger.trace(this.id + " Duration: " + (now - started) + " ms."); +// } } diff --git a/src/main/java/jcs/ui/layout/tiles/Straight.java b/src/main/java/jcs/ui/layout/tiles/Straight.java index 6f8b3de6..8a45ba69 100755 --- a/src/main/java/jcs/ui/layout/tiles/Straight.java +++ b/src/main/java/jcs/ui/layout/tiles/Straight.java @@ -129,21 +129,21 @@ public void renderTile(Graphics2D g2) { renderStraight(g2); } - @Override - protected void paintComponent(Graphics g) { - long started = System.currentTimeMillis(); - super.paintComponent(g); - - setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); - - Graphics2D g2 = (Graphics2D) g.create(); - drawTile(g2); - g2.dispose(); - - g.drawImage(this.tileImage, 0, 0, null); - - long now = System.currentTimeMillis(); - Logger.trace(this.id + " Duration: " + (now - started) + " ms."); - } +// @Override +// protected void paintComponent(Graphics g) { +// long started = System.currentTimeMillis(); +// super.paintComponent(g); +// +// setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); +// +// Graphics2D g2 = (Graphics2D) g.create(); +// drawTile(g2); +// g2.dispose(); +// +// g.drawImage(this.tileImage, 0, 0, null); +// +// long now = System.currentTimeMillis(); +// Logger.trace(this.id + " Duration: " + (now - started) + " ms."); +// } } diff --git a/src/main/java/jcs/ui/layout/tiles/Switch.java b/src/main/java/jcs/ui/layout/tiles/Switch.java index 2a099a59..c75a4d45 100644 --- a/src/main/java/jcs/ui/layout/tiles/Switch.java +++ b/src/main/java/jcs/ui/layout/tiles/Switch.java @@ -341,20 +341,20 @@ public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { } } - @Override - protected void paintComponent(Graphics g) { - long started = System.currentTimeMillis(); - super.paintComponent(g); - - setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); - - Graphics2D g2 = (Graphics2D) g.create(); - drawTile(g2); - g2.dispose(); - - g.drawImage(this.tileImage, 0, 0, null); - - long now = System.currentTimeMillis(); - Logger.trace(this.id + " Duration: " + (now - started) + " ms."); - } +// @Override +// protected void paintComponent(Graphics g) { +// long started = System.currentTimeMillis(); +// super.paintComponent(g); +// +// setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); +// +// Graphics2D g2 = (Graphics2D) g.create(); +// drawTile(g2); +// g2.dispose(); +// +// g.drawImage(this.tileImage, 0, 0, null); +// +// long now = System.currentTimeMillis(); +// Logger.trace(this.id + " Duration: " + (now - started) + " ms."); +// } } diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java index dd068616..ae8f39f1 100755 --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -17,15 +17,14 @@ import java.awt.Color; import java.awt.Dimension; +import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; -import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.AffineTransform; import java.awt.geom.Ellipse2D; import java.awt.geom.PathIterator; -import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; @@ -52,8 +51,8 @@ import jcs.entities.TileBean.Orientation; import jcs.entities.TileBean.TileType; import jcs.ui.layout.LayoutUtil; -import jcs.ui.layout.events.TileEvent; -import jcs.ui.layout.events.TileEventListener; +import static jcs.ui.layout.tiles.Block.BLOCK_HEIGHT; +import static jcs.ui.layout.tiles.Block.BLOCK_WIDTH; import org.imgscalr.Scalr; import org.imgscalr.Scalr.Method; import org.imgscalr.Scalr.Mode; @@ -76,21 +75,21 @@ *

* A Tile is rendered to a Buffered Image to speed up the display */ -public abstract class Tile extends JComponent implements TileEventListener { //, ItemSelectable { +public abstract class Tile extends JComponent { //implements TileEventListener { //, ItemSelectable { public static final int GRID = 20; public static final int DEFAULT_WIDTH = GRID * 2; public static final int DEFAULT_HEIGHT = GRID * 2; - + static final int RENDER_GRID = GRID * 10; static final int RENDER_WIDTH = RENDER_GRID * 2; static final int RENDER_HEIGHT = RENDER_GRID * 2; - + public static final Color DEFAULT_BACKGROUND_COLOR = Color.white; public static final Color DEFAULT_TRACK_COLOR = Color.lightGray; public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.blue; public static final Color DEFAULT_SELECTED_COLOR = Color.yellow; - + public static final String MODEL_CHANGED_PROPERTY = "model"; public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled"; @@ -98,325 +97,362 @@ public abstract class Tile extends JComponent implements TileEventListener { //, * The data model that determines the button's state. */ protected TileModel model = null; - + protected String id; protected Integer tileX; protected Integer tileY; - + protected int renderWidth; protected int renderHeight; - + protected Orientation tileOrientation; protected Direction tileDirection; - + protected TileType tileType; protected String accessoryId; protected String sensorId; - + protected AccessoryValue accessoryValue; protected AccessoryValue routeValue; - + protected SignalType signalType; protected AccessoryBean.SignalValue signalValue; - + + protected TileBean tileBean; protected AccessoryBean accessoryBean; protected SensorBean sensorBean; protected BlockBean blockBean; - + protected List neighbours; - + protected int offsetX = 0; protected int offsetY = 0; - + protected int renderOffsetX = 0; protected int renderOffsetY = 0; - + protected Color selectedColor; protected Color trackColor; protected Color trackRouteColor; protected Orientation incomingSide; - + protected Color backgroundColor; protected boolean drawName = true; - + protected BufferedImage tileImage; - + protected PropertyChangeListener propertyChangeListener; - + protected ChangeListener changeListener = null; protected ActionListener actionListener = null; - //protected ItemListener itemListener = null; protected transient ChangeEvent changeEvent; - + private Handler handler; - //protected Tile(TileType tileType, Point center) { - // this(tileType, Orientation.EAST, Direction.CENTER, center.x, center.y, DEFAULT_WIDTH, DEFAULT_HEIGHT); - //} protected Tile(TileType tileType, Orientation orientation, Point center, int width, int height) { this(tileType, orientation, Direction.CENTER, center.x, center.y, width, height); } - + protected Tile(TileType tileType, Orientation orientation, int x, int y, int width, int height) { this(tileType, orientation, Direction.CENTER, x, y, width, height); } - + protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { this(tileType, orientation, direction, x, y, width, height, null, null); } - + protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height, Color backgroundColor, Color selectedColor) { this.tileType = tileType; this.tileOrientation = orientation; this.tileDirection = direction; this.tileX = x; this.tileY = y; - + setLayout(null); Dimension d = new Dimension(width, height); setSize(d); setPreferredSize(d); - - int w = getWidth(); - int h = getHeight(); - + + //int w = getWidth(); + //int h = getHeight(); this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT; - + this.trackColor = DEFAULT_TRACK_COLOR; this.backgroundColor = backgroundColor; this.selectedColor = selectedColor; - + if (this.backgroundColor == null) { this.backgroundColor = DEFAULT_BACKGROUND_COLOR; } if (this.selectedColor == null) { this.selectedColor = DEFAULT_SELECTED_COLOR; } - } - - protected Tile(Object tileBean) { - this(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); + + protected Tile(TileBean tileBean) { + //this(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); + this(tileBean, tileWidth(tileBean.getOrientation(), tileBean.getTileType()), tileHeight(tileBean.getOrientation(), tileBean.getTileType())); } - - protected Tile(Object tileBean, int width, int height) { - copyInto(tileBean); + + protected Tile(TileBean tileBean, int width, int height) { + this.tileBean = tileBean; + //Quick properties + this.id = tileBean.getId(); + this.tileType = tileBean.getTileType(); + this.tileOrientation = tileBean.getOrientation(); + this.tileDirection = tileBean.getDirection(); + this.tileX = tileBean.getX(); + this.tileY = tileBean.getY(); + + this.accessoryId = tileBean.getAccessoryId(); + this.accessoryBean = tileBean.getAccessoryBean(); + this.signalType = tileBean.getSignalType(); + + this.sensorId = tileBean.getSensorId(); + this.sensorBean = tileBean.getSensorBean(); + this.blockBean = tileBean.getBlockBean(); + setLayout(null); Dimension d = new Dimension(width, height); setSize(d); setPreferredSize(d); - + this.trackColor = DEFAULT_TRACK_COLOR; this.backgroundColor = DEFAULT_BACKGROUND_COLOR; this.selectedColor = DEFAULT_SELECTED_COLOR; this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT; } - - private void copyInto(Object object) { - if (object instanceof TileBean other) { - this.id = other.getId(); - this.tileType = other.getTileType(); - this.tileOrientation = other.getOrientation(); - this.tileOrientation = other.getOrientation(); - this.tileDirection = other.getDirection(); - this.tileDirection = other.getDirection(); - this.tileX = other.getX(); - this.tileY = other.getY(); - - this.signalType = other.getSignalType(); - this.accessoryId = other.getAccessoryId(); - this.sensorId = other.getSensorId(); - this.accessoryBean = other.getAccessoryBean(); - this.sensorBean = other.getSensorBean(); - this.blockBean = other.getBlockBean(); - - if (other.getAccessoryBean() != null) { - AccessoryBean ab = other.getAccessoryBean(); - this.signalType = SignalType.getSignalType(ab.getType()); + + protected static int tileWidth(Orientation orientation, TileType tileType) { + if (Orientation.EAST == orientation || Orientation.WEST == orientation) { + if (null == tileType) { + return DEFAULT_WIDTH; + } else { + return switch (tileType) { + case BLOCK -> + BLOCK_WIDTH; + case CROSS -> + DEFAULT_WIDTH * 2; + default -> + DEFAULT_WIDTH; + }; } - + } else { + return DEFAULT_WIDTH; } - - if (object instanceof Tile tile) { - this.renderWidth = tile.renderWidth; - this.renderHeight = tile.renderHeight; + } + + protected static int tileHeight(Orientation orientation, TileType tileType) { + if (Orientation.EAST == orientation || Orientation.WEST == orientation) { + return DEFAULT_HEIGHT; + } else { + if (null == tileType) { + return DEFAULT_HEIGHT; + } else { + return switch (tileType) { + case BLOCK -> + BLOCK_HEIGHT; + case CROSS -> + DEFAULT_HEIGHT * 2; + default -> + DEFAULT_HEIGHT; + }; + } } - } - + + protected void populateModel() { + if (this.blockBean != null) { + this.model.setBlockState(this.blockBean.getBlockState()); + this.model.setLocomotive(this.blockBean.getLocomotive()); + this.model.setArrivalSuffix(this.blockBean.getArrivalSuffix()); + this.model.setLogicalDirection(LocomotiveBean.Direction.get(this.blockBean.getLogicalDirection())); + } + } + public TileBean getTileBean() { - TileBean tb = new TileBean(); - tb.setId(this.id); - tb.setX(this.tileX); - tb.setY(this.tileY); - tb.setTileType(this.tileType); - tb.setTileOrientation(this.tileOrientation.getOrientation()); - tb.setTileDirection(this.tileDirection.getDirection()); - tb.setSignalType(this.signalType); - tb.setAccessoryId(this.accessoryId); - tb.setSensorId(this.sensorId); - tb.setAccessoryBean(this.accessoryBean); - tb.setSensorBean(this.sensorBean); - tb.setBlockBean(this.blockBean); - - return tb; - } - + if (tileBean == null) { + tileBean = new TileBean(); + tileBean.setId(this.id); + tileBean.setX(this.tileX); + tileBean.setY(this.tileY); + tileBean.setTileType(this.tileType); + tileBean.setTileOrientation(this.tileOrientation.getOrientation()); + tileBean.setTileDirection(this.tileDirection.getDirection()); + tileBean.setSignalType(this.signalType); + tileBean.setAccessoryId(this.accessoryId); + tileBean.setSensorId(this.sensorId); + tileBean.setAccessoryBean(this.accessoryBean); + tileBean.setSensorBean(this.sensorBean); + tileBean.setBlockBean(this.blockBean); + } + return tileBean; + } + public boolean isSelected() { return model.isSelected(); } - + public void setSelected(boolean b) { //boolean oldValue = isSelected(); model.setSelected(b); } - - @Override + + //@Override public String getId() { return id; } - + public void setId(String id) { this.id = id; } - + public SignalType getSignalType() { return signalType; } - + public void setSignalType(SignalType signalType) { this.signalType = signalType; } - + public Integer getTileX() { return tileX; } -// public void setTileX(Integer x) { -// this.tileX = x; -// } public Integer getTileY() { return tileY; } -// public void setTileY(Integer y) { -// this.tileY = y; -// } public Point getCenter() { return new Point(this.tileX, this.tileY); } - + public void setCenter(Point center) { tileX = center.x; tileY = center.y; + if (this.tileBean != null) { + this.tileBean.setCenter(center); + } } - + public Orientation getOrientation() { return tileOrientation; } - + public void setOrientation(Orientation orientation) { this.tileOrientation = orientation; + if (this.tileBean != null) { + this.tileBean.setOrientation(orientation); + } } - + public Direction getDirection() { return tileDirection; } - + public void setDirection(Direction direction) { this.tileDirection = direction; + if (this.tileBean != null) { + this.tileBean.setDirection(direction); + } } - + public String getAccessoryId() { return accessoryId; } - + public void setAccessoryId(String accessoryId) { this.accessoryId = accessoryId; + if (this.tileBean != null) { + this.tileBean.setAccessoryId(accessoryId); + } } - + public String getSensorId() { return sensorId; } - + public void setSensorId(String sensorId) { this.sensorId = sensorId; } - + public boolean isActive() { return model.isSensorActive(); } - + public void setActive(boolean active) { model.setSensorActive(active); } - + public BlockState getBlockState() { return model.getBlockState(); } - + public void setBlockState(BlockState blockState) { if (blockBean != null) { blockBean.setBlockState(blockState); + LocomotiveBean locomotive = model.getLocomotive(); + model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (blockState == BlockState.OCCUPIED || blockState == BlockState.INBOUND || blockState == BlockState.OUTBOUND)); } model.setBlockState(blockState); } - + public String getDepartureSuffix() { return model.getDepartureSuffix(); } - + public void setDepartureSuffix(String suffix) { if (blockBean != null) { blockBean.setDepartureSuffix(suffix); } model.setDepartureSuffix(suffix); } - + public boolean isReverseArrival() { return model.isReverseArrival(); } - + public void setReverseArrival(boolean reverseArrival) { if (blockBean != null) { blockBean.setReverseArrival(reverseArrival); } model.setReverseArrival(reverseArrival); } - + public LocomotiveBean.Direction getLogicalDirection() { return model.getLogicalDirection(); } - + public void setLogicalDirection(LocomotiveBean.Direction logicalDirection) { if (blockBean != null) { blockBean.setLogicalDirection(logicalDirection.getDirection()); } model.setLogicalDirection(logicalDirection); } - + public LocomotiveBean getLocomotive() { return model.getLocomotive(); } - + public void setLocomotive(LocomotiveBean locomotive) { if (blockBean != null) { blockBean.setLocomotive(locomotive); + model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (model.getBlockState() == BlockState.OCCUPIED || model.getBlockState() == BlockState.INBOUND || model.getBlockState() == BlockState.OUTBOUND)); } - - this.model.setLocomotive(locomotive); + + model.setLocomotive(locomotive); } - + public AccessoryBean getAccessoryBean() { return accessoryBean; } - + public void setAccessoryBean(AccessoryBean accessoryBean) { this.accessoryBean = accessoryBean; - + if (accessoryBean != null) { this.accessoryId = accessoryBean.getId(); this.signalValue = accessoryBean.getSignalValue(); @@ -427,7 +463,7 @@ public void setAccessoryBean(AccessoryBean accessoryBean) { this.signalValue = AccessoryBean.SignalValue.OFF; } } - + public AccessoryValue getAccessoryValue() { if (this.accessoryValue == null) { return AccessoryValue.OFF; @@ -435,12 +471,12 @@ public AccessoryValue getAccessoryValue() { return accessoryValue; } } - + public void setAccessoryValue(AccessoryValue value) { this.accessoryValue = value; repaint(); } - + public AccessoryValue getRouteValue() { if (routeValue == null) { return AccessoryValue.OFF; @@ -448,127 +484,127 @@ public AccessoryValue getRouteValue() { return routeValue; } } - + public void setRouteValue(AccessoryValue value) { this.routeValue = value; repaint(); } - + public AccessoryBean.SignalValue getSignalValue() { return signalValue; } - + public void setSignalValue(AccessoryBean.SignalValue signalValue) { this.signalValue = signalValue; this.repaint(); } - + public SensorBean getSensorBean() { return sensorBean; } - + public void setSensorBean(SensorBean sensorBean) { this.sensorBean = sensorBean; } - + public BlockBean getBlockBean() { return blockBean; } - + public void setBlockBean(BlockBean blockBean) { this.blockBean = blockBean; } - + public void setRenderWidth(int renderWidth) { this.renderWidth = renderWidth; } - + public void setRenderHeight(int renderHeight) { this.renderHeight = renderHeight; } - + public int getRenderOffsetX() { return renderOffsetX; } - + public void setRenderOffsetX(int renderOffsetX) { this.renderOffsetX = renderOffsetX; } - + public int getRenderOffsetY() { return renderOffsetY; } - + public void setRenderOffsetY(int renderOffsetY) { this.renderOffsetY = renderOffsetY; } - + public TileBean.TileType getTileType() { return this.tileType; } - + public final void setTileType(TileType tileType) { this.tileType = tileType; } - + public Color getTrackColor() { return trackColor; } - + public final void setTrackColor(Color trackColor) { this.trackColor = trackColor; } - + public Color getTrackRouteColor() { return trackRouteColor; } - + public void setTrackRouteColor(Color trackRouteColor) { this.trackRouteColor = trackRouteColor; } - + public Color getSelectedColor() { return selectedColor; } - + public void setSelectedColor(Color selectedColor) { this.selectedColor = selectedColor; } - + public Orientation getIncomingSide() { return incomingSide; } - + public void setIncomingSide(Orientation incomingSide) { this.incomingSide = incomingSide; } - + public Color getBackgroundColor() { return backgroundColor; } - + public void setBackgroundColor(Color backgroundColor) { this.backgroundColor = backgroundColor; } - + public boolean isDrawRoute() { return model.isShowRoute(); } - + public void setDrawRoute(boolean drawRoute) { this.model.setShowRoute(drawRoute); } - + public int getRenderWidth() { return renderWidth; } - + public int getRenderHeight() { return renderHeight; } - + abstract void renderTile(Graphics2D g2d); - + abstract void renderTileRoute(Graphics2D g2d); /** @@ -576,30 +612,29 @@ public int getRenderHeight() { * * @param g2d The graphics handle */ - //@Override public void drawTile(Graphics2D g2d) { // by default and image is rendered in the EAST orientation if (tileOrientation == null) { tileOrientation = Orientation.EAST; } - - tileImage = createImage(); - Graphics2D g2di = tileImage.createGraphics(); + + BufferedImage bf = createImage(); + Graphics2D g2di = bf.createGraphics(); //Avoid errors if (model.isShowRoute() && incomingSide == null) { incomingSide = getOrientation(); } - + if (model.isSelected()) { g2di.setBackground(selectedColor); } else { g2di.setBackground(backgroundColor); } - + g2di.clearRect(0, 0, renderWidth, renderHeight); int ox = 0, oy = 0; - + AffineTransform trans = new AffineTransform(); switch (tileOrientation) { case SOUTH -> { @@ -623,40 +658,31 @@ public void drawTile(Graphics2D g2d) { trans.translate(ox, oy); } } - - Logger.trace(tileOrientation.getOrientation() + " renderWidth: " + renderWidth + " renderHeight: " + renderHeight + " CP: (" + renderWidth / 2 + "," + renderHeight / 2 + ")"); - Logger.trace(tileOrientation.getOrientation() + " ox: " + ox + " oy: " + oy); - + + //Logger.trace(tileOrientation.getOrientation() + " renderWidth: " + renderWidth + " renderHeight: " + renderHeight + " CP: (" + renderWidth / 2 + "," + renderHeight / 2 + ")"); + //Logger.trace(tileOrientation.getOrientation() + " ox: " + ox + " oy: " + oy); g2di.setTransform(trans); - + renderTile(g2di); - + if (model.isShowRoute()) { renderTileRoute(g2di); } - + if (model.isShowCenter()) { drawCenterPoint(g2di); } // Scale the image back... if (model.isScaleImage()) { - tileImage = Scalr.resize(tileImage, Method.AUTOMATIC, Mode.FIT_EXACT, getWidth(), getHeight(), Scalr.OP_ANTIALIAS); + tileImage = Scalr.resize(bf, Method.AUTOMATIC, Mode.FIT_EXACT, getWidth(), getHeight(), Scalr.OP_ANTIALIAS); + } else { + tileImage = bf; } - - g2di.dispose(); -// int oxx, oyy; -// if (scaleImage) { -// oxx = offsetX; -// oyy = offsetY; -// } else { -// oxx = renderOffsetX; -// oyy = renderOffsetY; -// } - //g2d.drawImage(tileImage, (tileX - tileImage.getWidth() / 2) + oxx, (tileY - tileImage.getHeight() / 2) + oyy, null); + g2di.dispose(); } - + public BufferedImage getTileImage() { return tileImage; } @@ -668,19 +694,19 @@ public BufferedImage getTileImage() { */ public void drawName(Graphics2D g2) { } - + protected void drawCenterPoint(Graphics2D g2d) { drawCenterPoint(g2d, Color.magenta); } - + protected void drawCenterPoint(Graphics2D g2, Color color) { drawCenterPoint(g2, color, 60); } - + protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { double dX = (renderWidth / 2 - size / 2); double dY = (renderHeight / 2 - size / 2); - + g2d.setColor(color); g2d.fill(new Ellipse2D.Double(dX, dY, size, size)); } @@ -716,27 +742,27 @@ protected Orientation rotate(boolean repaint) { } return tileOrientation; } - + public void flipHorizontal() { if (Orientation.NORTH.equals(getOrientation()) || Orientation.SOUTH.equals(getOrientation())) { rotate(false); rotate(true); } } - + public void flipVertical() { if (Orientation.EAST.equals(getOrientation()) || Orientation.WEST.equals(getOrientation())) { rotate(false); rotate(true); } } - + @Override public void move(int newX, int newY) { Point cs = LayoutUtil.snapToGrid(newX, newY); setCenter(cs); } - + protected static void drawRotate(Graphics2D g2d, double x, double y, int angle, String text) { g2d.translate((float) x, (float) y); g2d.rotate(Math.toRadians(angle)); @@ -744,55 +770,55 @@ protected static void drawRotate(Graphics2D g2d, double x, double y, int angle, g2d.rotate(-Math.toRadians(angle)); g2d.translate(-x, -y); } - + public static BufferedImage flipHorizontally(BufferedImage source) { BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); - + AffineTransform flip = AffineTransform.getScaleInstance(1, -1); flip.translate(0, -source.getHeight()); AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); - + op.filter(source, output); - + return output; } - + public static BufferedImage flipVertically(BufferedImage source) { BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); - + AffineTransform flip = AffineTransform.getScaleInstance(-1, 1); flip.translate(-source.getWidth(), 0); AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); - + op.filter(source, output); - + return output; } - + public Set getAltPoints() { return Collections.EMPTY_SET; } - + public final int getOffsetX() { return offsetX; } - + public void setOffsetX(int offsetX) { this.offsetX = offsetX; } - + public final int getOffsetY() { return offsetY; } - + public void setOffsetY(int offsetY) { this.offsetY = offsetY; } - + protected BufferedImage createImage() { return new BufferedImage(renderWidth, renderHeight, BufferedImage.TYPE_INT_RGB); } - + public int getCenterX() { if (tileX > 0) { return this.tileX; @@ -800,7 +826,7 @@ public int getCenterX() { return GRID; } } - + public int getCenterY() { if (tileY > 0) { return this.tileY; @@ -808,19 +834,19 @@ public int getCenterY() { return GRID; } } - + public boolean isDrawName() { return drawName; } - + public void setDrawName(boolean drawName) { this.drawName = drawName; } - + public boolean isScaleImage() { return model.isScaleImage(); } - + public void setScaleImage(boolean scaleImage) { Dimension d; if (scaleImage) { @@ -828,21 +854,21 @@ public void setScaleImage(boolean scaleImage) { } else { d = new Dimension(renderWidth, renderHeight); } - + setSize(d); setPreferredSize(d); - + model.setScaleImage(scaleImage); } - + public boolean isDrawCenterPoint() { return model.isShowCenter(); } - + public void setDrawCenterPoint(boolean drawCenterPoint) { model.setShowCenter(drawCenterPoint); } - + @Override public String toString() { return this.getClass().getSimpleName() @@ -856,158 +882,147 @@ public String toString() { + xyToString() + "}"; } - - @Override - public Rectangle getBounds() { - int w, h, cx, cy; - //TODO: Check this may by the componet does this already - if (this.getWidth() > 0 & this.getHeight() > 0) { - //if (this.width > 0 & this.height > 0) { - //w = this.width; - w = this.getPreferredSize().width; - //h = this.height; - h = this.getPreferredSize().height; - } else { - w = DEFAULT_WIDTH; - h = DEFAULT_HEIGHT; - } - - if (this.tileX > 0 && this.tileY > 0) { - cx = this.tileX + this.offsetX; - cy = this.tileY + this.offsetY; - } else { - cx = w / 2; - cy = h / 2; - } - - int ltx = cx - w / 2; - int lty = cy - h / 2; - return new Rectangle(ltx, lty, w, h); - } - - public Rectangle2D getBounds2D() { - return getBounds().getBounds2D(); - } - - public boolean contains(double x, double y) { - int w, h, cx, cy, tlx, tly; - if (this.getWidth() > 0 & this.getHeight() > 0) { - //if (this.width > 0 & this.height > 0) { -// w = this.width; -// h = this.height; - w = this.getPreferredSize().width; - h = this.getPreferredSize().height; - - } else { - w = DEFAULT_WIDTH; - h = DEFAULT_HEIGHT; - } - - if (this.getWidth() > 0 & this.getHeight() > 0) { - //if (this.width > 0 & this.height > 0) { - cx = this.tileX; - cy = this.tileY; - } else { - cx = w / 2; - cy = h / 2; - } - // top left dX and dY - tlx = cx - w / 2; - tly = cy - h / 2; +// @Override +// public Rectangle getBounds() { +// int w, h, cx, cy; +// //TODO: Check this may by the componet does this already +// if (this.getWidth() > 0 & this.getHeight() > 0) { +// //if (this.width > 0 & this.height > 0) { +// //w = this.width; +// w = this.getPreferredSize().width; +// //h = this.height; +// h = this.getPreferredSize().height; +// } else { +// w = DEFAULT_WIDTH; +// h = DEFAULT_HEIGHT; +// } +// +// if (this.tileX > 0 && this.tileY > 0) { +// cx = this.tileX + this.offsetX; +// cy = this.tileY + this.offsetY; +// } else { +// cx = w / 2; +// cy = h / 2; +// } +// +// int ltx = cx - w / 2; +// int lty = cy - h / 2; +// return new Rectangle(ltx, lty, w, h); +// } + +// public Rectangle2D getBounds2D() { +// return getBounds().getBounds2D(); +// } + +// public boolean contains(double x, double y) { +// int w, h, cx, cy, tlx, tly; +// if (this.getWidth() > 0 & this.getHeight() > 0) { +// //if (this.width > 0 & this.height > 0) { +//// w = this.width; +//// h = this.height; +// w = this.getPreferredSize().width; +// h = this.getPreferredSize().height; +// +// } else { +// w = DEFAULT_WIDTH; +// h = DEFAULT_HEIGHT; +// } +// +// if (this.getWidth() > 0 & this.getHeight() > 0) { +// //if (this.width > 0 & this.height > 0) { +// cx = this.tileX; +// cy = this.tileY; +// } else { +// cx = w / 2; +// cy = h / 2; +// } +// +// // top left dX and dY +// tlx = cx - w / 2; +// tly = cy - h / 2; +// +// // Check if X and Y range is ok +// return !(x < tlx || x > (tlx + w) || y < tly || y > (tly + h)); +// } - // Check if X and Y range is ok - return !(x < tlx || x > (tlx + w) || y < tly || y > (tly + h)); - } - public String xyToString() { return "(" + this.tileX + "," + this.tileY + ")"; } - - public boolean contains(Point2D p) { - return this.contains(p.getX(), p.getY()); - } - - public boolean intersects(double x, double y, double w, double h) { - return getBounds().intersects(x, y, w, h); - } - - public boolean intersects(Rectangle2D r2d) { - return getBounds().intersects(r2d); - } - - public boolean contains(double x, double y, double w, double h) { - return getBounds().contains(x, y, w, h); - } - - public boolean contains(Rectangle2D r2d) { - return getBounds().contains(r2d); - } - - public PathIterator getPathIterator(AffineTransform at) { - return getBounds().getPathIterator(at); - } - - public PathIterator getPathIterator(AffineTransform at, double flatness) { - return getBounds().getPathIterator(at, flatness); - } - - @Deprecated - public PropertyChangeListener getPropertyChangeListener() { - return this.propertyChangeListener; - } - - @Deprecated - public void setPropertyChangeListener(PropertyChangeListener propertyChangeListener) { - this.propertyChangeListener = propertyChangeListener; - } - - @Deprecated - public void repaintTile() { -// if (this.propertyChangeListener != null) { -// this.propertyChangeListener.propertyChange(new PropertyChangeEvent(this, "repaintTile", this, this)); -// } - } - - @Override - @Deprecated - public void onTileChange(TileEvent tileEvent) { - Logger.warn("Deprecated! " + tileEvent.getTileId()); - if (tileEvent.isEventFor(this)) { - boolean drawRoute = tileEvent.isShowRoute(); - setIncomingSide(tileEvent.getIncomingSide()); - - if (isJunction()) { - // setRouteValue(tileEvent.getRouteState()); - } - - if (tileEvent.getBlockBean() != null) { - this.setBlockBean(tileEvent.getBlockBean()); - } - - if (tileEvent.getTileBean() != null) { - TileBean other = tileEvent.getTileBean(); - this.copyInto(other); - } - - if (isBlock()) { - // ((Block) this).setRouteBlockState(tileEvent.getBlockState()); - if (!drawRoute) { - // ((Block) this).setRouteBlockState(null); - } - } - - setBackgroundColor(tileEvent.getBackgroundColor()); - setTrackColor(tileEvent.getTrackColor()); - setTrackRouteColor(tileEvent.getTrackRouteColor()); +// public boolean contains(Point2D p) { +// return this.contains(p.getX(), p.getY()); +// } + +// public boolean intersects(double x, double y, double w, double h) { +// return getBounds().intersects(x, y, w, h); +// } + +// public boolean intersects(Rectangle2D r2d) { +// return getBounds().intersects(r2d); +// } + +// public boolean contains(double x, double y, double w, double h) { +// return getBounds().contains(x, y, w, h); +// } + +// public boolean contains(Rectangle2D r2d) { +// return getBounds().contains(r2d); +// } + +// public PathIterator getPathIterator(AffineTransform at) { +// return getBounds().getPathIterator(at); +// } + +// public PathIterator getPathIterator(AffineTransform at, double flatness) { +// return getBounds().getPathIterator(at, flatness); +// } + +// @Deprecated +// public PropertyChangeListener getPropertyChangeListener() { +// return this.propertyChangeListener; +// } +// @Deprecated +// public void setPropertyChangeListener(PropertyChangeListener propertyChangeListener) { +// this.propertyChangeListener = propertyChangeListener; +// } + //@Override +// @Deprecated +// public void onTileChange(TileEvent tileEvent) { +// Logger.warn("Deprecated! " + tileEvent.getTileId()); +// if (tileEvent.isEventFor(this)) { +// boolean drawRoute = tileEvent.isShowRoute(); +// setIncomingSide(tileEvent.getIncomingSide()); +// +// if (isJunction()) { +// // setRouteValue(tileEvent.getRouteState()); +// } +// // if (tileEvent.getBlockBean() != null) { -// setBlockBean(tileEvent.getBlockBean()); +// this.setBlockBean(tileEvent.getBlockBean()); // } -// repaintTile(); - } - } - +// +// //if (tileEvent.getTileBean() != null) { +// // TileBean other = tileEvent.getTileBean(); +// // this.copyInto(other); +// //} +// if (isBlock()) { +// // ((Block) this).setRouteBlockState(tileEvent.getBlockState()); +// if (!drawRoute) { +// // ((Block) this).setRouteBlockState(null); +// } +// } +// +// setBackgroundColor(tileEvent.getBackgroundColor()); +// setTrackColor(tileEvent.getTrackColor()); +// setTrackRouteColor(tileEvent.getTrackRouteColor()); +// +//// if (tileEvent.getBlockBean() != null) { +//// setBlockBean(tileEvent.getBlockBean()); +//// } +//// repaintTile(); +// } +// } /** * The main route of the tile is horizontal * @@ -1025,15 +1040,15 @@ public boolean isHorizontal() { public boolean isVertical() { return (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) && TileType.CURVED != tileType; } - + public boolean isJunction() { return TileType.SWITCH == tileType || TileType.CROSS == tileType; } - + public boolean isBlock() { return TileType.BLOCK == tileType; } - + public boolean isDirectional() { return TileType.STRAIGHT_DIR == tileType; } @@ -1046,52 +1061,52 @@ public boolean isDirectional() { public boolean isDiagonal() { return TileType.CURVED == tileType; } - + public boolean isCrossing() { return TileType.CROSSING == tileType; } - + public List getNeighbours() { return neighbours; } - + public void setNeighbours(List neighbours) { this.neighbours = neighbours; } - + public String getIdSuffix(Tile other) { return ""; } - + public Map getNeighborOrientations() { Map edgeOrientations = new HashMap<>(); - + Map neighborPoints = getNeighborPoints(); - + for (Orientation o : Orientation.values()) { edgeOrientations.put(neighborPoints.get(o), o); } return edgeOrientations; } - + public Map getEdgeOrientations() { Map edgeOrientations = new HashMap<>(); - + Map edgeConnections = getEdgePoints(); - + for (Orientation o : Orientation.values()) { edgeOrientations.put(edgeConnections.get(o), o); } return edgeOrientations; } - + public boolean isAdjacent(Tile other) { boolean adjacent = false; - + if (other != null) { Collection thisEdgePoints = getEdgePoints().values(); Collection otherEdgePoints = other.getEdgePoints().values(); - + for (Point p : thisEdgePoints) { adjacent = otherEdgePoints.contains(p); if (adjacent) { @@ -1099,7 +1114,7 @@ public boolean isAdjacent(Tile other) { } } } - + return adjacent; } @@ -1113,101 +1128,41 @@ public boolean isAdjacent(Tile other) { public boolean isArrowDirection(Tile other) { return true; } - + public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { return AccessoryValue.OFF; } - - @Deprecated - protected StringBuilder getImageKeyBuilder() { - StringBuilder sb = new StringBuilder(); - //sb.append(id); - sb.append(this.tileType); - sb.append("~"); - sb.append(getOrientation().getOrientation()); - sb.append("~"); - sb.append(getDirection().getDirection()); - //sb.append("~"); - //sb.append(isDrawOutline() ? "y" : "n"); - sb.append("~"); - int r = backgroundColor.getRed(); - int g = backgroundColor.getGreen(); - int b = backgroundColor.getBlue(); - sb.append("#"); - sb.append(r); - sb.append("#"); - sb.append(g); - sb.append("#"); - sb.append(b); - sb.append("~"); - r = trackColor.getRed(); - g = trackColor.getGreen(); - b = trackColor.getBlue(); - sb.append("#"); - sb.append(r); - sb.append("#"); - sb.append(g); - sb.append("#"); - sb.append(b); - sb.append("~"); - sb.append(isDrawRoute() ? "y" : "n"); - if (isDrawRoute()) { - if (incomingSide != null) { - sb.append("~"); - sb.append(incomingSide.getOrientation()); - } - sb.append("~"); - r = trackRouteColor.getRed(); - g = trackRouteColor.getGreen(); - b = trackRouteColor.getBlue(); - sb.append("#"); - sb.append(r); - sb.append("#"); - sb.append(g); - sb.append("#"); - sb.append(b); - } - //sb.append("~"); - //Tile specific properties - //AccessoryValue - //SignalType - //SignalValue - //active; - //Logger.trace(sb); - return sb; - } - public abstract Map getNeighborPoints(); - + public abstract Map getEdgePoints(); - + public abstract Set getAllPoints(); - + public TileModel getModel() { return model; } - + public void setModel(TileModel newModel) { TileModel oldModel = getModel(); - + if (oldModel != null) { oldModel.removeChangeListener(changeListener); oldModel.removeActionListener(actionListener); changeListener = null; actionListener = null; } - + model = newModel; - + if (newModel != null) { changeListener = createChangeListener(); actionListener = createActionListener(); - + newModel.addChangeListener(changeListener); newModel.addActionListener(actionListener); } - + firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel); if (newModel != oldModel) { revalidate(); @@ -1224,38 +1179,38 @@ public void setModel(TileModel newModel) { @Override public void updateUI() { } - + protected ChangeListener createChangeListener() { return getHandler(); } - + protected ActionListener createActionListener() { return getHandler(); } - + private Handler getHandler() { if (handler == null) { handler = new Handler(); } return handler; } - + class Handler implements ActionListener, ChangeListener, Serializable { - + @Override public void stateChanged(ChangeEvent e) { Object source = e.getSource(); - + fireStateChanged(); repaint(); } - + @Override public void actionPerformed(ActionEvent event) { fireActionPerformed(event); } } - + protected void fireStateChanged() { Object[] listeners = listenerList.getListenerList(); //reverse order @@ -1269,7 +1224,7 @@ protected void fireStateChanged() { } } } - + protected void fireActionPerformed(ActionEvent event) { Object[] listeners = listenerList.getListenerList(); ActionEvent e = null; @@ -1288,5 +1243,23 @@ protected void fireActionPerformed(ActionEvent event) { } } } - + + @Override + protected void paintComponent(Graphics g) { + long started = System.currentTimeMillis(); + super.paintComponent(g); + + setBounds(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); + + Graphics2D g2 = (Graphics2D) g.create(); + //Graphics2D g2 = (Graphics2D) g.create(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); + drawTile(g2); + g2.dispose(); + + g.drawImage(tileImage, 0, 0, null); + + long now = System.currentTimeMillis(); + Logger.trace(id + " Duration: " + (now - started) + " ms. Tile (" + tileX + "," + tileY + ")"); + } + } diff --git a/src/main/java/jcs/ui/layout/tiles/TileModel.java b/src/main/java/jcs/ui/layout/tiles/TileModel.java index 3d472126..46f144f3 100644 --- a/src/main/java/jcs/ui/layout/tiles/TileModel.java +++ b/src/main/java/jcs/ui/layout/tiles/TileModel.java @@ -87,6 +87,10 @@ public interface TileModel extends Serializable { public void setLocomotive(LocomotiveBean locomotive); + boolean isOverlayImage(); + + public void setOverlayImage(boolean overlayImage); + // void addChangeListener(ChangeListener l); diff --git a/src/test/java/jcs/ui/layout/tiles/BlockTileTester.java b/src/test/java/jcs/ui/layout/tiles/BlockTileTester.java index 7b7d4a8f..b06cde9a 100644 --- a/src/test/java/jcs/ui/layout/tiles/BlockTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/BlockTileTester.java @@ -57,9 +57,9 @@ public BlockTileTester(String title) { private void createTiles() { - blockEast = new Block(TileBean.Orientation.EAST, 200, 40); + blockEast = new Block(TileBean.Orientation.EAST, 220, 60); blockEast.setId("east"); - blockEast.setBlockState(blockStates.get(blockStateIndex)); + //blockEast.setBlockState(blockStates.get(blockStateIndex)); //blockEast.setBlockBean(createBlockBean(blockEast)); blockEast.setTrackRouteColor(Color.MAGENTA); @@ -81,9 +81,9 @@ private void createTiles() { dotGridCanvas.add(blockEast); - dotGridCanvas.add(blockSouth); - dotGridCanvas.add(blockWest); - dotGridCanvas.add(blockNorth); + //dotGridCanvas.add(blockSouth); + //dotGridCanvas.add(blockWest); + //dotGridCanvas.add(blockNorth); } private BlockBean createBlockBean(Tile tile) { diff --git a/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java b/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java index afb7d614..24b3f47b 100644 --- a/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java +++ b/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java @@ -28,6 +28,7 @@ public DotGridCanvas() { setLayout(null); setOpaque(true); setDoubleBuffered(false); + setBackground(Color.white); } @Override diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java index 308362f5..b4efac2a 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java @@ -25,7 +25,6 @@ public class UnscaledBlockCanvas extends JPanel { //implements PropertyChangeListener { private boolean expanded; - private int paintCount = 0; public UnscaledBlockCanvas() { setLayout(null); @@ -36,13 +35,10 @@ public UnscaledBlockCanvas() { @Override public void paint(Graphics g) { long started = System.currentTimeMillis(); - paintCount++; //Rectangle r = g.getClipBounds(); //Logger.trace("Rx: " + r.x + " Ry: " + r.y + " Rw: " + r.width + " Rh: " + r.height); - if (paintCount > 2) { - super.paint(g); - } + super.paint(g); paintGrid(g); long now = System.currentTimeMillis(); diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.java b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.java index 46d8ce54..6c0ecff4 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.java +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.java @@ -22,6 +22,7 @@ import javax.swing.DefaultComboBoxModel; import javax.swing.ImageIcon; import javax.swing.JFrame; +import javax.swing.JLabel; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import jcs.entities.BlockBean; @@ -48,6 +49,17 @@ public UnscaledBlockTester() { blockTile = createBlock(); canvas.add(blockTile); + //String imgPath = System.getProperty("user.home") + File.separator + "jcs" + File.separator + "images" + File.separator + "DHG 6505.png"; + //ImageIcon locIcon = new ImageIcon(getClass().getResource("/images/DHG 6505.png")); + //Image locImage = new BufferedImage(locIcon.getIconWidth(), locIcon.getIconHeight(), BufferedImage.TYPE_INT_RGB); + + //String imgPath = System.getProperty("user.home") + File.separator + "jcs" + File.separator + "images" + File.separator + "DHG 6505.png"; + //Image locImage = ImageUtil.readImage(imgPath); + + //locImage = ImageUtil.scaleImage(locImage, 100); + //JLabel c = new JLabel(new ImageIcon(locImage)); + + //canvas.add(c); centerSP.getViewport().validate(); pack(); @@ -79,17 +91,18 @@ private ComboBoxModel createStateComboBoxModel() { private LocomotiveBean createLocomotiveBean() { LocomotiveBean lb = new LocomotiveBean(8L, "NS DHG 6505", 8L, 8, "", "dcc", 100, 0, 0, 1, true, true); - String imgPath = System.getProperty("user.home") + File.separator + "jcs" + File.separator + "images" + File.separator + "DHG 6505.png"; + String imgPath = getClass().getResource("/images/DHG 6505.png").getFile().replaceAll("%20"," "); lb.setIcon(imgPath); - ImageIcon locIcon = new ImageIcon(getClass().getResource("/images/DHG 6505.png")); - Image locImage = new BufferedImage(locIcon.getIconWidth(), locIcon.getIconHeight(), BufferedImage.TYPE_INT_RGB); + Image locImage = ImageUtil.readImage(imgPath); locImage = ImageUtil.scaleImage(locImage, 100); lb.setLocIcon(locImage); - if (this.backwardsRB.isSelected()) { + if (backwardsRB.isSelected()) { lb.setDirection(LocomotiveBean.Direction.BACKWARDS); + this.blockTile.setLogicalDirection(LocomotiveBean.Direction.BACKWARDS); } else { lb.setDirection(LocomotiveBean.Direction.FORWARDS); + this.blockTile.setLogicalDirection(LocomotiveBean.Direction.FORWARDS); } return lb; @@ -290,7 +303,7 @@ private void rotateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN- }//GEN-LAST:event_rotateButtonActionPerformed private void showLocCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showLocCBActionPerformed - if (this.showLocCB.isSelected()) { + if (showLocCB.isSelected()) { blockTile.setLocomotive(createLocomotiveBean()); } else { blockTile.setLocomotive(null); @@ -302,10 +315,12 @@ private void orientationCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN }//GEN-LAST:event_orientationCBActionPerformed private void departureSideCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_departureSideCBActionPerformed - if ("".equals(departureSideCB.getSelectedItem())) { - blockTile.setDepartureSuffix(null); - } else { - blockTile.setDepartureSuffix(departureSideCB.getSelectedItem().toString()); + if (blockTile != null) { + if ("".equals(departureSideCB.getSelectedItem())) { + blockTile.setDepartureSuffix(null); + } else { + blockTile.setDepartureSuffix(departureSideCB.getSelectedItem().toString()); + } } }//GEN-LAST:event_departureSideCBActionPerformed @@ -317,10 +332,6 @@ private void showCenterCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN- blockTile.setDrawCenterPoint(this.showCenterCB.isSelected()); }//GEN-LAST:event_showCenterCBActionPerformed -// private String getDepartureSuffix() { -// return this.blockTile.getDepartureSuffix(); -// } - private void reverseArrivalCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_reverseArrivalCBActionPerformed blockTile.setReverseArrival(reverseArrivalCB.isSelected()); }//GEN-LAST:event_reverseArrivalCBActionPerformed @@ -403,15 +414,6 @@ public static void main(String args[]) { }); } -// @Override -// public void propertyChange(PropertyChangeEvent evt) { -// if ("repaintTile".equals(evt.getPropertyName())) { -// Tile t = (Tile) evt.getNewValue(); -// Logger.trace("Tile: " + t); -// this.repaint(); -// } -// } - // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JRadioButton backwardsRB; private jcs.ui.layout.tiles.UnscaledBlockCanvas canvas; From 4bab1471c66aac8e4d04f43182bb7255172ee360 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Sat, 25 Jan 2025 22:31:08 +0100 Subject: [PATCH 06/70] Slowly restoring the Edit functionality, but now a lot faster --- src/main/java/jcs/ui/layout/LayoutCanvas.java | 563 ++++-------------- src/main/java/jcs/ui/layout/LayoutPanel.java | 6 +- src/main/java/jcs/ui/layout/TileCache.java | 117 ++-- src/main/java/jcs/ui/layout/tiles/Block.java | 42 +- src/main/java/jcs/ui/layout/tiles/Tile.java | 49 +- .../jcs/ui/layout/tiles/BlockTileTester.java | 14 +- 6 files changed, 211 insertions(+), 580 deletions(-) diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.java b/src/main/java/jcs/ui/layout/LayoutCanvas.java index 67f95120..d822940a 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.java +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.java @@ -29,14 +29,11 @@ import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import java.awt.image.BufferedImage; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import javax.swing.DebugGraphics; import javax.swing.JFrame; import javax.swing.JMenuItem; import javax.swing.JPanel; @@ -54,6 +51,7 @@ import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean.TileType; import static jcs.entities.TileBean.TileType.BLOCK; import static jcs.entities.TileBean.TileType.CROSS; import static jcs.entities.TileBean.TileType.CURVED; @@ -100,16 +98,13 @@ public enum Mode { private Orientation orientation; private Direction direction; - private TileBean.TileType tileType; + private TileType tileType; private Point mouseLocation = new Point(); - private BufferedImage grid; - + //private BufferedImage grid; private final ExecutorService executor; -// private final Map tiles; -// private final Map altTiles; private final Set selectedTiles; private Tile selectedTile; @@ -125,6 +120,7 @@ public LayoutCanvas() { } public LayoutCanvas(boolean readonly) { + super(); setLayout(null); setOpaque(true); setDoubleBuffered(true); @@ -155,20 +151,14 @@ private void postInit() { @Override public void paint(Graphics g) { long started = System.currentTimeMillis(); - - //for (Tile tile : TileCache.tiles.values()) { - // tile.setSelected(selectedTiles.contains(tile.getCenter())); - //} - - //paintNullGrid(g); super.paint(g); if (drawGrid) { - //if (lineGrid) { - // paintLineGrid(g); - //} else { - paintDotGrid(g); - //} + if (lineGrid) { + paintLineGrid(g); + } else { + paintDotGrid(g); + } } long now = System.currentTimeMillis(); @@ -226,75 +216,23 @@ protected void paintComponent(Graphics g) { } //@Override - public void propertyChange(PropertyChangeEvent evt) { - if ("repaintTile".equals(evt.getPropertyName())) { - Tile tile = (Tile) evt.getNewValue(); - - Logger.trace("Repainting Tile: " + tile.getId()); -// repaint(tile.getBounds()); - } - } - - private void paintNullGrid(Graphics g) { - if (this.grid != null) { - int pw = this.getWidth(); - int ph = this.getHeight(); - int gw = grid.getWidth(); - int gh = grid.getHeight(); - - if (pw != gw || ph != gh) { - this.grid = null; - } - } - - if (this.grid == null) { - int width = getSize().width; - int height = getSize().height; - grid = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); - Graphics2D gc = grid.createGraphics(); - - gc.setBackground(Color.white); - gc.clearRect(0, 0, width, height); - - gc.setPaint(Color.black); - - gc.dispose(); - } - Graphics2D g2 = (Graphics2D) g; - //Draw grid from pre computed image - g2.drawImage(grid, null, 0, 0); - } - - private void paintDotGrid(Graphics g) { - int width = this.getWidth(); - int height = this.getHeight(); - - int xOffset = 0; - int yOffset = 0; - - //Logger.trace("W: " + width + " H: " + height + " X: " + this.getX() + " Y: " + this.getY()); - Graphics2D gc = (Graphics2D) g; - Paint p = gc.getPaint(); - gc.setPaint(Color.black); - - for (int r = 0; r < width; r++) { - for (int c = 0; c < height; c++) { - gc.drawOval((r * 20 * 2) + xOffset - 2, (c * 20 * 2) + yOffset - 2, 4, 4); - } - } - gc.setPaint(p); - +// public void propertyChange(PropertyChangeEvent evt) { +// if ("repaintTile".equals(evt.getPropertyName())) { +// Tile tile = (Tile) evt.getNewValue(); +// +// Logger.trace("Repainting Tile: " + tile.getId()); +//// repaint(tile.getBounds()); +// } +// } +// private void paintNullGrid(Graphics g) { // if (this.grid != null) { // int pw = this.getWidth(); // int ph = this.getHeight(); -// // int gw = grid.getWidth(); // int gh = grid.getHeight(); // // if (pw != gw || ph != gh) { -// //Logger.trace("Changed Canvas: " + pw + " x " + ph + " Grid: " + gw + " x " + gh); // this.grid = null; -// } else { // } // } // @@ -309,51 +247,45 @@ private void paintDotGrid(Graphics g) { // // gc.setPaint(Color.black); // -// for (int r = 0; r < width; r++) { -// for (int c = 0; c < height; c++) { -// gc.drawOval(r * Tile.GRID * 2, c * Tile.GRID * 2, 1, 1); -// } -// } // gc.dispose(); // } // Graphics2D g2 = (Graphics2D) g; +// //Draw grid from pre computed image // g2.drawImage(grid, null, 0, 0); - } - - private void paintLineGrid(Graphics g) { - if (this.grid != null) { - int pw = this.getWidth(); - int ph = this.getHeight(); - - int gw = grid.getWidth(); - int gh = grid.getHeight(); +// } + private void paintDotGrid(Graphics g) { + int width = getWidth(); + int height = getHeight(); + Graphics2D gc = (Graphics2D) g; + Paint p = gc.getPaint(); + gc.setPaint(Color.black); - if (pw != gw || ph != gh) { - this.grid = null; + int xOffset = 0; + int yOffset = 0; + for (int r = 0; r < width; r++) { + for (int c = 0; c < height; c++) { + gc.drawOval((r * 20 * 2) + xOffset - 2, (c * 20 * 2) + yOffset - 2, 4, 4); } } + gc.setPaint(p); + } - if (this.grid == null) { - int width = getSize().width; - int height = getSize().height; - grid = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); - Graphics2D gc = grid.createGraphics(); - - gc.setBackground(Color.white); - gc.clearRect(0, 0, width, height); - gc.setPaint(Color.lightGray); + private void paintLineGrid(Graphics g) { + int width = getWidth(); + int height = getHeight(); + Graphics2D gc = (Graphics2D) g; + Paint p = gc.getPaint(); + gc.setPaint(Color.black); + gc.setPaint(Color.lightGray); - gc.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - for (int x = 0; x < width; x += 40) { - gc.drawLine(x, 0, x, height); - } - for (int y = 0; y < height; y += 40) { - gc.drawLine(0, y, width, y); - } - gc.dispose(); + gc.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + for (int x = 0; x < width; x += 40) { + gc.drawLine(x, 0, x, height); + } + for (int y = 0; y < height; y += 40) { + gc.drawLine(0, y, width, y); } - Graphics2D g2 = (Graphics2D) g; - g2.drawImage(grid, null, 0, 0); + gc.setPaint(p); } void setMode(LayoutCanvas.Mode mode) { @@ -391,84 +323,19 @@ void loadLayoutInBackground() { } private void loadTiles() { - boolean showValues = Mode.CONTROL.equals(mode); + //boolean showValues = Mode.CONTROL.equals(mode); TileCache.loadTiles(); - TileCache.setShowValues(showValues); - //TileCache.setDrawOutline(drawGrid); - TileCache.setDrawCenterPoint(!this.readonly); -// List tileBeans = PersistenceFactory.getService().getTileBeans(); selectedTiles.clear(); -// altTiles.clear(); -// tiles.clear(); -// selectedRouteElements.clear(); - -// for (TileBean tb : tileBeans) { -// Tile tile = TileFactory.createTile(tb, drawGrid, showValues); -// tile.setPropertyChangeListener(this); -// tiles.put(tile.getCenter(), tile); -// -// //Alternative point(s) to be able to find all points -// if (!tile.getAltPoints().isEmpty()) { -// Set alt = tile.getAltPoints(); -// for (Point ap : alt) { -// altTiles.put(ap, tile); -// } -// } -// } -// Logger.debug("Loaded " + tiles.size() + " Tiles..."); for (Tile tile : TileCache.tiles.values()) { this.add(tile); + tile.setDrawCenterPoint(!readonly); + tile.setBounds(tile.getTileBounds()); } repaint(); } - void saveLayout() { - //Create a snapshot as persisting is done in worker thread -// Set snapshot = new HashSet<>(tiles.values()); - this.selectedTiles.clear(); -// this.executor.execute(() -> saveTiles(snapshot)); - - this.executor.execute(() -> TileCache.saveTiles()); - } - -// private synchronized void saveTiles(Set snapshot) { -// TileCache.saveTiles(); -// -// Logger.debug("Saving " + snapshot.size() + " tiles..."); -// List beans = new LinkedList<>(); -// -// for (Tile tile : snapshot) { -// if (tile != null) { -// TileBean tb = tile.getTileBean(); -// Logger.trace("Saving " + tile + " -> " + tb); -// beans.add(tb); -// } else { -// Logger.warn("Tile is null?"); -// } -// } -// PersistenceFactory.getService().persist(beans); -// } - private void saveTile(final Tile tile) { -// if (tile != null) { -// TileBean tb = tile.getTileBean(); -// this.executor.execute(() -> PersistenceFactory.getService().persist(tb)); - this.executor.execute(() -> TileCache.saveTile(tile)); -// } else { -// Logger.warn("Tile is null?"); -// } - } - -// private void deleteTile(final Tile tile) { -// if (tile != null) { -// TileBean tb = tile.getTileBean(); - //this.executor.execute(() -> PersistenceFactory.getService().remove(tb)); -// this.executor.execute(() -> TileCache.deleteTile(tile)); -// } else { -// Logger.warn("Tile is null?"); -// } -// } private void mouseMoveAction(MouseEvent evt) { Point sp = LayoutUtil.snapToGrid(evt.getPoint()); Tile tile = TileCache.findTile(sp); @@ -497,19 +364,20 @@ private void mousePressedAction(MouseEvent evt) { Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); //Clear any previous selection - for(Point p : selectedTiles) { - if(TileCache.containsPoint(p)) { + for (Point p : selectedTiles) { + if (TileCache.containsPoint(p)) { Tile st = TileCache.findTile(p); st.setSelected(false); - } + } } - + selectedTiles.clear(); Tile tile = TileCache.findTile(snapPoint); - + if (tile != null) { selectedTiles.addAll(tile.getAllPoints()); tile.setSelected(true); + selectedTile = tile; } switch (mode) { @@ -518,8 +386,6 @@ private void mousePressedAction(MouseEvent evt) { if (evt.getButton() == MouseEvent.BUTTON1) { executeControlActionForTile(tile, snapPoint); } else { - Logger.trace("Show menuitems for tile " + tile); - this.selectedTile = tile; if (tile.isBlock()) { showBlockPopupMenu(tile, snapPoint); } @@ -530,16 +396,10 @@ private void mousePressedAction(MouseEvent evt) { if (MouseEvent.BUTTON1 == evt.getButton() && tile == null) { //Only add a new tile when there is no tile on the selected snapPoint Logger.trace("Adding a new tile: " + tileType + " @ (" + snapPoint.x + ", " + snapPoint.y + ")"); - - Tile addedTile = addTile(snapPoint); + Tile addedTile = addTile(snapPoint, tileType, orientation, direction, true, !readonly); if (addedTile != null) { selectedTiles.addAll(addedTile.getAllPoints()); - - //if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { - //this.saveTile(tile); - this.add(addedTile); - repaint(); - //} + repaint(addedTile.getTileBounds()); } } else { if (tile != null) { @@ -551,31 +411,59 @@ private void mousePressedAction(MouseEvent evt) { if (MouseEvent.BUTTON3 == evt.getButton() && tile != null) { showOperationsPopupMenu(tile, snapPoint); } - } case DELETE -> { - //removeTiles(selectedTiles); - //TileCache.removeTiles(selectedTiles); - Tile t = (Tile) this.getComponentAt(snapPoint); - if (t != null) { - this.remove(t); - TileCache.deleteTile(t); + Tile toBeDeleted = (Tile) getComponentAt(snapPoint); + if (toBeDeleted != null) { + removeTile(toBeDeleted); + selectedTiles.clear(); + repaint(toBeDeleted.getTileBounds()); + selectedTile = null; } - - this.selectedTiles.clear(); - repaint(); } default -> { Logger.trace((tile != null ? "Selected tile: " + tile.getId() + ", " + tile.xyToString() : "No tile selected")); - if (tile == null) { - this.selectedTiles.clear(); - } + //if (tile == null) { + // this.selectedTiles.clear(); + //} if (MouseEvent.BUTTON3 == evt.getButton()) { showOperationsPopupMenu(tile, snapPoint); } } } + + } + + private Tile addTile(Point p, TileType tileType, Orientation orientation, Direction direction, boolean selected, boolean showCenter) { + Logger.trace("Adding: " + tileType + " @ " + p + " O: " + orientation + " D: " + direction); + Point chkp = TileCache.checkAvailable(p, orientation); + + Tile tile = TileFactory.createTile(tileType, orientation, direction, chkp, drawGrid); + tile.setSelected(selected); + tile.setDrawCenterPoint(showCenter); + + //Can the tile be placed, keeping in mind the extra points + boolean canBeAdded = !TileCache.checkTileOccupation(tile); + + if (canBeAdded) { + add(tile); + tile.setBounds(tile.getTileBounds()); + + TileCache.addTile(tile); + return tile; + } else { + return null; + } + } + + void removeTile(Tile tile) { + Tile toBeDeleted = (Tile) getComponentAt(tile.getCenter()); + if (toBeDeleted != null) { + Logger.trace("Deleting Tile " + tile.getId()); + remove(toBeDeleted); + TileCache.deleteTile(tile); + } } private void mouseDragAction(MouseEvent evt) { @@ -591,23 +479,6 @@ private void mouseDragAction(MouseEvent evt) { repaint(); } -// private boolean checkTileOccupation(Tile tile) { -// Set tilePoints = tile.getAllPoints(); -// for (Point p : tilePoints) { -// if (tiles.containsKey(p) || altTiles.containsKey(p)) { -// //The is a match, check if it is an other tile -// Tile mt = this.findTile(p); -// if (tile.getId().equals(mt.getId())) { -// //same tile continue -// } else { -// //Other tile so really occupied -// return true; -// } -// } -// } -// return false; -// return TileCache.checkTileOccupation(tile); -// } private void mouseReleasedAction(MouseEvent evt) { Tile selTile = getSelectedTile(); if (selTile != null) { @@ -859,7 +730,7 @@ private void showOperationsPopupMenu(Tile tile, Point p) { @SuppressWarnings("UnusedAssignment") boolean showDelete = false; - TileBean.TileType tt = tile.getTileType(); + TileType tt = tile.getTileType(); switch (tt) { case SENSOR -> { showProperties = true; @@ -913,225 +784,28 @@ private void showOperationsPopupMenu(Tile tile, Point p) { this.operationsPM.show(this, p.x, p.y); } -// public Tile findTile(Point cp) { -// Tile result = this.tiles.get(cp); -// if (result == null) { -// //Logger.trace("Using alternative points..."); -// result = this.altTiles.get(cp); -// if (result != null) { -// //Logger.trace("Found " + result + " in alt tiles"); -// } -// } -// return result; -// } -// private Point getCheckAvailable(Point newPoint) { -// if (this.tiles.containsKey(newPoint)) { -// Tile et = this.tiles.get(newPoint); -// Logger.debug("@ " + newPoint + " is allready occcupied by: " + et + "..."); -// //Search for the nearest avalaible free point -// //first get the Center point of the tile which is occuping this slot -// // show warning! -// Point ecp = et.getCenter(); -// -// int w = et.getWidth(); -// int h = et.getHeight(); -// -// Point np; -// np = switch (this.orientation) { -// case EAST -> -// new Point(ecp.x + w, ecp.y); -// case WEST -> -// new Point(newPoint.x - w, ecp.y); -// case SOUTH -> -// new Point(ecp.x, newPoint.y + h); -// default -> -// new Point(ecp.x, newPoint.y - h); -// }; -// -// Logger.trace("Alternative CP: " + np); -// // recursive check -// return getCheckAvailable(np); -// } else { -// Logger.debug("@ " + newPoint + " is not yet used..."); -// -// return newPoint; -// } -// } - private Tile addTile(Point p) { - if (this.orientation == null) { - this.orientation = Orientation.EAST; - } - - if (this.direction == null) { - this.direction = Direction.RIGHT; - } - - Logger.trace("Adding: " + tileType + " @ " + p); - Point chkp = TileCache.checkAvailable(p, this.orientation); - boolean fullRepaint = !chkp.equals(p); - - Tile tile = TileFactory.createTile(tileType, orientation, direction, chkp, drawGrid); - - //Can the tile be placed, keeping in mind the extra points - boolean canBeAdded = !TileCache.checkTileOccupation(tile); - - if (canBeAdded) { - TileCache.addTile(tile); - - Logger.trace("Added Tile " + tile.getClass().getSimpleName() + " " + tile.getOrientation() + " @ " + tile.getCenter() + " Full repaint: " + fullRepaint); - } - - if (fullRepaint) { - this.repaint(); - } - - if (canBeAdded) { - return tile; - } else { - return null; - } - } - - void removeTiles() { - TileCache.removeTiles(selectedTiles); - //removeTiles(selectedTiles); - repaint(); - } -// private void removeTiles(Set pointsToRemove) { -// TileCache.removeTiles(pointsToRemove); -// for (Point p : pointsToRemove) { -// Tile removed = TileCache.tiles.remove(p); -// -// if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { -// this.deleteTile(removed); -// } -// -// if (removed != null && removed.getAllPoints() != null) { -// Set rps = removed.getAltPoints(); -// //Also remove alt points -// for (Point ap : rps) { -// tiles.remove(ap); -// } -// -// Logger.trace("Removed: " + removed); -// } -// } -// selectedTiles.clear(); -// repaint(); -// } - private JFrame getParentFrame() { JFrame frame = (JFrame) SwingUtilities.getRoot(this); return frame; } public void rotateSelectedTile() { - Logger.trace("Selected Tiles " + selectedTiles.size()); - TileCache.rotateTile(selectedTiles); - -// //make copy as the map could be cleared -// Set snapshot = new HashSet<>(selectedTiles); -// -// for (Point p : snapshot) { -// Logger.trace("Selected Tile @ " + p); -// if (this.tiles.containsKey(p)) { -// Tile t = this.tiles.get(p); -// //Remove the alternative or extra points... -// for (Point ep : t.getAltPoints()) { -// this.altTiles.remove(ep); -// } -// -// t.rotate(); -// Logger.trace("Rotated " + t); -// this.orientation = t.getOrientation(); -// this.direction = t.getDirection(); -// -// //override -// this.tiles.put(p, t); -// for (Point ep : t.getAltPoints()) { -// this.altTiles.put(ep, t); -// } -// -// this.selectedTiles.clear(); -// this.selectedTiles.addAll(t.getAllPoints()); -// -// if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { -// this.saveTile(t); -// } -// } -// } - repaint(); + Logger.trace("Selected Tile " + selectedTile.getId()); + selectedTile = TileCache.rotateTile(selectedTile); + selectedTile.setBounds(selectedTile.getTileBounds()); + selectedTile.repaint(); } public void flipSelectedTileHorizontal() { - TileCache.flipHorizontal(selectedTiles); -// Set snapshot = new HashSet<>(selectedTiles); -// for (Point p : snapshot) { -// Logger.trace("Selected Tile @ " + p); -// if (this.tiles.containsKey(p)) { -// Tile t = this.tiles.get(p); -// //Remove the alternative or extra points... -// for (Point ep : t.getAltPoints()) { -// this.altTiles.remove(ep); -// } -// -// t.flipHorizontal(); -// Logger.trace("Flipped " + t); -// this.orientation = t.getOrientation(); -// this.direction = t.getDirection(); -// -// //override -// this.tiles.put(p, t); -// for (Point ep : t.getAltPoints()) { -// this.altTiles.put(ep, t); -// } -// -// if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { -// this.saveTile(t); -// } -// -// this.selectedTiles.clear(); -// this.selectedTiles.addAll(t.getAllPoints()); -// } -// } -// this.executor.execute(() -> repaint()); - repaint(); + selectedTile = TileCache.flipHorizontal(selectedTile); + selectedTile.setBounds(selectedTile.getTileBounds()); + selectedTile.repaint(); } public void flipSelectedTileVertical() { - TileCache.flipVertical(selectedTiles); - -// Set snapshot = new HashSet<>(selectedTiles); -// for (Point p : snapshot) { -// Logger.trace("Selected Tile @ " + p); -// if (this.tiles.containsKey(p)) { -// Tile t = this.tiles.get(p); -// //Remove the alternative or extra points... -// for (Point ep : t.getAltPoints()) { -// this.altTiles.remove(ep); -// } -// -// t.flipVertical(); -// Logger.trace("Flipped " + t); -// this.orientation = t.getOrientation(); -// this.direction = t.getDirection(); -// -// //override -// this.tiles.put(p, t); -// for (Point ep : t.getAltPoints()) { -// this.altTiles.put(ep, t); -// } -// -// if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { -// this.saveTile(t); -// } -// -// this.selectedTiles.clear(); -// this.selectedTiles.addAll(t.getAllPoints()); -// } -// } -// this.executor.execute(() -> repaint()); - repaint(); + selectedTile = TileCache.flipVertical(selectedTile); + selectedTile.setBounds(selectedTile.getTileBounds()); + selectedTile.repaint(); } void routeLayout() { @@ -1380,7 +1054,7 @@ private void horizontalMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_hor Logger.trace(this.orientation + ", " + evt.getModifiers() + ", " + evt.paramString()); if (this.mouseLocation != null && evt.getModifiers() == ActionEvent.MOUSE_EVENT_MASK) { - addTile(this.mouseLocation); + //addTile(this.mouseLocation); this.mouseLocation = null; } }//GEN-LAST:event_horizontalMIActionPerformed @@ -1389,7 +1063,7 @@ private void verticalMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_verti Logger.trace(this.orientation + ", " + evt.getModifiers() + ", " + evt.paramString()); if (this.mouseLocation != null && evt.getModifiers() == ActionEvent.MOUSE_EVENT_MASK) { - addTile(this.mouseLocation); + //addTile(this.mouseLocation); this.mouseLocation = null; } }//GEN-LAST:event_verticalMIActionPerformed @@ -1398,7 +1072,7 @@ private void rightMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_rightMIA Logger.trace(this.orientation + ", " + evt.getModifiers() + ", " + evt.paramString()); if (this.mouseLocation != null && evt.getModifiers() == ActionEvent.MOUSE_EVENT_MASK) { - addTile(this.mouseLocation); + //addTile(this.mouseLocation); this.mouseLocation = null; } }//GEN-LAST:event_rightMIActionPerformed @@ -1407,7 +1081,7 @@ private void leftMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_leftMIAct Logger.trace(this.orientation + ", " + evt.getModifiers() + ", " + evt.paramString()); if (this.mouseLocation != null && evt.getModifiers() == ActionEvent.MOUSE_EVENT_MASK) { - addTile(this.mouseLocation); + //addTile(this.mouseLocation); this.mouseLocation = null; } }//GEN-LAST:event_leftMIActionPerformed @@ -1433,9 +1107,12 @@ private void moveMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_moveMIAct }//GEN-LAST:event_moveMIActionPerformed private void deleteMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_deleteMIActionPerformed - //this.removeTiles(selectedTiles); - TileCache.removeTiles(selectedTiles); - this.selectedTiles.clear(); + if (selectedTile != null) { + removeTile(selectedTile); + selectedTiles.clear(); + repaint(selectedTile.getTileBounds()); + selectedTile = null; + } }//GEN-LAST:event_deleteMIActionPerformed private void propertiesMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_propertiesMIActionPerformed diff --git a/src/main/java/jcs/ui/layout/LayoutPanel.java b/src/main/java/jcs/ui/layout/LayoutPanel.java index 8a942a81..909a4fd1 100755 --- a/src/main/java/jcs/ui/layout/LayoutPanel.java +++ b/src/main/java/jcs/ui/layout/LayoutPanel.java @@ -874,7 +874,7 @@ private void moveMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_moveMIAct }//GEN-LAST:event_moveMIActionPerformed private void deleteMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_deleteMIActionPerformed - this.canvas.removeTiles(); + //this.canvas.removeTiles(); }//GEN-LAST:event_deleteMIActionPerformed private void propertiesMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_propertiesMIActionPerformed @@ -882,7 +882,7 @@ private void propertiesMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_pro }//GEN-LAST:event_propertiesMIActionPerformed private void saveBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_saveBtnActionPerformed - this.canvas.saveLayout(); + //this.canvas.saveLayout(); }//GEN-LAST:event_saveBtnActionPerformed private void loadBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_loadBtnActionPerformed @@ -899,7 +899,7 @@ private void addBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_addBtnAct private void deleteBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_deleteBtnActionPerformed setMode(LayoutCanvas.Mode.DELETE); - this.canvas.removeTiles(); + //this.canvas.removeTiles(); }//GEN-LAST:event_deleteBtnActionPerformed private void repaintBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_repaintBtnActionPerformed diff --git a/src/main/java/jcs/ui/layout/TileCache.java b/src/main/java/jcs/ui/layout/TileCache.java index 566d9605..7299e2c4 100644 --- a/src/main/java/jcs/ui/layout/TileCache.java +++ b/src/main/java/jcs/ui/layout/TileCache.java @@ -45,7 +45,6 @@ public class TileCache { private static final Map tileEventListeners = new HashMap<>(); - private static boolean drawOutline; private static boolean drawCenterPoint; private static boolean showValues; @@ -55,13 +54,6 @@ public class TileCache { private TileCache() { } -// static void setDrawOutline(boolean drawOutline) { -// TileCache.drawOutline = drawOutline; -// -// for (Tile tile : tiles.values()) { -// tile.setDrawOutline(drawOutline); -// } -// } static void setDrawCenterPoint(boolean drawCenterPoint) { TileCache.drawCenterPoint = drawCenterPoint; @@ -146,7 +138,6 @@ static void addTile(Tile tile) { tiles.put(tile.getCenter(), tile); //addTileEventListener((TileEventListener) tile); - //Alternative point(s) to be able to find all points if (!tile.getAltPoints().isEmpty()) { Set alt = tile.getAltPoints(); @@ -159,28 +150,22 @@ static void addTile(Tile tile) { Logger.trace("Added " + tile + " There are now " + TileCache.tiles.size() + " tiles..."); } - static void removeTiles(Set pointsToRemove) { - for (Point p : pointsToRemove) { - Tile removed = tiles.remove(p); - removeTileEventListener(removed); - - deleteTile(removed); - - if (removed != null && removed.getAllPoints() != null) { - Set rps = removed.getAltPoints(); + static void deleteTile(final Tile tile) { + if (tile != null) { + if (tiles.containsKey(tile.getCenter())) { + tiles.remove(tile.getCenter()); + Set rps = tile.getAltPoints(); //Also remove alt points for (Point ap : rps) { altTiles.remove(ap); } + TileBean tb = tile.getTileBean(); + PersistenceFactory.getService().remove(tb); + Logger.trace("Deleted " + tile.getId()); + } else { + Logger.warn("Tile " + tile.getId() + " not found in cache"); } - } - } - - static void deleteTile(final Tile tile) { - if (tile != null) { - TileBean tb = tile.getTileBean(); - PersistenceFactory.getService().remove(tb); } else { Logger.warn("Tile is null?"); } @@ -266,61 +251,59 @@ static Point checkAvailable(Point newPoint, Orientation orientation) { } } - static void rotateTile(Set centerPoints) { - for (Point p : centerPoints) { - if (tiles.containsKey(p)) { - Tile t = tiles.get(p); - //Remove the alternative or extra points... - for (Point ep : t.getAltPoints()) { - altTiles.remove(ep); - } + static Tile rotateTile(Tile tile) { + if (!tiles.containsKey(tile.getCenter())) { + Logger.warn("Tile " + tile.getId() + " NOT in cache!"); + } - t.rotate(); + //Remove the alternative or extra points... + for (Point ep : tile.getAltPoints()) { + altTiles.remove(ep); + } - //update - tiles.put(p, t); - for (Point ep : t.getAltPoints()) { - altTiles.put(ep, t); - } + tile.rotate(); - saveTile(t); - } + //update + tiles.put(tile.getCenter(), tile); + for (Point ep : tile.getAltPoints()) { + altTiles.put(ep, tile); } + + saveTile(tile); + return tile; } - public static void flipHorizontal(Set points) { - flipTile(points, true); + static Tile flipHorizontal(Tile tile) { + return flipTile(tile, true); } - public static void flipVertical(Set points) { - flipTile(points, false); + public static Tile flipVertical(Tile tile) { + return flipTile(tile, false); } - private static void flipTile(Set points, boolean horizontal) { - for (Point p : points) { - if (tiles.containsKey(p)) { - Tile t = tiles.get(p); - //Remove the alternative or extra points... - for (Point ep : t.getAltPoints()) { - altTiles.remove(ep); - } + private static Tile flipTile(Tile tile, boolean horizontal) { + if (!tiles.containsKey(tile.getCenter())) { + Logger.warn("Tile " + tile.getId() + " NOT in cache!"); + } - if (horizontal) { - t.flipHorizontal(); - } else { - t.flipVertical(); - } - //Update - tiles.put(p, t); - for (Point ep : t.getAltPoints()) { - altTiles.put(ep, t); - } + //Remove the alternative or extra points... + for (Point ep : tile.getAltPoints()) { + altTiles.remove(ep); + } - if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { - saveTile(t); - } - } + if (horizontal) { + tile.flipHorizontal(); + } else { + tile.flipVertical(); } + //update + tiles.put(tile.getCenter(), tile); + for (Point ep : tile.getAltPoints()) { + altTiles.put(ep, tile); + } + + saveTile(tile); + return tile; } static void moveTile(Point snapPoint, Tile tile) { diff --git a/src/main/java/jcs/ui/layout/tiles/Block.java b/src/main/java/jcs/ui/layout/tiles/Block.java index d150243c..abf288dc 100755 --- a/src/main/java/jcs/ui/layout/tiles/Block.java +++ b/src/main/java/jcs/ui/layout/tiles/Block.java @@ -23,6 +23,7 @@ import java.awt.Graphics2D; import java.awt.Image; import java.awt.Point; +import java.awt.Rectangle; import java.awt.geom.Ellipse2D; import java.awt.image.BufferedImage; import java.util.HashMap; @@ -41,6 +42,7 @@ import jcs.entities.TileBean.TileType; import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; +import static jcs.ui.layout.tiles.Tile.GRID; import static jcs.ui.layout.tiles.Tile.RENDER_HEIGHT; import static jcs.ui.layout.tiles.Tile.RENDER_WIDTH; import jcs.ui.util.ImageUtil; @@ -286,7 +288,8 @@ public String getIdSuffix(Tile other) { @Override public Orientation rotate() { - rotate(false); + super.rotate(); + int w = tileWidth(tileOrientation, TileType.BLOCK); int h = tileHeight(tileOrientation, TileType.BLOCK); @@ -295,7 +298,9 @@ public Orientation rotate() { setSize(d); changeRenderSize(); - repaint(); + setBounds(getTileBounds()); + + repaint(getTileBounds()); return tileOrientation; } @@ -705,11 +710,8 @@ public void drawName(Graphics2D g2d) { } @Override - protected void paintComponent(Graphics g) { - long started = System.currentTimeMillis(); - super.paintComponent(g); - - int multiplier = 1; //(model.isScaleImage() ? 1 : 10); + public Rectangle getTileBounds() { + int multiplier = (model.isScaleImage() ? 1 : 10); int xx, yy; if (tileOrientation == Orientation.EAST || tileOrientation == Orientation.WEST) { xx = tileX - GRID * multiplier - GRID * multiplier * 2; @@ -719,21 +721,16 @@ protected void paintComponent(Graphics g) { yy = tileY - GRID * multiplier - GRID * multiplier * 2; } - //if (model.isScaleImage()) { - setBounds(xx, yy, tileWidth(tileOrientation, TileType.BLOCK), tileHeight(tileOrientation, TileType.BLOCK)); - //setBounds(tileX - 60, tileY - 20, tileWidth(tileOrientation, TileType.BLOCK), tileHeight(tileOrientation, TileType.BLOCK)); - //} else { - //setBounds(xx, yy, renderWidth, renderHeight); - //} - - - //setBounds(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); - - //Graphics2D g2 = (Graphics2D) g.create(); - //Graphics2D g2 = (Graphics2D) g.create(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); - + if (model.isScaleImage()) { + return new Rectangle(xx, yy, tileWidth(tileOrientation, TileType.BLOCK), tileHeight(tileOrientation, TileType.BLOCK)); + } else { + return new Rectangle(xx, yy, renderWidth, renderHeight); + } + } - //Logger.trace(id + ": " + tileOrientation + " W: " + getWidth() + " H: " + getHeight() + " tX: " + tileX + ", tY: " + tileY + " xx: " + xx + " yy: " + yy + " Scale factor: " + multiplier); + @Override + protected void paintComponent(Graphics g) { + long started = System.currentTimeMillis(); Graphics2D g2 = (Graphics2D) g.create(); drawTile(g2); @@ -744,9 +741,6 @@ protected void paintComponent(Graphics g) { } g.drawImage(tileImage, 0, 0, null); - - //new Exception().printStackTrace() ; - long now = System.currentTimeMillis(); Logger.trace(id + " Duration: " + (now - started) + " ms."); } diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java index ae8f39f1..dfaf4512 100755 --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -20,12 +20,11 @@ import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; +import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.AffineTransform; import java.awt.geom.Ellipse2D; -import java.awt.geom.PathIterator; -import java.awt.geom.Rectangle2D; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; import java.beans.PropertyChangeListener; @@ -344,8 +343,8 @@ public Orientation getOrientation() { public void setOrientation(Orientation orientation) { this.tileOrientation = orientation; - if (this.tileBean != null) { - this.tileBean.setOrientation(orientation); + if (tileBean != null) { + tileBean.setOrientation(orientation); } } @@ -714,19 +713,9 @@ protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { /** * Rotate the tile clockwise 90 deg * - * @return + * @return the new Orientation */ public Orientation rotate() { - return rotate(true); - } - - /** - * Rotate the tile clockwise 90 deg - * - * @param repaint - * @return - */ - protected Orientation rotate(boolean repaint) { switch (tileOrientation) { case EAST -> setOrientation(Orientation.SOUTH); @@ -737,23 +726,20 @@ protected Orientation rotate(boolean repaint) { default -> setOrientation(Orientation.EAST); } - if (repaint) { - repaint(); - } return tileOrientation; } public void flipHorizontal() { - if (Orientation.NORTH.equals(getOrientation()) || Orientation.SOUTH.equals(getOrientation())) { - rotate(false); - rotate(true); + if (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) { + rotate(); + rotate(); } } public void flipVertical() { if (Orientation.EAST.equals(getOrientation()) || Orientation.WEST.equals(getOrientation())) { - rotate(false); - rotate(true); + rotate(); + rotate(); } } @@ -910,11 +896,9 @@ public String toString() { // int lty = cy - h / 2; // return new Rectangle(ltx, lty, w, h); // } - // public Rectangle2D getBounds2D() { // return getBounds().getBounds2D(); // } - // public boolean contains(double x, double y) { // int w, h, cx, cy, tlx, tly; // if (this.getWidth() > 0 & this.getHeight() > 0) { @@ -945,7 +929,6 @@ public String toString() { // // Check if X and Y range is ok // return !(x < tlx || x > (tlx + w) || y < tly || y > (tly + h)); // } - public String xyToString() { return "(" + this.tileX + "," + this.tileY + ")"; } @@ -953,31 +936,24 @@ public String xyToString() { // public boolean contains(Point2D p) { // return this.contains(p.getX(), p.getY()); // } - // public boolean intersects(double x, double y, double w, double h) { // return getBounds().intersects(x, y, w, h); // } - // public boolean intersects(Rectangle2D r2d) { // return getBounds().intersects(r2d); // } - // public boolean contains(double x, double y, double w, double h) { // return getBounds().contains(x, y, w, h); // } - // public boolean contains(Rectangle2D r2d) { // return getBounds().contains(r2d); // } - // public PathIterator getPathIterator(AffineTransform at) { // return getBounds().getPathIterator(at); // } - // public PathIterator getPathIterator(AffineTransform at, double flatness) { // return getBounds().getPathIterator(at, flatness); // } - // @Deprecated // public PropertyChangeListener getPropertyChangeListener() { // return this.propertyChangeListener; @@ -1244,12 +1220,13 @@ protected void fireActionPerformed(ActionEvent event) { } } + public Rectangle getTileBounds() { + return new Rectangle(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); + } + @Override protected void paintComponent(Graphics g) { long started = System.currentTimeMillis(); - super.paintComponent(g); - - setBounds(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); Graphics2D g2 = (Graphics2D) g.create(); //Graphics2D g2 = (Graphics2D) g.create(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); diff --git a/src/test/java/jcs/ui/layout/tiles/BlockTileTester.java b/src/test/java/jcs/ui/layout/tiles/BlockTileTester.java index b06cde9a..d50b4f9f 100644 --- a/src/test/java/jcs/ui/layout/tiles/BlockTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/BlockTileTester.java @@ -59,8 +59,8 @@ private void createTiles() { blockEast = new Block(TileBean.Orientation.EAST, 220, 60); blockEast.setId("east"); - //blockEast.setBlockState(blockStates.get(blockStateIndex)); - //blockEast.setBlockBean(createBlockBean(blockEast)); + blockEast.setBlockState(blockStates.get(blockStateIndex)); + blockEast.setBlockBean(createBlockBean(blockEast)); blockEast.setTrackRouteColor(Color.MAGENTA); blockSouth = new Block(TileBean.Orientation.SOUTH, 360, 80); @@ -69,21 +69,21 @@ private void createTiles() { blockSouth.setTrackRouteColor(Color.YELLOW); - blockWest = new Block(TileBean.Orientation.WEST, 200, 120); + blockWest = new Block(TileBean.Orientation.WEST, 180, 140); blockWest.setId("west"); blockSouth.setBlockState(blockStates.get(blockStateIndex+1)); blockWest.setTrackRouteColor(Color.CYAN); - blockNorth = new Block(TileBean.Orientation.NORTH, 40, 80); + blockNorth = new Block(TileBean.Orientation.NORTH, 60, 100); blockNorth.setId("north"); blockSouth.setBlockState(blockStates.get(blockStateIndex+1)); blockNorth.setTrackRouteColor(Color.blue); dotGridCanvas.add(blockEast); - //dotGridCanvas.add(blockSouth); - //dotGridCanvas.add(blockWest); - //dotGridCanvas.add(blockNorth); + dotGridCanvas.add(blockSouth); + dotGridCanvas.add(blockWest); + dotGridCanvas.add(blockNorth); } private BlockBean createBlockBean(Tile tile) { From cbcf078fe4de26a193cbf1e4672cb430df09d6f7 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Sun, 26 Jan 2025 15:36:06 +0100 Subject: [PATCH 07/70] Cross Tile working again --- src/main/java/jcs/ui/layout/LayoutCanvas.java | 117 ++---- src/main/java/jcs/ui/layout/TileCache.java | 18 +- src/main/java/jcs/ui/layout/tiles/Cross.java | 231 +++++++----- .../java/jcs/ui/layout/tiles/Straight.java | 2 - src/main/java/jcs/ui/layout/tiles/Switch.java | 25 +- src/main/java/jcs/ui/layout/tiles/Tile.java | 170 ++------- .../jcs/ui/layout/tiles/CrossTileTester.form | 208 +++++++++++ .../jcs/ui/layout/tiles/CrossTileTester.java | 333 ++++++++++++++---- .../jcs/ui/layout/tiles/DotGridCanvas.java | 40 ++- .../ui/layout/tiles/StraightTileTester.java | 1 - .../ui/layout/tiles/UnscaledBlockCanvas.java | 173 +-------- .../ui/layout/tiles/UnscaledTileFrame.java | 8 +- 12 files changed, 742 insertions(+), 584 deletions(-) create mode 100644 src/test/java/jcs/ui/layout/tiles/CrossTileTester.form diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.java b/src/main/java/jcs/ui/layout/LayoutCanvas.java index d822940a..6ac0884d 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.java +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.java @@ -17,6 +17,7 @@ import java.awt.BasicStroke; import java.awt.Color; +import java.awt.Component; import java.awt.Cursor; import java.awt.Dimension; import java.awt.Graphics; @@ -165,94 +166,34 @@ public void paint(Graphics g) { Logger.trace("Duration: " + (now - started) + " ms."); } +// @Override +// protected void paintComponent(Graphics g) { +// long started = System.currentTimeMillis(); +// super.paintComponent(g); +// long now = System.currentTimeMillis(); +// Logger.trace("Duration: " + (now - started) + " ms."); +// } + @Override - protected void paintComponent(Graphics g) { - long started = System.currentTimeMillis(); - super.paintComponent(g); - -// Graphics2D g2 = (Graphics2D) g.create(); -// Set snapshot = new HashSet<>(TileCache.tiles.values()); -// -// if (this.drawGrid) { -// if (lineGrid) { -// paintLineGrid(g); -// } else { -// paintDotGrid(g); -// } -// } else { -// paintNullGrid(g); -// } -// -// for (Tile tile : snapshot) { -// //for (Tile tile : TileCache.tiles.values()) { -// //tile.setDrawOutline(drawGrid); -// -// if (Mode.CONTROL != mode) { -// if (selectedTiles.contains(tile.getCenter())) { -// //tile.setBackgroundColor(Color.yellow); -// tile.setBackgroundColor(Color.orange); -// } else { -// tile.setBackgroundColor(Color.white); -// } -// } -// -// //tile.drawTile(g2); -// //debug -//// if (!this.readonly) { -//// tile.drawCenterPoint(g2, Color.magenta, 3); -//// } -// } -// if (this.movingTileCenterPoint != null && this.movingTileImage != null) { -// int x = movingTileCenterPoint.x; -// int y = movingTileCenterPoint.y; -// int w = movingTileImage.getWidth(); -// int h = movingTileImage.getHeight(); -// g2.drawImage(movingTileImage, (x - w / 2), (y - h / 2), null); -// } -// -// g2.dispose(); - long now = System.currentTimeMillis(); - Logger.trace("Duration: " + (now - started) + " ms."); + public Component add(Component component) { + super.add(component); + if (component instanceof Tile tile) { + tile.setBounds(tile.getTileBounds()); + } + return component; + } + + @Override + public Component add(String name, Component component) { + if (component instanceof Tile tile) { + super.add(tile.getId(), tile); + tile.setBounds(tile.getTileBounds()); + } else { + super.add(component); + } + return component; } - //@Override -// public void propertyChange(PropertyChangeEvent evt) { -// if ("repaintTile".equals(evt.getPropertyName())) { -// Tile tile = (Tile) evt.getNewValue(); -// -// Logger.trace("Repainting Tile: " + tile.getId()); -//// repaint(tile.getBounds()); -// } -// } -// private void paintNullGrid(Graphics g) { -// if (this.grid != null) { -// int pw = this.getWidth(); -// int ph = this.getHeight(); -// int gw = grid.getWidth(); -// int gh = grid.getHeight(); -// -// if (pw != gw || ph != gh) { -// this.grid = null; -// } -// } -// -// if (this.grid == null) { -// int width = getSize().width; -// int height = getSize().height; -// grid = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); -// Graphics2D gc = grid.createGraphics(); -// -// gc.setBackground(Color.white); -// gc.clearRect(0, 0, width, height); -// -// gc.setPaint(Color.black); -// -// gc.dispose(); -// } -// Graphics2D g2 = (Graphics2D) g; -// //Draw grid from pre computed image -// g2.drawImage(grid, null, 0, 0); -// } private void paintDotGrid(Graphics g) { int width = getWidth(); int height = getHeight(); @@ -330,7 +271,7 @@ private void loadTiles() { for (Tile tile : TileCache.tiles.values()) { this.add(tile); tile.setDrawCenterPoint(!readonly); - tile.setBounds(tile.getTileBounds()); + //tile.setBounds(tile.getTileBounds()); } repaint(); @@ -448,9 +389,9 @@ private Tile addTile(Point p, TileType tileType, Orientation orientation, Direct if (canBeAdded) { add(tile); - tile.setBounds(tile.getTileBounds()); + //tile.setBounds(tile.getTileBounds()); - TileCache.addTile(tile); + TileCache.addAndSaveTile(tile); return tile; } else { return null; diff --git a/src/main/java/jcs/ui/layout/TileCache.java b/src/main/java/jcs/ui/layout/TileCache.java index 7299e2c4..361bb354 100644 --- a/src/main/java/jcs/ui/layout/TileCache.java +++ b/src/main/java/jcs/ui/layout/TileCache.java @@ -17,7 +17,6 @@ import jcs.ui.layout.tiles.*; import java.awt.Point; -import java.beans.PropertyChangeListener; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -49,6 +48,7 @@ public class TileCache { private static boolean showValues; static final Map tiles = new HashMap<>(); + static final Map points = new HashMap<>(); static final Map altTiles = new HashMap<>(); private TileCache() { @@ -116,8 +116,9 @@ static void loadTiles() { Tile tile = TileFactory.createTile(tb, showValues); //tile.setPropertyChangeListener(listener); tiles.put(tile.getCenter(), tile); - //addTileEventListener((TileEventListener) tile); + points.put(tile.getId(), tile.getCenter()); + //addTileEventListener((TileEventListener) tile); //Alternative point(s) to be able to find all points if (!tile.getAltPoints().isEmpty()) { Set alt = tile.getAltPoints(); @@ -134,8 +135,9 @@ static List getTiles() { return tiles.values().stream().collect(Collectors.toList()); } - static void addTile(Tile tile) { + static void addAndSaveTile(Tile tile) { tiles.put(tile.getCenter(), tile); + points.put(tile.getId(), tile.getCenter()); //addTileEventListener((TileEventListener) tile); //Alternative point(s) to be able to find all points @@ -154,6 +156,7 @@ static void deleteTile(final Tile tile) { if (tile != null) { if (tiles.containsKey(tile.getCenter())) { tiles.remove(tile.getCenter()); + points.remove(tile.getId()); Set rps = tile.getAltPoints(); //Also remove alt points for (Point ap : rps) { @@ -196,6 +199,15 @@ public static Tile findTile(Point cp) { return result; } + public static Tile findTile(String id) { + Point p = points.get(id); + if (p != null) { + return findTile(p); + } else { + return null; + } + } + static boolean checkTileOccupation(Tile tile) { Set tilePoints = tile.getAllPoints(); for (Point p : tilePoints) { diff --git a/src/main/java/jcs/ui/layout/tiles/Cross.java b/src/main/java/jcs/ui/layout/tiles/Cross.java index 170114d6..3df8e88b 100644 --- a/src/main/java/jcs/ui/layout/tiles/Cross.java +++ b/src/main/java/jcs/ui/layout/tiles/Cross.java @@ -19,6 +19,8 @@ import java.awt.Color; import java.awt.Graphics2D; import java.awt.Point; +import java.awt.Rectangle; +import java.awt.geom.Ellipse2D; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -36,6 +38,9 @@ import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; import static jcs.ui.layout.tiles.Tile.GRID; +import static jcs.ui.layout.tiles.Tile.tileHeight; +import static jcs.ui.layout.tiles.Tile.tileWidth; +import org.tinylog.Logger; public class Cross extends Switch { @@ -50,68 +55,106 @@ public class Cross extends Switch { public static final Color LIGHT_GREEN = new Color(0, 255, 51); public static final Color DARK_GREEN = new Color(0, 153, 0); - private static int crossWidth(Orientation orientation) { - if (Orientation.EAST == orientation || Orientation.WEST == orientation) { - return DEFAULT_WIDTH * 2; - } else { - return DEFAULT_WIDTH; - } + public Cross(Orientation orientation, Direction direction, Point center) { + this(orientation, direction, center.x, center.y); } - private static int crossHeight(Orientation orientation) { - if (Orientation.EAST == orientation || Orientation.WEST == orientation) { - return DEFAULT_HEIGHT; - } else { - return DEFAULT_HEIGHT * 2; - } + public Cross(Orientation orientation, Direction direction, int x, int y) { + this(orientation, direction, x, y, tileWidth(orientation, TileType.CROSS), tileHeight(orientation, TileType.CROSS)); } - public Cross(TileBean tileBean) { - super(tileBean, crossWidth(tileBean.getOrientation()), crossHeight(tileBean.getOrientation())); - setWidthHeightAndOffsets(); + public Cross(Orientation orientation, Direction direction, int x, int y, int width, int height) { + super(TileType.CROSS, orientation, direction, x, y, width, height); + changeRenderSizeAndOffsets(); } - public Cross(Orientation orientation, Direction direction, Point center) { - this(orientation, direction, center.x, center.y); + public Cross(TileBean tileBean) { + super(tileBean, tileWidth(tileBean.getOrientation(), TileType.CROSS), tileHeight(tileBean.getOrientation(), TileType.CROSS)); + changeRenderSizeAndOffsets(); } - public Cross(Orientation orientation, Direction direction, int x, int y) { - this(orientation, direction, x, y, crossWidth(orientation), crossHeight(orientation)); - } + private void changeRenderSizeAndOffsets() { + //Reset offsets + this.offsetY = 0; + this.renderOffsetY = 0; + this.offsetX = 0; + this.renderOffsetX = 0; - public Cross(Orientation orientation, Direction direction, int x, int y, int width, int height) { - super(orientation, direction, x, y, width, height); - this.tileType = TileType.CROSS; - setWidthHeightAndOffsets(); + if (isHorizontal()) { + //this.width = DEFAULT_WIDTH * 2; + //this.height = DEFAULT_HEIGHT; + this.renderWidth = RENDER_GRID * 4; + this.renderHeight = RENDER_GRID * 2; + + this.offsetY = 0; + this.renderOffsetY = 0; + } else { + //this.width = DEFAULT_WIDTH; + //this.height = DEFAULT_HEIGHT * 2; + this.renderWidth = RENDER_GRID * 2; + this.renderHeight = RENDER_GRID * 4; + + this.offsetX = 0; + this.renderOffsetX = 0; + } + + //Due to the asymetical shape (center is on the left) + //the offset has to be changed with the rotation + switch (getOrientation()) { + case SOUTH -> { + this.offsetY = +GRID; + this.renderOffsetY = RENDER_GRID; + } + case WEST -> { + this.offsetX = -GRID; + this.renderOffsetX = -RENDER_GRID; + } + case NORTH -> { + this.offsetY = -GRID; + this.renderOffsetY = -RENDER_GRID; + } + default -> { + //East so default + this.offsetX = +GRID; + this.renderOffsetX = +RENDER_GRID; + } + } } +// private void changeRenderSize() { +// if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { +// this.renderWidth = RENDER_WIDTH * 2; +// this.renderHeight = RENDER_HEIGHT; +// } else { +// this.renderWidth = RENDER_WIDTH; +// this.renderHeight = RENDER_HEIGHT * 2; +// } +// } /** - * A Cross has a width in horizontal position of 2 tiles and a height of 1 tile in Vertical position a width of 1 tile and a height of 2 tiles. + * A Cross has a width in horizontal position of 2 tiles and a height of 1 tile in Vertical position.
* * @return the set of center point which mark the position of the Cross */ @Override public Set getAltPoints() { - int xx = this.tileX; - int yy = this.tileY; Set alternatives = new HashSet<>(); switch (getOrientation()) { case SOUTH -> { - Point sp = new Point(xx, (yy + DEFAULT_HEIGHT)); + Point sp = new Point(tileX, (tileY + DEFAULT_HEIGHT)); alternatives.add(sp); } case WEST -> { - Point wp = new Point((xx - DEFAULT_WIDTH), yy); + Point wp = new Point((tileX - DEFAULT_WIDTH), tileY); alternatives.add(wp); } case NORTH -> { - Point np = new Point(xx, (yy - DEFAULT_HEIGHT)); + Point np = new Point(tileX, (tileY - DEFAULT_HEIGHT)); alternatives.add(np); } default -> { //East so default - Point ep = new Point((tileX + DEFAULT_WIDTH), yy); + Point ep = new Point((tileX + DEFAULT_WIDTH), tileY); alternatives.add(ep); } } @@ -242,60 +285,6 @@ public Map getEdgePoints() { return edgeConnections; } -// @Override -// public void rotate() { -// super.rotate(); -// setWidthHeightAndOffsets(); -// } - - final void setWidthHeightAndOffsets() { - //Reset offsets - this.offsetY = 0; - this.renderOffsetY = 0; - this.offsetX = 0; - this.renderOffsetX = 0; - - if (isHorizontal()) { - //this.width = DEFAULT_WIDTH * 2; - //this.height = DEFAULT_HEIGHT; - this.renderWidth = RENDER_GRID * 4; - this.renderHeight = RENDER_GRID * 2; - - this.offsetY = 0; - this.renderOffsetY = 0; - } else { - //this.width = DEFAULT_WIDTH; - //this.height = DEFAULT_HEIGHT * 2; - this.renderWidth = RENDER_GRID * 2; - this.renderHeight = RENDER_GRID * 4; - - this.offsetX = 0; - this.renderOffsetX = 0; - } - - //Due to the asymetical shape (center is on the left) - //the offset has to be changed with the rotation - switch (getOrientation()) { - case SOUTH -> { - this.offsetY = +GRID; - this.renderOffsetY = RENDER_GRID; - } - case WEST -> { - this.offsetX = -GRID; - this.renderOffsetX = -RENDER_GRID; - } - case NORTH -> { - this.offsetY = -GRID; - this.renderOffsetY = -RENDER_GRID; - } - default -> { - //East so default - this.offsetX = +GRID; - this.renderOffsetX = +RENDER_GRID; - } - } - } - @Override protected void renderStraight(Graphics2D g2, Color color) { int xx, yy, w, h; @@ -589,4 +578,76 @@ public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { return AccessoryValue.OFF; } } + + @Override + protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { + //A Cross has 1 alternate point + //1st square holds the centerpoint + //2nd square + double dX1, dX2, dY1, dY2; + switch (tileOrientation) { + case SOUTH -> { + dX1 = renderWidth / 2 - size / 2; + dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; + dX2 = renderWidth / 2 + renderWidth - size / 4; + dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; + } + case WEST -> { + dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; + dY1 = renderHeight / 2 - size / 2; + dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; + dY2 = renderHeight / 2 - size / 4; + } + case NORTH -> { + dX1 = renderWidth / 2 - size / 2; + dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; + dX2 = renderWidth / 2 + renderWidth - size / 4; + dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; + } + default -> { + //East + dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; + dY1 = renderHeight / 2 - size / 2; + dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; + dY2 = renderHeight / 2 - size / 4; + } + } + + g2d.setColor(color); + g2d.fill(new Ellipse2D.Double(dX1, dY1, size, size)); + g2d.fill(new Ellipse2D.Double(dX2, dY2, size / 2, size / 2)); + } + + @Override + public Rectangle getTileBounds() { + int multiplier = (model.isScaleImage() ? 1 : 10); + int xx, yy; + //Centerpoint is inbalanced + switch (tileOrientation) { + case SOUTH -> { + xx = tileX - GRID * multiplier; + yy = tileY - GRID * multiplier; + } + case WEST -> { + xx = tileX - GRID * multiplier - GRID * 2 * multiplier; + yy = tileY - GRID * multiplier; + } + case NORTH -> { + xx = tileX - GRID * multiplier; + yy = tileY - GRID * multiplier - GRID * 2 * multiplier; + } + default -> { + //East + xx = tileX - GRID * multiplier; + yy = tileY - GRID * multiplier; + } + } + + if (model.isScaleImage()) { + return new Rectangle(xx, yy, tileWidth(tileOrientation, TileType.CROSS), tileHeight(tileOrientation, TileType.CROSS)); + } else { + return new Rectangle(xx, yy, renderWidth, renderHeight); + } + } + } diff --git a/src/main/java/jcs/ui/layout/tiles/Straight.java b/src/main/java/jcs/ui/layout/tiles/Straight.java index 8a45ba69..96685548 100755 --- a/src/main/java/jcs/ui/layout/tiles/Straight.java +++ b/src/main/java/jcs/ui/layout/tiles/Straight.java @@ -16,7 +16,6 @@ package jcs.ui.layout.tiles; import java.awt.BasicStroke; -import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.util.HashMap; @@ -26,7 +25,6 @@ import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; import jcs.entities.TileBean.TileType; -import org.tinylog.Logger; public class Straight extends Tile { diff --git a/src/main/java/jcs/ui/layout/tiles/Switch.java b/src/main/java/jcs/ui/layout/tiles/Switch.java index c75a4d45..de49b9ae 100644 --- a/src/main/java/jcs/ui/layout/tiles/Switch.java +++ b/src/main/java/jcs/ui/layout/tiles/Switch.java @@ -17,7 +17,6 @@ import java.awt.BasicStroke; import java.awt.Color; -import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.util.HashMap; @@ -38,19 +37,9 @@ import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; -import org.tinylog.Logger; public class Switch extends Tile implements AccessoryEventListener { - public Switch(TileBean tileBean) { - this(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); - } - - protected Switch(TileBean tileBean, int width, int height) { - super(tileBean, width, height); - setModel(new DefaultTileModel()); - } - public Switch(Orientation orientation, Direction direction, Point center) { this(orientation, direction, center.x, center.y); } @@ -60,8 +49,20 @@ public Switch(Orientation orientation, Direction direction, int x, int y) { } public Switch(Orientation orientation, Direction direction, int x, int y, int width, int height) { - super(TileType.SWITCH, orientation, direction, x, y, width, height); + this(TileType.SWITCH, orientation, direction, x, y, width, height); + } + protected Switch(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { + super(tileType, orientation, direction, x, y, width, height); + setModel(new DefaultTileModel()); + } + + public Switch(TileBean tileBean) { + this(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); + } + + protected Switch(TileBean tileBean, int width, int height) { + super(tileBean, width, height); setModel(new DefaultTileModel()); } diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java index dfaf4512..da73f3fd 100755 --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -173,8 +173,6 @@ protected Tile(TileType tileType, Orientation orientation, Direction direction, setSize(d); setPreferredSize(d); - //int w = getWidth(); - //int h = getHeight(); this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT; @@ -191,7 +189,6 @@ protected Tile(TileType tileType, Orientation orientation, Direction direction, } protected Tile(TileBean tileBean) { - //this(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); this(tileBean, tileWidth(tileBean.getOrientation(), tileBean.getTileType()), tileHeight(tileBean.getOrientation(), tileBean.getTileType())); } @@ -300,7 +297,6 @@ public void setSelected(boolean b) { model.setSelected(b); } - //@Override public String getId() { return id; } @@ -332,8 +328,8 @@ public Point getCenter() { public void setCenter(Point center) { tileX = center.x; tileY = center.y; - if (this.tileBean != null) { - this.tileBean.setCenter(center); + if (tileBean != null) { + tileBean.setCenter(center); } } @@ -354,8 +350,8 @@ public Direction getDirection() { public void setDirection(Direction direction) { this.tileDirection = direction; - if (this.tileBean != null) { - this.tileBean.setDirection(direction); + if (tileBean != null) { + tileBean.setDirection(direction); } } @@ -365,8 +361,8 @@ public String getAccessoryId() { public void setAccessoryId(String accessoryId) { this.accessoryId = accessoryId; - if (this.tileBean != null) { - this.tileBean.setAccessoryId(accessoryId); + if (tileBean != null) { + tileBean.setAccessoryId(accessoryId); } } @@ -453,13 +449,13 @@ public void setAccessoryBean(AccessoryBean accessoryBean) { this.accessoryBean = accessoryBean; if (accessoryBean != null) { - this.accessoryId = accessoryBean.getId(); - this.signalValue = accessoryBean.getSignalValue(); - this.signalType = SignalType.getSignalType(accessoryBean.getType()); + accessoryId = accessoryBean.getId(); + signalValue = accessoryBean.getSignalValue(); + signalType = SignalType.getSignalType(accessoryBean.getType()); } else { - this.accessoryId = null; - this.signalType = SignalType.NONE; - this.signalValue = AccessoryBean.SignalValue.OFF; + accessoryId = null; + signalType = SignalType.NONE; + signalValue = AccessoryBean.SignalValue.OFF; } } @@ -495,7 +491,7 @@ public AccessoryBean.SignalValue getSignalValue() { public void setSignalValue(AccessoryBean.SignalValue signalValue) { this.signalValue = signalValue; - this.repaint(); + repaint(); } public SensorBean getSensorBean() { @@ -606,6 +602,12 @@ public int getRenderHeight() { abstract void renderTileRoute(Graphics2D g2d); + public abstract Map getNeighborPoints(); + + public abstract Map getEdgePoints(); + + public abstract Set getAllPoints(); + /** * Draw the Tile * @@ -869,136 +871,10 @@ public String toString() { + "}"; } -// @Override -// public Rectangle getBounds() { -// int w, h, cx, cy; -// //TODO: Check this may by the componet does this already -// if (this.getWidth() > 0 & this.getHeight() > 0) { -// //if (this.width > 0 & this.height > 0) { -// //w = this.width; -// w = this.getPreferredSize().width; -// //h = this.height; -// h = this.getPreferredSize().height; -// } else { -// w = DEFAULT_WIDTH; -// h = DEFAULT_HEIGHT; -// } -// -// if (this.tileX > 0 && this.tileY > 0) { -// cx = this.tileX + this.offsetX; -// cy = this.tileY + this.offsetY; -// } else { -// cx = w / 2; -// cy = h / 2; -// } -// -// int ltx = cx - w / 2; -// int lty = cy - h / 2; -// return new Rectangle(ltx, lty, w, h); -// } -// public Rectangle2D getBounds2D() { -// return getBounds().getBounds2D(); -// } -// public boolean contains(double x, double y) { -// int w, h, cx, cy, tlx, tly; -// if (this.getWidth() > 0 & this.getHeight() > 0) { -// //if (this.width > 0 & this.height > 0) { -//// w = this.width; -//// h = this.height; -// w = this.getPreferredSize().width; -// h = this.getPreferredSize().height; -// -// } else { -// w = DEFAULT_WIDTH; -// h = DEFAULT_HEIGHT; -// } -// -// if (this.getWidth() > 0 & this.getHeight() > 0) { -// //if (this.width > 0 & this.height > 0) { -// cx = this.tileX; -// cy = this.tileY; -// } else { -// cx = w / 2; -// cy = h / 2; -// } -// -// // top left dX and dY -// tlx = cx - w / 2; -// tly = cy - h / 2; -// -// // Check if X and Y range is ok -// return !(x < tlx || x > (tlx + w) || y < tly || y > (tly + h)); -// } public String xyToString() { return "(" + this.tileX + "," + this.tileY + ")"; } -// public boolean contains(Point2D p) { -// return this.contains(p.getX(), p.getY()); -// } -// public boolean intersects(double x, double y, double w, double h) { -// return getBounds().intersects(x, y, w, h); -// } -// public boolean intersects(Rectangle2D r2d) { -// return getBounds().intersects(r2d); -// } -// public boolean contains(double x, double y, double w, double h) { -// return getBounds().contains(x, y, w, h); -// } -// public boolean contains(Rectangle2D r2d) { -// return getBounds().contains(r2d); -// } -// public PathIterator getPathIterator(AffineTransform at) { -// return getBounds().getPathIterator(at); -// } -// public PathIterator getPathIterator(AffineTransform at, double flatness) { -// return getBounds().getPathIterator(at, flatness); -// } -// @Deprecated -// public PropertyChangeListener getPropertyChangeListener() { -// return this.propertyChangeListener; -// } -// @Deprecated -// public void setPropertyChangeListener(PropertyChangeListener propertyChangeListener) { -// this.propertyChangeListener = propertyChangeListener; -// } - //@Override -// @Deprecated -// public void onTileChange(TileEvent tileEvent) { -// Logger.warn("Deprecated! " + tileEvent.getTileId()); -// if (tileEvent.isEventFor(this)) { -// boolean drawRoute = tileEvent.isShowRoute(); -// setIncomingSide(tileEvent.getIncomingSide()); -// -// if (isJunction()) { -// // setRouteValue(tileEvent.getRouteState()); -// } -// -// if (tileEvent.getBlockBean() != null) { -// this.setBlockBean(tileEvent.getBlockBean()); -// } -// -// //if (tileEvent.getTileBean() != null) { -// // TileBean other = tileEvent.getTileBean(); -// // this.copyInto(other); -// //} -// if (isBlock()) { -// // ((Block) this).setRouteBlockState(tileEvent.getBlockState()); -// if (!drawRoute) { -// // ((Block) this).setRouteBlockState(null); -// } -// } -// -// setBackgroundColor(tileEvent.getBackgroundColor()); -// setTrackColor(tileEvent.getTrackColor()); -// setTrackRouteColor(tileEvent.getTrackRouteColor()); -// -//// if (tileEvent.getBlockBean() != null) { -//// setBlockBean(tileEvent.getBlockBean()); -//// } -//// repaintTile(); -// } -// } /** * The main route of the tile is horizontal * @@ -1109,12 +985,6 @@ public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { return AccessoryValue.OFF; } - public abstract Map getNeighborPoints(); - - public abstract Map getEdgePoints(); - - public abstract Set getAllPoints(); - public TileModel getModel() { return model; } @@ -1175,7 +1045,7 @@ class Handler implements ActionListener, ChangeListener, Serializable { @Override public void stateChanged(ChangeEvent e) { - Object source = e.getSource(); + //Object source = e.getSource(); fireStateChanged(); repaint(); diff --git a/src/test/java/jcs/ui/layout/tiles/CrossTileTester.form b/src/test/java/jcs/ui/layout/tiles/CrossTileTester.form new file mode 100644 index 00000000..59c4dba4 --- /dev/null +++ b/src/test/java/jcs/ui/layout/tiles/CrossTileTester.form @@ -0,0 +1,208 @@ + + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/java/jcs/ui/layout/tiles/CrossTileTester.java b/src/test/java/jcs/ui/layout/tiles/CrossTileTester.java index 3173bd54..308066e9 100644 --- a/src/test/java/jcs/ui/layout/tiles/CrossTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/CrossTileTester.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Frans Jacobs. + * Copyright 2025 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,92 +17,279 @@ import java.awt.Color; import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; import java.awt.Toolkit; import javax.swing.JFrame; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import jcs.entities.AccessoryBean.AccessoryValue; -import jcs.entities.TileBean.Direction; -import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean; import org.tinylog.Logger; -/** - * @author Frans Jacobs - */ -public class CrossTileTester extends JFrame { +public class CrossTileTester extends javax.swing.JFrame { - private final Tile switchEastR; - private final Tile switchSouthR; - private final Tile switchWestR; - private final Tile switchNorthR; + private Tile crossEastR; + private Tile crossSouthR; + private Tile crossWestR; + private Tile crossNorthR; - private final Tile switchEastL; - private final Tile switchSouthL; - private final Tile switchWestL; - private final Tile switchNorthL; + private Tile crossEastL; + private Tile crossSouthL; + private Tile crossWestL; + private Tile crossNorthL; + /** + * Creates new form TileTester + * + * @param title + */ public CrossTileTester(String title) { super(title); + initComponents(); - switchEastR = new Cross(Orientation.EAST, Direction.RIGHT, 70, 100); - switchSouthR = new Cross(Orientation.SOUTH, Direction.RIGHT, 160, 100); - switchWestR = new Cross(Orientation.WEST, Direction.RIGHT, 250, 100); - switchNorthR = new Cross(Orientation.NORTH, Direction.RIGHT, 300, 100); + createTiles(); - switchEastL = new Cross(Orientation.EAST, Direction.LEFT, 70, 200); - switchSouthL = new Cross(Orientation.SOUTH, Direction.LEFT, 160, 200); - switchWestL = new Cross(Orientation.WEST, Direction.LEFT, 250, 200); - switchNorthL = new Cross(Orientation.NORTH, Direction.LEFT, 300, 200); + this.setVisible(true); } - @Override - public void paint(Graphics g) { - Graphics2D g2d = (Graphics2D) g; + private void createTiles() { + + crossEastR = new Cross(TileBean.Orientation.EAST, TileBean.Direction.RIGHT, 60, 60); + crossEastR.setId("eastR"); + crossEastR.setTrackRouteColor(Color.MAGENTA); + crossEastR.setRouteValue(AccessoryValue.GREEN); -// switchEastR.drawTile(g2d, true); -// switchEastR.drawBounds(g2d); - switchEastR.drawCenterPoint(g2d, Color.red); - ((Switch) switchEastR).setAccessoryValue(AccessoryValue.RED); + crossSouthR = new Cross(TileBean.Orientation.SOUTH, TileBean.Direction.RIGHT, 180, 60); + crossSouthR.setId("southR"); + crossSouthR.setTrackRouteColor(Color.YELLOW); + crossSouthR.setRouteValue(AccessoryValue.RED); -// switchSouthR.drawTile(g2d, false); -// switchSouthR.drawBounds(g2d); - switchSouthR.drawCenterPoint(g2d, Color.blue); + crossWestR = new Cross(TileBean.Orientation.WEST, TileBean.Direction.RIGHT, 380, 60); + crossWestR.setId("westR"); + crossWestR.setTrackRouteColor(Color.CYAN); -// switchWestR.drawTile(g2d, true); -// switchWestR.drawBounds(g2d); - switchWestR.drawCenterPoint(g2d, Color.red); - ((Switch) switchWestR).setAccessoryValue(AccessoryValue.GREEN); + crossNorthR = new Cross(TileBean.Orientation.NORTH, TileBean.Direction.RIGHT, 180, 220); + crossNorthR.setId("northR"); + crossNorthR.setTrackRouteColor(Color.blue); + crossNorthR.setRouteValue(AccessoryValue.GREEN); -// switchNorthR.drawTile(g2d, false); -// switchNorthR.drawBounds(g2d); - switchNorthR.drawCenterPoint(g2d, Color.cyan); // -// switchEastL.drawTile(g2d, false); -// switchEastL.drawBounds(g2d); - switchEastL.drawCenterPoint(g2d, Color.red); + crossEastL = new Cross(TileBean.Orientation.EAST, TileBean.Direction.LEFT, 60, 140); + crossEastL.setId("eastR"); + crossEastL.setTrackRouteColor(Color.MAGENTA); + crossEastL.setRouteValue(AccessoryValue.GREEN); + + crossSouthL = new Cross(TileBean.Orientation.SOUTH, TileBean.Direction.LEFT, 260, 60); + crossSouthL.setId("southR"); + crossSouthL.setTrackRouteColor(Color.YELLOW); + crossSouthL.setRouteValue(AccessoryValue.RED); -// switchSouthL.drawTile(g2d, true); -// switchSouthL.drawBounds(g2d); - switchSouthL.drawCenterPoint(g2d, Color.blue); - ((Switch) switchSouthL).setAccessoryValue(AccessoryValue.GREEN); + crossWestL = new Cross(TileBean.Orientation.WEST, TileBean.Direction.LEFT, 380, 140); + crossWestL.setId("westR"); + crossWestL.setTrackRouteColor(Color.CYAN); -// switchWestL.drawTile(g2d, false); -// switchWestL.drawBounds(g2d); - switchWestL.drawCenterPoint(g2d, Color.red); + crossNorthL = new Cross(TileBean.Orientation.NORTH, TileBean.Direction.LEFT, 260, 220); + crossNorthL.setId("northR"); + crossNorthL.setTrackRouteColor(Color.blue); + crossNorthL.setRouteValue(AccessoryValue.GREEN); -// switchNorthL.drawTile(g2d, true); -// switchNorthL.drawBounds(g2d); - switchNorthL.drawCenterPoint(g2d, Color.cyan); - ((Switch) switchNorthL).setAccessoryValue(AccessoryValue.RED); + dotGridCanvas.add(crossEastR); + dotGridCanvas.add(crossSouthR); + dotGridCanvas.add(crossWestR); + dotGridCanvas.add(crossNorthR); + dotGridCanvas.add(crossEastL); + dotGridCanvas.add(crossSouthL); + dotGridCanvas.add(crossWestL); + dotGridCanvas.add(crossNorthL); } - public static void main(String args[]) { + /** + * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + toolbarPanel = new javax.swing.JPanel(); + toolBar = new javax.swing.JToolBar(); + eastTileBtn = new javax.swing.JToggleButton(); + southTileBtn = new javax.swing.JToggleButton(); + westTileBtn = new javax.swing.JToggleButton(); + northTileBtn = new javax.swing.JToggleButton(); + selectSouthTileBtn = new javax.swing.JToggleButton(); + drawCenterBtn = new javax.swing.JToggleButton(); + greenRedBtn = new javax.swing.JToggleButton(); + dotGridCanvas = new jcs.ui.layout.tiles.DotGridCanvas(); + + setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + + java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); + flowLayout1.setAlignOnBaseline(true); + toolbarPanel.setLayout(flowLayout1); + + toolBar.setRollover(true); + + eastTileBtn.setText("East"); + eastTileBtn.setFocusable(false); + eastTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + eastTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + eastTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + eastTileBtnActionPerformed(evt); + } + }); + toolBar.add(eastTileBtn); + + southTileBtn.setText("South"); + southTileBtn.setFocusable(false); + southTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + southTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + southTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + southTileBtnActionPerformed(evt); + } + }); + toolBar.add(southTileBtn); + + westTileBtn.setText("West"); + westTileBtn.setFocusable(false); + westTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + westTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + westTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + westTileBtnActionPerformed(evt); + } + }); + toolBar.add(westTileBtn); + + northTileBtn.setText("North"); + northTileBtn.setFocusable(false); + northTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + northTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + northTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + northTileBtnActionPerformed(evt); + } + }); + toolBar.add(northTileBtn); + + selectSouthTileBtn.setText("Select Tile"); + selectSouthTileBtn.setFocusable(false); + selectSouthTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + selectSouthTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + selectSouthTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + selectSouthTileBtnActionPerformed(evt); + } + }); + toolBar.add(selectSouthTileBtn); + + drawCenterBtn.setText("show Center"); + drawCenterBtn.setFocusable(false); + drawCenterBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + drawCenterBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + drawCenterBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + drawCenterBtnActionPerformed(evt); + } + }); + toolBar.add(drawCenterBtn); + + greenRedBtn.setText("Red"); + greenRedBtn.setFocusable(false); + greenRedBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + greenRedBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + greenRedBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + greenRedBtnActionPerformed(evt); + } + }); + toolBar.add(greenRedBtn); + + toolbarPanel.add(toolBar); + + getContentPane().add(toolbarPanel, java.awt.BorderLayout.NORTH); + + dotGridCanvas.setPreferredSize(new java.awt.Dimension(480, 320)); + getContentPane().add(dotGridCanvas, java.awt.BorderLayout.CENTER); + pack(); + }// //GEN-END:initComponents + + private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed + Logger.trace(crossNorthR.id + "..."); + this.crossNorthR.setDrawRoute(this.northTileBtn.isSelected()); + this.crossNorthL.setDrawRoute(this.northTileBtn.isSelected()); + }//GEN-LAST:event_northTileBtnActionPerformed + + private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed + this.crossEastR.setDrawRoute(this.eastTileBtn.isSelected()); + this.crossEastL.setDrawRoute(this.eastTileBtn.isSelected()); + }//GEN-LAST:event_eastTileBtnActionPerformed + + private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed + this.crossWestR.setDrawRoute(this.westTileBtn.isSelected()); + this.crossWestL.setDrawRoute(this.westTileBtn.isSelected()); + }//GEN-LAST:event_westTileBtnActionPerformed + + private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed + this.crossSouthR.setDrawRoute(this.southTileBtn.isSelected()); + this.crossSouthL.setDrawRoute(this.southTileBtn.isSelected()); + }//GEN-LAST:event_southTileBtnActionPerformed + + private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed + this.crossSouthR.setSelected(this.selectSouthTileBtn.isSelected()); + this.crossSouthL.setSelected(this.selectSouthTileBtn.isSelected()); + }//GEN-LAST:event_selectSouthTileBtnActionPerformed + + private void drawCenterBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_drawCenterBtnActionPerformed + this.crossEastR.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + this.crossEastL.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + this.crossSouthR.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + this.crossSouthL.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + this.crossWestR.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + this.crossWestL.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + this.crossNorthR.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + this.crossNorthL.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + }//GEN-LAST:event_drawCenterBtnActionPerformed + + private void greenRedBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_greenRedBtnActionPerformed + boolean red = this.greenRedBtn.isSelected(); + if (red) { + this.greenRedBtn.setText("Green"); + if (this.westTileBtn.isSelected()) { + this.crossWestR.setAccessoryValue(AccessoryValue.OFF); + this.crossWestR.setRouteValue(AccessoryValue.GREEN); + + this.crossWestL.setAccessoryValue(AccessoryValue.OFF); + this.crossWestL.setRouteValue(AccessoryValue.GREEN); + } else { + this.crossWestR.setAccessoryValue(AccessoryValue.GREEN); + this.crossWestL.setAccessoryValue(AccessoryValue.GREEN); + } + } else { + this.greenRedBtn.setText("Red"); + if (this.westTileBtn.isSelected()) { + this.crossWestR.setAccessoryValue(AccessoryValue.OFF); + this.crossWestR.setRouteValue(AccessoryValue.RED); + + this.crossWestL.setAccessoryValue(AccessoryValue.OFF); + this.crossWestL.setRouteValue(AccessoryValue.RED); + } else { + this.crossWestR.setAccessoryValue(AccessoryValue.RED); + this.crossWestL.setAccessoryValue(AccessoryValue.RED); + } + } + }//GEN-LAST:event_greenRedBtnActionPerformed + + /** + * @param args the command line arguments + */ + public static void main(String args[]) { try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); + CrossTileTester.setDefaultLookAndFeelDecorated(true); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException @@ -110,16 +297,26 @@ public static void main(String args[]) { Logger.error(ex); } - CrossTileTester app = new CrossTileTester("Cross Tile Tester"); - - Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); - app.setSize(400, 300); - - app.setLocation( - dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); - - app.setVisible(true); - - app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + /* Create and display the form */ + java.awt.EventQueue.invokeLater(() -> { + CrossTileTester app = new CrossTileTester("Switch Tile Tester"); + app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); + app.setLocation(dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); + app.pack(); + }); } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private jcs.ui.layout.tiles.DotGridCanvas dotGridCanvas; + private javax.swing.JToggleButton drawCenterBtn; + private javax.swing.JToggleButton eastTileBtn; + private javax.swing.JToggleButton greenRedBtn; + private javax.swing.JToggleButton northTileBtn; + private javax.swing.JToggleButton selectSouthTileBtn; + private javax.swing.JToggleButton southTileBtn; + private javax.swing.JToolBar toolBar; + private javax.swing.JPanel toolbarPanel; + private javax.swing.JToggleButton westTileBtn; + // End of variables declaration//GEN-END:variables } diff --git a/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java b/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java index 24b3f47b..a789e06b 100644 --- a/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java +++ b/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java @@ -16,6 +16,7 @@ package jcs.ui.layout.tiles; import java.awt.Color; +import java.awt.Component; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Paint; @@ -23,31 +24,48 @@ import org.tinylog.Logger; public class DotGridCanvas extends JPanel { - + public DotGridCanvas() { - setLayout(null); + super(null, false); setOpaque(true); - setDoubleBuffered(false); setBackground(Color.white); } - + +// @Override +// protected void paintComponent(Graphics g) { +// long started = System.currentTimeMillis(); +// super.paintComponent(g); +// +// paintDotGrid(g); +// long now = System.currentTimeMillis(); +// Logger.trace("Duration: " + (now - started) + " ms."); +// } + @Override public void paint(Graphics g) { long started = System.currentTimeMillis(); - - //Rectangle r = g.getClipBounds(); - //Logger.trace("Rx: " + r.x + " Ry: " + r.y + " Rw: " + r.width + " Rh: " + r.height); super.paint(g); - + paintDotGrid(g); long now = System.currentTimeMillis(); Logger.trace("Duration: " + (now - started) + " ms."); } + + + @Override + public Component add(Component component) { + super.add(component); + if (component instanceof Tile tile) { + tile.setBounds(tile.getTileBounds()); + } + return component; + } + private void paintDotGrid(Graphics g) { int width = this.getWidth(); int height = this.getHeight(); - + int xOffset = 0; int yOffset = 0; @@ -55,7 +73,7 @@ private void paintDotGrid(Graphics g) { Graphics2D gc = (Graphics2D) g; Paint p = gc.getPaint(); gc.setPaint(Color.black); - + for (int r = 0; r < width; r++) { for (int c = 0; c < height; c++) { gc.drawOval((r * 20 * 2) + xOffset - 2, (c * 20 * 2) + yOffset - 2, 4, 4); @@ -63,5 +81,5 @@ private void paintDotGrid(Graphics g) { } gc.setPaint(p); } - + } diff --git a/src/test/java/jcs/ui/layout/tiles/StraightTileTester.java b/src/test/java/jcs/ui/layout/tiles/StraightTileTester.java index 0a383d3b..df3bcbdd 100644 --- a/src/test/java/jcs/ui/layout/tiles/StraightTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/StraightTileTester.java @@ -64,7 +64,6 @@ private void createTiles() { trackNorth.setTrackRouteColor(Color.blue); dotGridCanvas.add(trackEast); - dotGridCanvas.add(trackSouth); dotGridCanvas.add(trackWest); dotGridCanvas.add(trackNorth); diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java index b4efac2a..486d1b0d 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java @@ -16,13 +16,14 @@ package jcs.ui.layout.tiles; import java.awt.Color; +import java.awt.Component; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Paint; import javax.swing.JPanel; import org.tinylog.Logger; -public class UnscaledBlockCanvas extends JPanel { //implements PropertyChangeListener { +public class UnscaledBlockCanvas extends JPanel { private boolean expanded; @@ -33,12 +34,18 @@ public UnscaledBlockCanvas() { } @Override - public void paint(Graphics g) { - long started = System.currentTimeMillis(); + public Component add(Component component) { + super.add(component); + if (component instanceof Tile tile) { + tile.setBounds(tile.getTileBounds()); + } + return component; + } - //Rectangle r = g.getClipBounds(); - //Logger.trace("Rx: " + r.x + " Ry: " + r.y + " Rw: " + r.width + " Rh: " + r.height); - super.paint(g); + @Override + protected void paintComponent(Graphics g) { + long started = System.currentTimeMillis(); + super.paintComponent(g); paintGrid(g); long now = System.currentTimeMillis(); @@ -72,160 +79,6 @@ private void paintGrid(Graphics g) { gc.setPaint(p); } - //private boolean showCenter; - //private final List tiles; -// public UnscaledBlockCanvas() { -// tiles = new ArrayList<>(); -// } -// public void addTile(Tile block) { -// this.tiles.add(block); -// this.add(block); -// } -// public boolean isShowCenter() { -// return showCenter; -// } -// public void setShowCenter(boolean showCenter) { -// this.showCenter = showCenter; -// } -// private Dimension getMinCanvasSize() { -// int minX = this.getSize().width; -// int maxX = 0; -// int minY = this.getSize().height; -// int maxY = 0; -// -// for (Tile tile : this.tiles) { -// Point tc = tile.getCenter(); -// boolean expand = !tile.isScaleImage(); -// int tw = tile.getWidth() * (expand ? 10 : 1); -// int th = tile.getHeight() * (expand ? 10 : 1); -// -// if (minX > tc.x - (tw / 2)) { -// minX = tc.x - (tw / 2); -// } -// if (maxX < tc.x + (tw / 2)) { -// maxX = tc.x + (tw / 2); -// } -// if (minY > tc.y - (th / 2)) { -// minY = tc.y - (th / 2); -// } -// if (maxY < tc.y + (th / 2)) { -// maxY = tc.y + (th / 2); -// } -// } -// -// int totalWidth = maxX - minX; -// if (totalWidth <= 120) { -// totalWidth = totalWidth + 20; -// } -// -// int totalHeight = maxY - minY; -// if (totalHeight <= 40) { -// totalHeight = totalHeight + 20; -// } -// -// //Logger.trace("MinX: " + minX + " maxX: " + maxX + " minY: " + minY + " maxY: " + maxY + " Width: " + totalWidth + " Height: " + totalHeight); -// return new Dimension(Math.abs(totalWidth), Math.abs(totalHeight)); -// } -// private Dimension getMinRenderCanvasSize() { -// int minX = this.getSize().width; -// int maxX = 0; -// int minY = this.getSize().height; -// int maxY = 0; -// -// for (Tile tile : this.tiles) { -// Point tc = tile.getCenter(); -// -// int tw = ((Block) tile).getRenderWidth(); -// int th = ((Block) tile).getRenderHeight(); -// -// if (minX > tc.x - (tw / 2)) { -// minX = tc.x - (tw / 2); -// } -// if (maxX < tc.x + (tw / 2)) { -// maxX = tc.x + (tw / 2); -// } -// if (minY > tc.y - (th / 2)) { -// minY = tc.y - (th / 2); -// } -// if (maxY < tc.y + (th / 2)) { -// maxY = tc.y + (th / 2); -// } -// } -// -// int totalWidth = maxX - minX; -// int totalHeight = maxY - minY; -// -// //Logger.trace("MinX: " + minX + " maxX: " + maxX + " minY: " + minY + " maxY: " + maxY + " Width: " + totalWidth + " Height: " + totalHeight); -// return new Dimension(Math.abs(totalWidth), Math.abs(totalHeight)); -// } -// private BufferedImage paintTiles() { -// Dimension canvasSize = getMinCanvasSize(); -// BufferedImage canvasImage = new BufferedImage(Math.abs(canvasSize.width), Math.abs(canvasSize.height), BufferedImage.TYPE_INT_RGB); -// Graphics2D g2d = canvasImage.createGraphics(); -// -// g2d.setBackground(Color.white); -// g2d.clearRect(0, 0, canvasSize.width, canvasSize.height); -// -// for (Tile tile : tiles) { -//// tile.setDrawOutline(showCenter); -// -// //tile.drawTile(g2d, true); -// -// if (showCenter) { -// tile.drawCenterPoint(g2d, Color.red); -// } -// } -// g2d.dispose(); -// -// return canvasImage; -// } -// @Override -// protected void paintComponent(Graphics g) { -// Graphics2D g2d = (Graphics2D) g; -// BufferedImage canvasImage = paintTiles(); -// -// //paint the image in the middle so -// int w = this.getSize().width; -// int h = this.getSize().height; -// -// int cx = w / 2; -// int cy = h / 2; -// -// int bw = canvasImage.getWidth(); -// int bh = canvasImage.getHeight(); -// -// int pw = w; -// int ph = h; -// -// if(bw > w) { -// pw = w; -// } -// if(bh > h) { -// ph = h; -// } -// -// setPreferredSize(new Dimension(bw, bh)); -// //setPreferredSize(new Dimension(pw, ph)); -// -// int x = cx - (bw / 2); -// int y = cy - (bh / 2); -// g2d.drawImage(canvasImage, null, x, y); -// } -// @Override -// public void propertyChange(PropertyChangeEvent evt) { -// if ("repaintTile".equals(evt.getPropertyName())) { -// Tile tile = (Tile) evt.getNewValue(); -// this.repaint(tile.getBounds()); -// } -// } -// @Override -// public Dimension getPreferredSize() { -// if (!tiles.isEmpty()) { -// return getMinCanvasSize(); -// } else { -// return this.getSize(); -// } -// } public boolean isExpanded() { return expanded; } diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.java b/src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.java index 8efa793e..43e5bf53 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.java +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.java @@ -240,9 +240,9 @@ private void changeDirection() { Direction direction = (Direction) this.directionCB.getSelectedItem(); this.tile.setDirection(direction); - if (TileType.CROSS == tile.getTileType()) { - ((Cross) tile).setWidthHeightAndOffsets(); - } + //if (TileType.CROSS == tile.getTileType()) { + // ((Cross) tile).setWidthHeightAndOffsets(); + //} //this.repaint(); } @@ -287,7 +287,7 @@ private void changeOrientation() { tile.setOrientation(orientation); if (TileType.CROSS == tile.getTileType()) { - ((Cross) tile).setWidthHeightAndOffsets(); + //((Cross) tile).setWidthHeightAndOffsets(); int x = tile.getCenterX(); int y = tile.getCenterY(); From c95c95fdff0ff1a5ea9d74b94c05256ca547de94 Mon Sep 17 00:00:00 2001 From: Frans Jacobs <41232225+fransjacobs@users.noreply.github.com> Date: Sun, 26 Jan 2025 22:07:19 +0100 Subject: [PATCH 08/70] More refactoring issue with rotation of Cross --- src/main/java/jcs/ui/layout/LayoutCanvas.java | 6 +- src/main/java/jcs/ui/layout/tiles/Block.java | 22 +- src/main/java/jcs/ui/layout/tiles/Cross.java | 2 + src/main/java/jcs/ui/layout/tiles/Curved.java | 15 +- .../jcs/ui/layout/tiles/DefaultTileModel.java | 17 ++ src/main/java/jcs/ui/layout/tiles/End.java | 8 +- .../java/jcs/ui/layout/tiles/Straight.java | 4 +- src/main/java/jcs/ui/layout/tiles/Switch.java | 4 +- src/main/java/jcs/ui/layout/tiles/Tile.java | 43 ++- .../java/jcs/ui/layout/tiles/TileFactory.java | 13 +- .../java/jcs/ui/layout/tiles/TileModel.java | 5 + src/test/java/jcs/ui/layout/TileTest.java | 288 +++++++++--------- .../jcs/ui/layout/tiles/DotGridCanvas.java | 42 +-- ...ledTileFrame.form => TileTesterFrame.form} | 53 +++- ...ledTileFrame.java => TileTesterFrame.java} | 282 ++++++++--------- 15 files changed, 438 insertions(+), 366 deletions(-) rename src/test/java/jcs/ui/layout/tiles/{UnscaledTileFrame.form => TileTesterFrame.form} (91%) rename src/test/java/jcs/ui/layout/tiles/{UnscaledTileFrame.java => TileTesterFrame.java} (74%) diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.java b/src/main/java/jcs/ui/layout/LayoutCanvas.java index 6ac0884d..5ba67e08 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.java +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.java @@ -380,7 +380,7 @@ private Tile addTile(Point p, TileType tileType, Orientation orientation, Direct Logger.trace("Adding: " + tileType + " @ " + p + " O: " + orientation + " D: " + direction); Point chkp = TileCache.checkAvailable(p, orientation); - Tile tile = TileFactory.createTile(tileType, orientation, direction, chkp, drawGrid); + Tile tile = TileFactory.createTile(tileType, orientation, direction, chkp); tile.setSelected(selected); tile.setDrawCenterPoint(showCenter); @@ -734,7 +734,9 @@ public void rotateSelectedTile() { Logger.trace("Selected Tile " + selectedTile.getId()); selectedTile = TileCache.rotateTile(selectedTile); selectedTile.setBounds(selectedTile.getTileBounds()); - selectedTile.repaint(); + //selectedTile.repaint(); + + repaint(selectedTile.getTileBounds()); } public void flipSelectedTileHorizontal() { diff --git a/src/main/java/jcs/ui/layout/tiles/Block.java b/src/main/java/jcs/ui/layout/tiles/Block.java index abf288dc..105cfcdb 100755 --- a/src/main/java/jcs/ui/layout/tiles/Block.java +++ b/src/main/java/jcs/ui/layout/tiles/Block.java @@ -55,10 +55,8 @@ public class Block extends Tile { public Block(TileBean tileBean) { super(tileBean); - setModel(new DefaultTileModel()); - + setModel(new DefaultTileModel(tileBean.getOrientation())); changeRenderSize(); - populateModel(); } @@ -72,11 +70,12 @@ public Block(Orientation orientation, int x, int y) { public Block(Orientation orientation, int x, int y, int width, int height) { super(TileType.BLOCK, orientation, x, y, width, height); - setModel(new DefaultTileModel()); + setModel(new DefaultTileModel(orientation)); changeRenderSize(); } private void changeRenderSize() { + Orientation tileOrientation = model.getTileOrienation(); if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { this.renderWidth = RENDER_WIDTH * 3; this.renderHeight = RENDER_HEIGHT; @@ -257,6 +256,7 @@ public String getIdSuffix(Tile other) { } } + Orientation tileOrientation = model.getTileOrienation(); if (match != null) { if (Orientation.EAST == tileOrientation && Orientation.EAST == match) { suffix = "+"; @@ -288,6 +288,7 @@ public String getIdSuffix(Tile other) { @Override public Orientation rotate() { + Orientation tileOrientation = model.getTileOrienation(); super.rotate(); int w = tileWidth(tileOrientation, TileType.BLOCK); @@ -300,7 +301,7 @@ public Orientation rotate() { setBounds(getTileBounds()); - repaint(getTileBounds()); + //repaint(getTileBounds()); return tileOrientation; } @@ -401,6 +402,7 @@ public void renderTile(Graphics2D g2) { private void renderDirectionArrow(Graphics2D g2) { //The default, forwards is in the direction of the block orientation, i.e. the + + Orientation tileOrientation = model.getTileOrienation(); BlockBean bb = this.getBlockBean(); boolean reverseArrival = model.isReverseArrival(); @@ -512,6 +514,7 @@ public void renderTileRoute(Graphics2D g2d) { protected void overlayLocImage() { int ww = tileImage.getWidth(); int hh = tileImage.getHeight(); + Orientation tileOrientation = model.getTileOrienation(); BufferedImage overlay = new BufferedImage(ww, hh, BufferedImage.TYPE_INT_ARGB); Graphics2D g2i = overlay.createGraphics(); @@ -632,7 +635,6 @@ protected void overlayLocImage() { g2i.dispose(); tileImage = overlay; } - } private Image getLocImage() { @@ -688,6 +690,7 @@ public void drawName(Graphics2D g2d) { } int textHeight = g2d.getFontMetrics().getHeight(); + Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case EAST -> { @@ -712,6 +715,8 @@ public void drawName(Graphics2D g2d) { @Override public Rectangle getTileBounds() { int multiplier = (model.isScaleImage() ? 1 : 10); + Orientation tileOrientation = model.getTileOrienation(); + int xx, yy; if (tileOrientation == Orientation.EAST || tileOrientation == Orientation.WEST) { xx = tileX - GRID * multiplier - GRID * multiplier * 2; @@ -751,6 +756,7 @@ protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { //1st square //2nd square holds the centerpoint //3rd square + Orientation tileOrientation = model.getTileOrienation(); double dX1, dX2, dX3, dY1, dY2, dY3; if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { dX1 = renderWidth / 3 / 2 - size / 2 / 2; @@ -772,10 +778,6 @@ protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { g2d.fill(new Ellipse2D.Double(dX1, dY1, size / 2, size / 2)); g2d.fill(new Ellipse2D.Double(dX2, dY2, size, size)); g2d.fill(new Ellipse2D.Double(dX3, dY3, size / 2, size / 2)); - - //Logger.trace(id + " dX2: " + dX2 + " dY2: " + dY2 + " O: " + tileOrientation + " rW: " + renderWidth + " rH:" + renderHeight + " Size: " + size); - //Logger.trace(id + " dX1: " + dX1 + " dY1: " + dY1); - //Logger.trace(id + " dX3: " + dX3 + " dY3: " + dY3); } } diff --git a/src/main/java/jcs/ui/layout/tiles/Cross.java b/src/main/java/jcs/ui/layout/tiles/Cross.java index 3df8e88b..72e03d11 100644 --- a/src/main/java/jcs/ui/layout/tiles/Cross.java +++ b/src/main/java/jcs/ui/layout/tiles/Cross.java @@ -585,6 +585,7 @@ protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { //1st square holds the centerpoint //2nd square double dX1, dX2, dY1, dY2; + Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case SOUTH -> { dX1 = renderWidth / 2 - size / 2; @@ -623,6 +624,7 @@ public Rectangle getTileBounds() { int multiplier = (model.isScaleImage() ? 1 : 10); int xx, yy; //Centerpoint is inbalanced + Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case SOUTH -> { xx = tileX - GRID * multiplier; diff --git a/src/main/java/jcs/ui/layout/tiles/Curved.java b/src/main/java/jcs/ui/layout/tiles/Curved.java index 1aad3e4b..0de19ed3 100755 --- a/src/main/java/jcs/ui/layout/tiles/Curved.java +++ b/src/main/java/jcs/ui/layout/tiles/Curved.java @@ -16,7 +16,6 @@ package jcs.ui.layout.tiles; import java.awt.BasicStroke; -import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.util.HashMap; @@ -29,26 +28,25 @@ import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; -import org.tinylog.Logger; public class Curved extends Tile { - Curved(TileBean tileBean) { + public Curved(TileBean tileBean) { super(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); - setModel(new DefaultTileModel()); + setModel(new DefaultTileModel(tileBean.getOrientation())); } - Curved(Orientation orientation, Point center) { + public Curved(Orientation orientation, Point center) { this(orientation, center.x, center.y); } - Curved(Orientation orientation, int x, int y) { + public Curved(Orientation orientation, int x, int y) { this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); } - Curved(Orientation orientation, int x, int y, int width, int height) { + public Curved(Orientation orientation, int x, int y, int width, int height) { super(TileType.CURVED, orientation, x, y, width, height); - setModel(new DefaultTileModel()); + setModel(new DefaultTileModel(orientation)); } @Override @@ -160,5 +158,4 @@ public void renderTileRoute(Graphics2D g2) { // long now = System.currentTimeMillis(); // Logger.trace(this.id + " Duration: " + (now - started) + " ms."); // } - } diff --git a/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java b/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java index f584c651..6663ee90 100644 --- a/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java +++ b/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java @@ -23,6 +23,7 @@ import javax.swing.event.EventListenerList; import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; +import jcs.entities.TileBean.Orientation; /** * @@ -41,6 +42,7 @@ public class DefaultTileModel implements TileModel { protected boolean selected = false; protected boolean scaleImage = true; protected boolean showCenter = false; + protected Orientation tileOrienation; protected boolean showRoute = false; protected boolean showBlockState = false; protected boolean showLocomotiveImage = false; @@ -57,7 +59,11 @@ public class DefaultTileModel implements TileModel { protected LocomotiveBean locomotive; public DefaultTileModel() { + this(Orientation.EAST); + } + public DefaultTileModel(Orientation orientation) { + this.tileOrienation = orientation; } @Override @@ -93,6 +99,17 @@ public void setShowCenter(boolean showCenter) { fireStateChanged(); } + @Override + public Orientation getTileOrienation() { + return tileOrienation; + } + + @Override + public void setTileOrienation(Orientation tileOrienation) { + this.tileOrienation = tileOrienation; + fireStateChanged(); + } + @Override public boolean isShowRoute() { return showRoute; diff --git a/src/main/java/jcs/ui/layout/tiles/End.java b/src/main/java/jcs/ui/layout/tiles/End.java index fd474844..e71da407 100644 --- a/src/main/java/jcs/ui/layout/tiles/End.java +++ b/src/main/java/jcs/ui/layout/tiles/End.java @@ -17,7 +17,6 @@ import java.awt.BasicStroke; import java.awt.Color; -import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.util.HashMap; @@ -30,13 +29,12 @@ import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; -import org.tinylog.Logger; public class End extends Tile { public End(TileBean tileBean) { super(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); - setModel(new DefaultTileModel()); + setModel(new DefaultTileModel(tileBean.getOrientation())); } public End(Orientation orientation, Point center) { @@ -49,8 +47,7 @@ public End(Orientation orientation, int x, int y) { public End(Orientation orientation, int x, int y, int width, int height) { super(TileType.END, orientation, x, y, width, height); - - setModel(new DefaultTileModel()); + setModel(new DefaultTileModel(orientation)); } @Override @@ -147,5 +144,4 @@ public void renderTileRoute(Graphics2D g2d) { // long now = System.currentTimeMillis(); // Logger.trace(this.id + " Duration: " + (now - started) + " ms."); // } - } diff --git a/src/main/java/jcs/ui/layout/tiles/Straight.java b/src/main/java/jcs/ui/layout/tiles/Straight.java index 96685548..9cc63d74 100755 --- a/src/main/java/jcs/ui/layout/tiles/Straight.java +++ b/src/main/java/jcs/ui/layout/tiles/Straight.java @@ -30,7 +30,7 @@ public class Straight extends Tile { public Straight(TileBean tileBean) { super(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); - setModel(new DefaultTileModel()); + setModel(new DefaultTileModel(tileBean.getOrientation())); } public Straight(Orientation orientation, Point center) { @@ -43,7 +43,7 @@ public Straight(Orientation orientation, int x, int y) { public Straight(Orientation orientation, int x, int y, int width, int height) { super(TileType.STRAIGHT, orientation, x, y, width, height); - setModel(new DefaultTileModel()); + setModel(new DefaultTileModel(orientation)); } @Override diff --git a/src/main/java/jcs/ui/layout/tiles/Switch.java b/src/main/java/jcs/ui/layout/tiles/Switch.java index de49b9ae..abfd920f 100644 --- a/src/main/java/jcs/ui/layout/tiles/Switch.java +++ b/src/main/java/jcs/ui/layout/tiles/Switch.java @@ -54,7 +54,7 @@ public Switch(Orientation orientation, Direction direction, int x, int y, int wi protected Switch(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { super(tileType, orientation, direction, x, y, width, height); - setModel(new DefaultTileModel()); + setModel(new DefaultTileModel(orientation)); } public Switch(TileBean tileBean) { @@ -63,7 +63,7 @@ public Switch(TileBean tileBean) { protected Switch(TileBean tileBean, int width, int height) { super(tileBean, width, height); - setModel(new DefaultTileModel()); + setModel(new DefaultTileModel(tileBean.getOrientation())); } @Override diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java index da73f3fd..fdf6acf3 100755 --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -104,7 +104,7 @@ public abstract class Tile extends JComponent { //implements TileEventListener { protected int renderWidth; protected int renderHeight; - protected Orientation tileOrientation; + //protected Orientation tileOrientation; protected Direction tileDirection; protected TileType tileType; @@ -163,7 +163,8 @@ protected Tile(TileType tileType, Orientation orientation, Direction direction, protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height, Color backgroundColor, Color selectedColor) { this.tileType = tileType; - this.tileOrientation = orientation; + //this.tileOrientation = orientation; + //model.setTileOrienation(orientation); this.tileDirection = direction; this.tileX = x; this.tileY = y; @@ -197,7 +198,8 @@ protected Tile(TileBean tileBean, int width, int height) { //Quick properties this.id = tileBean.getId(); this.tileType = tileBean.getTileType(); - this.tileOrientation = tileBean.getOrientation(); + //this.tileOrientation = tileBean.getOrientation(); + //this.model.setTileOrienation(tileBean.getOrientation()); this.tileDirection = tileBean.getDirection(); this.tileX = tileBean.getX(); this.tileY = tileBean.getY(); @@ -276,7 +278,9 @@ public TileBean getTileBean() { tileBean.setX(this.tileX); tileBean.setY(this.tileY); tileBean.setTileType(this.tileType); - tileBean.setTileOrientation(this.tileOrientation.getOrientation()); + //tileBean.setTileOrientation(this.tileOrientation.getOrientation()); + tileBean.setTileOrientation(this.model.getTileOrienation().getOrientation()); + tileBean.setTileDirection(this.tileDirection.getDirection()); tileBean.setSignalType(this.signalType); tileBean.setAccessoryId(this.accessoryId); @@ -334,11 +338,13 @@ public void setCenter(Point center) { } public Orientation getOrientation() { - return tileOrientation; + //return tileOrientation; + return model.getTileOrienation(); } public void setOrientation(Orientation orientation) { - this.tileOrientation = orientation; + //this.tileOrientation = orientation; + model.setTileOrienation(orientation); if (tileBean != null) { tileBean.setOrientation(orientation); } @@ -615,9 +621,10 @@ public int getRenderHeight() { */ public void drawTile(Graphics2D g2d) { // by default and image is rendered in the EAST orientation - if (tileOrientation == null) { - tileOrientation = Orientation.EAST; - } + Orientation tileOrientation = model.getTileOrienation(); +// if (tileOrientation == null) { +// tileOrientation = Orientation.EAST; +// } BufferedImage bf = createImage(); Graphics2D g2di = bf.createGraphics(); @@ -718,6 +725,7 @@ protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { * @return the new Orientation */ public Orientation rotate() { + Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case EAST -> setOrientation(Orientation.SOUTH); @@ -728,10 +736,11 @@ public Orientation rotate() { default -> setOrientation(Orientation.EAST); } - return tileOrientation; + return model.getTileOrienation(); } public void flipHorizontal() { + Orientation tileOrientation = model.getTileOrienation(); if (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) { rotate(); rotate(); @@ -739,7 +748,8 @@ public void flipHorizontal() { } public void flipVertical() { - if (Orientation.EAST.equals(getOrientation()) || Orientation.WEST.equals(getOrientation())) { + Orientation tileOrientation = model.getTileOrienation(); + if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { rotate(); rotate(); } @@ -881,6 +891,7 @@ public String xyToString() { * @return true when main route goes from East to West or vv */ public boolean isHorizontal() { + Orientation tileOrientation = model.getTileOrienation(); return (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) && TileType.CURVED != tileType; } @@ -890,6 +901,7 @@ public boolean isHorizontal() { * @return true when main route goes from North to South or vv */ public boolean isVertical() { + Orientation tileOrientation = model.getTileOrienation(); return (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) && TileType.CURVED != tileType; } @@ -1091,7 +1103,14 @@ protected void fireActionPerformed(ActionEvent event) { } public Rectangle getTileBounds() { - return new Rectangle(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); + //return new Rectangle(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); + + if (model.isScaleImage()) { + return new Rectangle(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); + } else { + return new Rectangle(tileX - renderWidth / 2, tileY - renderHeight / 2, renderWidth, renderHeight); + } + } @Override diff --git a/src/main/java/jcs/ui/layout/tiles/TileFactory.java b/src/main/java/jcs/ui/layout/tiles/TileFactory.java index 203796ba..f1522721 100755 --- a/src/main/java/jcs/ui/layout/tiles/TileFactory.java +++ b/src/main/java/jcs/ui/layout/tiles/TileFactory.java @@ -228,8 +228,8 @@ public static Tile createTile(TileBean tileBean, boolean showValues) { * @param drawOutline whether the outline of the tile must be rendered * @return a Tile object */ - public static Tile createTile(TileBean.TileType tileType, Orientation orientation, int x, int y, boolean drawOutline) { - return createTile(tileType, orientation, Direction.CENTER, x, y, drawOutline); + public static Tile createTile(TileBean.TileType tileType, Orientation orientation, int x, int y) { + return createTile(tileType, orientation, Direction.CENTER, x, y); } /** @@ -238,14 +238,13 @@ public static Tile createTile(TileBean.TileType tileType, Orientation orientatio * @param direction direction plays a role with Turnout tiles whether it goes to the Left or Right * @param x the tile center X * @param y the tile center Y - * @param drawOutline whether the outline of the tile must be rendered * @return a Tile object */ - public static Tile createTile(TileBean.TileType tileType, Orientation orientation, Direction direction, int x, int y, boolean drawOutline) { - return createTile(tileType, orientation, direction, new Point(x, y), drawOutline); + public static Tile createTile(TileBean.TileType tileType, Orientation orientation, Direction direction, int x, int y) { + return createTile(tileType, orientation, direction, new Point(x, y)); } - public static Tile createTile(TileBean.TileType tileType, Orientation orientation, Direction direction, Point center, boolean drawOutline) { + public static Tile createTile(TileBean.TileType tileType, Orientation orientation, Direction direction, Point center) { Tile tile = null; switch (tileType) { case STRAIGHT -> { @@ -275,11 +274,9 @@ public static Tile createTile(TileBean.TileType tileType, Orientation orientatio } if (tile != null) { - //tile.setDrawOutline(drawOutline); tile.setId(nextTileId(tileType)); } -// addTileEventListener((TileEventListener) tile); return (Tile) tile; } diff --git a/src/main/java/jcs/ui/layout/tiles/TileModel.java b/src/main/java/jcs/ui/layout/tiles/TileModel.java index 46f144f3..84b78bf0 100644 --- a/src/main/java/jcs/ui/layout/tiles/TileModel.java +++ b/src/main/java/jcs/ui/layout/tiles/TileModel.java @@ -20,6 +20,7 @@ import javax.swing.event.ChangeListener; import jcs.entities.BlockBean; import jcs.entities.LocomotiveBean; +import jcs.entities.TileBean; /** * @@ -39,6 +40,10 @@ public interface TileModel extends Serializable { public void setShowCenter(boolean showCenter); + public TileBean.Orientation getTileOrienation(); + + void setTileOrienation(TileBean.Orientation tileOrienation); + boolean isShowRoute(); public void setShowRoute(boolean showRoute); diff --git a/src/test/java/jcs/ui/layout/TileTest.java b/src/test/java/jcs/ui/layout/TileTest.java index 244a7d39..cd18f276 100644 --- a/src/test/java/jcs/ui/layout/TileTest.java +++ b/src/test/java/jcs/ui/layout/TileTest.java @@ -39,7 +39,7 @@ public TileTest() { @Test public void testgetCenterX() { System.out.println("getCenterX"); - Tile instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 180, 100, false); + Tile instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 180, 100); int expResult = 180; int result = instance.getCenterX(); assertEquals(expResult, result); @@ -49,30 +49,22 @@ public void testgetCenterX() { public void testgetCenterXZero() { System.out.println("getCenterX"); Tile instance - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 0, 0, false); + = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 0, 0); int expResult = 20; int result = instance.getCenterX(); assertEquals(expResult, result); } -// public int getGridX() { -// return (getCenterX() - Tile.GRID) / (Tile.GRID * 2); -// } -// public int getGridY() { -// return (getCenterY() - Tile.GRID) / (Tile.GRID * 2); -// } @Test public void testGetGridX() { System.out.println("getGridX"); - Tile instance - = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 100, 100, false); + Tile instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 100, 100); int expResult = 2; int result = (instance.getTileX() - Tile.GRID) / (Tile.GRID * 2); assertEquals(expResult, result); - instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 220, 220, false); + instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 220, 220); expResult = 5; result = (instance.getTileX() - Tile.GRID) / (Tile.GRID * 2); @@ -82,7 +74,7 @@ public void testGetGridX() { @Test public void testgetCenterY() { System.out.println("getCenterY"); - Tile instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 180, 100, false); + Tile instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 180, 100); int expResult = 100; int result = instance.getCenterY(); assertEquals(expResult, result); @@ -91,7 +83,7 @@ public void testgetCenterY() { @Test public void testgetCenterYZero() { System.out.println("getCenterY"); - Tile instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 0, 0, false); + Tile instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 0, 0); int expResult = 20; int result = instance.getCenterY(); assertEquals(expResult, result); @@ -100,7 +92,7 @@ public void testgetCenterYZero() { @Test public void testGetGridY() { System.out.println("getGridY"); - Tile instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 100, 140, false); + Tile instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 100, 140); int expResult = 3; int result = (instance.getTileY() - Tile.GRID) / (Tile.GRID * 2); assertEquals(expResult, result); @@ -110,8 +102,7 @@ public void testGetGridY() { public void testGetAllPoints() { System.out.println("getAllPoints"); Tile instance - = TileFactory.createTile( - TileBean.TileType.BLOCK, Orientation.WEST, Direction.CENTER, 220, 220, false); + = TileFactory.createTile(TileBean.TileType.BLOCK, Orientation.WEST, Direction.CENTER, 220, 220); Set expResult = new HashSet<>(); expResult.add(new Point(220, 220)); expResult.add(new Point(180, 220)); @@ -126,8 +117,7 @@ public void testGetAllPoints() { public void testGetAltPointsBlock() { System.out.println("getAltPointsBlock"); Tile instance - = TileFactory.createTile( - TileBean.TileType.BLOCK, Orientation.WEST, Direction.CENTER, 220, 220, false); + = TileFactory.createTile(TileBean.TileType.BLOCK, Orientation.WEST, Direction.CENTER, 220, 220); Set expResult = new HashSet<>(); expResult.add(new Point(180, 220)); expResult.add(new Point(260, 220)); @@ -140,16 +130,16 @@ public void testGetAltPointsCross() { System.out.println("getAltPointsCross"); Tile instanceE = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.EAST, Direction.CENTER, 220, 220, false); + TileBean.TileType.CROSS, Orientation.EAST, Direction.CENTER, 220, 220); Tile instanceS = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.SOUTH, Direction.CENTER, 220, 220, false); + TileBean.TileType.CROSS, Orientation.SOUTH, Direction.CENTER, 220, 220); Tile instanceW = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.WEST, Direction.CENTER, 220, 220, false); + TileBean.TileType.CROSS, Orientation.WEST, Direction.CENTER, 220, 220); Tile instanceN = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.NORTH, Direction.CENTER, 220, 220, false); + TileBean.TileType.CROSS, Orientation.NORTH, Direction.CENTER, 220, 220); Set expResultE = new HashSet<>(); expResultE.add(new Point(260, 220)); @@ -186,31 +176,31 @@ public void testGetNeighborPointsCross() { System.out.println("getNeighborPointsCross"); Tile instanceEL = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.EAST, Direction.LEFT, 220, 220, false); + TileBean.TileType.CROSS, Orientation.EAST, Direction.LEFT, 220, 220); Tile instanceER = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.EAST, Direction.RIGHT, 220, 220, false); + TileBean.TileType.CROSS, Orientation.EAST, Direction.RIGHT, 220, 220); Tile instanceWL = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.WEST, Direction.LEFT, 220, 220, false); + TileBean.TileType.CROSS, Orientation.WEST, Direction.LEFT, 220, 220); Tile instanceWR = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.WEST, Direction.RIGHT, 220, 220, false); + TileBean.TileType.CROSS, Orientation.WEST, Direction.RIGHT, 220, 220); Tile instanceSL = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.SOUTH, Direction.LEFT, 220, 220, false); + TileBean.TileType.CROSS, Orientation.SOUTH, Direction.LEFT, 220, 220); Tile instanceSR = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.SOUTH, Direction.RIGHT, 220, 220, false); + TileBean.TileType.CROSS, Orientation.SOUTH, Direction.RIGHT, 220, 220); Tile instanceNL = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.NORTH, Direction.LEFT, 220, 220, false); + TileBean.TileType.CROSS, Orientation.NORTH, Direction.LEFT, 220, 220); Tile instanceNR = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.NORTH, Direction.RIGHT, 220, 220, false); + TileBean.TileType.CROSS, Orientation.NORTH, Direction.RIGHT, 220, 220); Map expResultEL = new HashMap<>(); expResultEL.put(Orientation.EAST, new Point(300, 220)); @@ -298,23 +288,23 @@ public void testIsAdjacentStraight() { System.out.println("isAdjacentStraight"); Tile instanceE = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 100, 100, false); + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 100, 100); Tile instanceN = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 100, 100, false); + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 100, 100); Tile west = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 60, 100, false); + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 60, 100); Tile east = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 140, 100, false); + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 140, 100); Tile north = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 100, 60, false); + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 100, 60); Tile south = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 100, 140, false); + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 100, 140); assertTrue(instanceE.isAdjacent(west)); assertTrue(instanceE.isAdjacent(east)); @@ -333,31 +323,31 @@ public void testIsAdjacentBlock() { Tile instanceE = TileFactory.createTile( - TileBean.TileType.BLOCK, Orientation.EAST, Direction.CENTER, 220, 220, false); + TileBean.TileType.BLOCK, Orientation.EAST, Direction.CENTER, 220, 220); Tile instanceW = TileFactory.createTile( - TileBean.TileType.BLOCK, Orientation.WEST, Direction.CENTER, 220, 220, false); + TileBean.TileType.BLOCK, Orientation.WEST, Direction.CENTER, 220, 220); Tile instanceS = TileFactory.createTile( - TileBean.TileType.BLOCK, Orientation.SOUTH, Direction.CENTER, 220, 220, false); + TileBean.TileType.BLOCK, Orientation.SOUTH, Direction.CENTER, 220, 220); Tile instanceN = TileFactory.createTile( - TileBean.TileType.BLOCK, Orientation.NORTH, Direction.CENTER, 220, 220, false); + TileBean.TileType.BLOCK, Orientation.NORTH, Direction.CENTER, 220, 220); Tile west = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 140, 220, false); + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 140, 220); Tile east = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 300, 220, false); + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 300, 220); Tile north = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 220, 140, false); + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 220, 140); Tile south = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 220, 300, false); + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 220, 300); assertTrue(instanceE.isAdjacent(west)); assertTrue(instanceE.isAdjacent(east)); @@ -380,29 +370,29 @@ public void testIsAdjacentCurved() { System.out.println("isAdjacentCurved"); Tile instanceE = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 860, 140, false); + TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 860, 140); Tile instanceN = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 860, 140, false); + TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 860, 140); Tile instanceW = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 860, 140, false); + TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 860, 140); Tile instanceS = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 860, 140, false); + TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 860, 140); Tile straightE = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 140, false); + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 140); Tile straightN = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 100, false); + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 100); Tile straightW = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 140, false); + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 140); Tile straightS = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180, false); + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180); assertTrue(instanceE.isAdjacent(straightE)); assertFalse(instanceE.isAdjacent(straightN)); @@ -431,29 +421,29 @@ public void testIsAdjacentEnd() { Tile instanceE = TileFactory.createTile( - TileBean.TileType.END, Orientation.EAST, Direction.CENTER, 860, 140, false); + TileBean.TileType.END, Orientation.EAST, Direction.CENTER, 860, 140); Tile instanceS = TileFactory.createTile( - TileBean.TileType.END, Orientation.SOUTH, Direction.CENTER, 860, 140, false); + TileBean.TileType.END, Orientation.SOUTH, Direction.CENTER, 860, 140); Tile instanceW = TileFactory.createTile( - TileBean.TileType.END, Orientation.WEST, Direction.CENTER, 860, 140, false); + TileBean.TileType.END, Orientation.WEST, Direction.CENTER, 860, 140); Tile instanceN = TileFactory.createTile( - TileBean.TileType.END, Orientation.NORTH, Direction.CENTER, 860, 140, false); + TileBean.TileType.END, Orientation.NORTH, Direction.CENTER, 860, 140); Tile straightE = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 140, false); + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 140); Tile straightN = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 100, false); + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 100); Tile straightW = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 140, false); + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 140); Tile straightS = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180, false); + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180); assertFalse(instanceE.isAdjacent(straightE)); assertFalse(instanceE.isAdjacent(straightS)); @@ -481,30 +471,30 @@ public void testgetIdSuffix() { System.out.println("getGetIdSuffix"); Tile instanceE = TileFactory.createTile( - TileBean.TileType.BLOCK, Orientation.EAST, Direction.CENTER, 220, 220, false); + TileBean.TileType.BLOCK, Orientation.EAST, Direction.CENTER, 220, 220); Tile instanceW = TileFactory.createTile( - TileBean.TileType.BLOCK, Orientation.WEST, Direction.CENTER, 220, 220, false); + TileBean.TileType.BLOCK, Orientation.WEST, Direction.CENTER, 220, 220); Tile instanceN = TileFactory.createTile( - TileBean.TileType.BLOCK, Orientation.NORTH, Direction.CENTER, 220, 220, false); + TileBean.TileType.BLOCK, Orientation.NORTH, Direction.CENTER, 220, 220); Tile instanceS = TileFactory.createTile( - TileBean.TileType.BLOCK, Orientation.SOUTH, Direction.CENTER, 220, 220, false); + TileBean.TileType.BLOCK, Orientation.SOUTH, Direction.CENTER, 220, 220); Tile west = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 140, 220, false); + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 140, 220); Tile east = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 300, 220, false); + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 300, 220); Tile north = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 220, 140, false); + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 220, 140); Tile south = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 220, 300, false); + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 220, 300); String expResult = "-"; String result = instanceE.getIdSuffix(west); @@ -535,55 +525,55 @@ public void testIsAdjacentSwitchL() { System.out.println("isAdjacentSwitchL"); Tile instanceE = TileFactory.createTile( - TileBean.TileType.SWITCH, Orientation.EAST, Direction.LEFT, 1060, 140, false); + TileBean.TileType.SWITCH, Orientation.EAST, Direction.LEFT, 1060, 140); Tile instanceS = TileFactory.createTile( - TileBean.TileType.SWITCH, Orientation.SOUTH, Direction.LEFT, 1060, 140, false); + TileBean.TileType.SWITCH, Orientation.SOUTH, Direction.LEFT, 1060, 140); Tile instanceW = TileFactory.createTile( - TileBean.TileType.SWITCH, Orientation.WEST, Direction.LEFT, 1060, 140, false); + TileBean.TileType.SWITCH, Orientation.WEST, Direction.LEFT, 1060, 140); Tile instanceN = TileFactory.createTile( - TileBean.TileType.SWITCH, Orientation.NORTH, Direction.LEFT, 1060, 140, false); + TileBean.TileType.SWITCH, Orientation.NORTH, Direction.LEFT, 1060, 140); Tile north = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 1060, 100, false); + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 1060, 100); Tile west = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 1020, 140, false); + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 1020, 140); Tile east = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 1100, 140, false); + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 1100, 140); Tile south = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 1060, 180, false); + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 1060, 180); Tile westCS = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 1020, 140, false); + TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 1020, 140); Tile westCE = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 1020, 140, false); + TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 1020, 140); Tile westCW = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 1020, 140, false); + TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 1020, 140); Tile westCN = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 1020, 140, false); + TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 1020, 140); Tile southCS = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 1060, 180, false); + TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 1060, 180); Tile southCE = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 1060, 180, false); + TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 1060, 180); Tile southCW = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 1060, 180, false); + TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 1060, 180); Tile southCN = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 1060, 180, false); + TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 1060, 180); assertTrue(instanceE.isAdjacent(west)); assertTrue(instanceE.isAdjacent(east)); @@ -621,55 +611,55 @@ public void testIsAdjacentSwitchR() { System.out.println("isAdjacentSwitchR"); Tile instanceE = TileFactory.createTile( - TileBean.TileType.SWITCH, Orientation.EAST, Direction.RIGHT, 1060, 140, false); + TileBean.TileType.SWITCH, Orientation.EAST, Direction.RIGHT, 1060, 140); Tile instanceS = TileFactory.createTile( - TileBean.TileType.SWITCH, Orientation.SOUTH, Direction.RIGHT, 1060, 140, false); + TileBean.TileType.SWITCH, Orientation.SOUTH, Direction.RIGHT, 1060, 140); Tile instanceW = TileFactory.createTile( - TileBean.TileType.SWITCH, Orientation.WEST, Direction.RIGHT, 1060, 140, false); + TileBean.TileType.SWITCH, Orientation.WEST, Direction.RIGHT, 1060, 140); Tile instanceN = TileFactory.createTile( - TileBean.TileType.SWITCH, Orientation.NORTH, Direction.RIGHT, 1060, 140, false); + TileBean.TileType.SWITCH, Orientation.NORTH, Direction.RIGHT, 1060, 140); Tile north = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 1060, 100, false); + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 1060, 100); Tile west = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 1020, 140, false); + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 1020, 140); Tile east = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 1100, 140, false); + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 1100, 140); Tile south = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 1060, 180, false); + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 1060, 180); Tile eastCS = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 1100, 140, false); + TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 1100, 140); Tile eastCE = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 1100, 140, false); + TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 1100, 140); Tile eastCW = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 1100, 140, false); + TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 1100, 140); Tile eastCN = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 1100, 140, false); + TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 1100, 140); Tile northCS = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 1060, 100, false); + TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 1060, 100); Tile northCE = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 1060, 100, false); + TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 1060, 100); Tile northCW = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 1060, 100, false); + TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 1060, 100); Tile northCN = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 1060, 100, false); + TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 1060, 100); assertTrue(instanceE.isAdjacent(west)); assertTrue(instanceE.isAdjacent(east)); @@ -707,29 +697,29 @@ public void testIsArrowSwitchSide() { System.out.println("isArrowSwitchSide"); Tile instanceE = TileFactory.createTile( - TileBean.TileType.STRAIGHT_DIR, Orientation.EAST, Direction.RIGHT, 860, 140, false); + TileBean.TileType.STRAIGHT_DIR, Orientation.EAST, Direction.RIGHT, 860, 140); Tile instanceS = TileFactory.createTile( - TileBean.TileType.STRAIGHT_DIR, Orientation.SOUTH, Direction.RIGHT, 860, 140, false); + TileBean.TileType.STRAIGHT_DIR, Orientation.SOUTH, Direction.RIGHT, 860, 140); Tile instanceW = TileFactory.createTile( - TileBean.TileType.STRAIGHT_DIR, Orientation.WEST, Direction.RIGHT, 860, 140, false); + TileBean.TileType.STRAIGHT_DIR, Orientation.WEST, Direction.RIGHT, 860, 140); Tile instanceN = TileFactory.createTile( - TileBean.TileType.STRAIGHT_DIR, Orientation.NORTH, Direction.RIGHT, 860, 140, false); + TileBean.TileType.STRAIGHT_DIR, Orientation.NORTH, Direction.RIGHT, 860, 140); Tile straighE = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 140, false); + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 140); Tile straighS = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180, false); + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180); Tile straighW = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 140, false); + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 140); Tile straighN = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 100, false); + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 100); assertTrue(instanceE.isArrowDirection(straighE)); assertFalse(instanceE.isArrowDirection(straighW)); @@ -749,53 +739,53 @@ public void testIsAdjacentCrossL() { System.out.println("iIsAdjacentCrossL"); Tile instanceE = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.EAST, Direction.LEFT, 860, 100, false); + TileBean.TileType.CROSS, Orientation.EAST, Direction.LEFT, 860, 100); Tile instanceS = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.SOUTH, Direction.LEFT, 860, 100, false); + TileBean.TileType.CROSS, Orientation.SOUTH, Direction.LEFT, 860, 100); Tile instanceW = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.WEST, Direction.LEFT, 860, 100, false); + TileBean.TileType.CROSS, Orientation.WEST, Direction.LEFT, 860, 100); Tile instanceN = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.NORTH, Direction.LEFT, 860, 100, false); + TileBean.TileType.CROSS, Orientation.NORTH, Direction.LEFT, 860, 100); Tile north = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 900, 60, false); + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 900, 60); Tile north2 = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 60, false); + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 60); Tile north3 = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 20, false); + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 20); Tile west = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 100, false); + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 100); Tile west2 = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 780, 100, false); + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 780, 100); Tile west3 = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 60, false); + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 60); Tile east = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 940, 100, false); + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 940, 100); Tile east2 = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 100, false); + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 100); Tile east3 = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 140, false); + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 140); Tile south = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 140, false); + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 140); Tile south2 = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 820, 140, false); + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 820, 140); Tile south3 = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180, false); + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180); assertTrue(instanceE.isAdjacent(west)); assertTrue(instanceE.isAdjacent(east)); @@ -823,60 +813,60 @@ public void testIsAdjacentCrossR() { System.out.println("iIsAdjacentCrossR"); Tile instanceE = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.EAST, Direction.RIGHT, 860, 100, false); + TileBean.TileType.CROSS, Orientation.EAST, Direction.RIGHT, 860, 100); Tile instanceS = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.SOUTH, Direction.RIGHT, 860, 100, false); + TileBean.TileType.CROSS, Orientation.SOUTH, Direction.RIGHT, 860, 100); Tile instanceW = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.WEST, Direction.RIGHT, 860, 100, false); + TileBean.TileType.CROSS, Orientation.WEST, Direction.RIGHT, 860, 100); Tile instanceN = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.NORTH, Direction.RIGHT, 860, 100, false); + TileBean.TileType.CROSS, Orientation.NORTH, Direction.RIGHT, 860, 100); Tile north = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 60, false); + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 60); Tile north2 = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 60, false); + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 60); Tile north3 = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 20, false); + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 20); Tile north4 = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 820, 60, false); + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 820, 60); Tile west = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 140, false); + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 140); Tile west2 = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 100, false); + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 100); Tile west3 = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 860, 100, false); + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 860, 100); Tile west4 = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 780, 100, false); + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 780, 100); Tile east = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 940, 100, false); + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 940, 100); Tile east2 = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 60, false); + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 60); Tile east3 = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 100, false); + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 100); Tile south = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 140, false); + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 140); Tile south2 = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 900, 140, false); + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 900, 140); Tile south3 = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180, false); + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180); assertTrue(instanceE.isAdjacent(west2)); assertTrue(instanceE.isAdjacent(east)); @@ -902,14 +892,14 @@ public void testIsAdjacentCrossR() { @Test public void testIsAdjacentCrossing() { System.out.println("isAdjacentCrossing"); - Tile instanceE = TileFactory.createTile(TileBean.TileType.CROSSING, Orientation.EAST, Direction.CENTER, 100, 100, false); + Tile instanceE = TileFactory.createTile(TileBean.TileType.CROSSING, Orientation.EAST, Direction.CENTER, 100, 100); - Tile instanceN = TileFactory.createTile(TileBean.TileType.CROSSING, Orientation.NORTH, Direction.CENTER, 100, 100, false); + Tile instanceN = TileFactory.createTile(TileBean.TileType.CROSSING, Orientation.NORTH, Direction.CENTER, 100, 100); - Tile west = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 60, 100, false); - Tile east = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 140, 100, false); - Tile north = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 100, 60, false); - Tile south = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 100, 140, false); + Tile west = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 60, 100); + Tile east = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 140, 100); + Tile north = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 100, 60); + Tile south = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 100, 140); assertTrue(instanceE.isAdjacent(west)); assertTrue(instanceE.isAdjacent(east)); diff --git a/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java b/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java index a789e06b..d9b5d190 100644 --- a/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java +++ b/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java @@ -23,24 +23,19 @@ import javax.swing.JPanel; import org.tinylog.Logger; + +// jcs.ui.layout.tiles.DotGridCanvas + public class DotGridCanvas extends JPanel { + private boolean expanded; + public DotGridCanvas() { super(null, false); setOpaque(true); - setBackground(Color.white); + //setBackground(Color.white); } -// @Override -// protected void paintComponent(Graphics g) { -// long started = System.currentTimeMillis(); -// super.paintComponent(g); -// -// paintDotGrid(g); -// long now = System.currentTimeMillis(); -// Logger.trace("Duration: " + (now - started) + " ms."); -// } - @Override public void paint(Graphics g) { long started = System.currentTimeMillis(); @@ -50,9 +45,7 @@ public void paint(Graphics g) { long now = System.currentTimeMillis(); Logger.trace("Duration: " + (now - started) + " ms."); } - - - + @Override public Component add(Component component) { super.add(component); @@ -66,20 +59,33 @@ private void paintDotGrid(Graphics g) { int width = this.getWidth(); int height = this.getHeight(); - int xOffset = 0; - int yOffset = 0; + int grid; + if (expanded) { + grid = 20; + } else { + grid = 20; + } - //Logger.trace("W: " + width + " H: " + height + " X: " + this.getX() + " Y: " + this.getY()); Graphics2D gc = (Graphics2D) g; Paint p = gc.getPaint(); gc.setPaint(Color.black); for (int r = 0; r < width; r++) { for (int c = 0; c < height; c++) { - gc.drawOval((r * 20 * 2) + xOffset - 2, (c * 20 * 2) + yOffset - 2, 4, 4); + gc.drawOval((r * grid * 2) - 2, (c * grid * 2) - 2, 4, 4); } } gc.setPaint(p); + + } + + public boolean isExpanded() { + return expanded; + } + + public void setExpanded(boolean expanded) { + this.expanded = expanded; + this.repaint(); } } diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.form b/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.form similarity index 91% rename from src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.form rename to src/test/java/jcs/ui/layout/tiles/TileTesterFrame.form index a7bb9ab5..9b77fbc1 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.form +++ b/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.form @@ -22,12 +22,20 @@ - + + + + + + + + + @@ -162,12 +170,20 @@
- + + + + + + + + + - + - + @@ -390,11 +406,27 @@ - - + + + + + + + + + + + + + + + + + + - + @@ -402,15 +434,12 @@
- + - + - - - diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.java b/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java similarity index 74% rename from src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.java rename to src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java index 43e5bf53..c5e311b7 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.java +++ b/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java @@ -16,11 +16,9 @@ package jcs.ui.layout.tiles; import java.awt.Color; -import java.awt.Graphics; import java.awt.Point; import javax.swing.ComboBoxModel; import javax.swing.DefaultComboBoxModel; -import javax.swing.JComponent; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import jcs.entities.AccessoryBean; @@ -32,29 +30,26 @@ import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; +import jcs.ui.layout.LayoutUtil; import jcs.ui.layout.events.TileEvent; import org.tinylog.Logger; -/** - * - * @author FJA - */ -public class UnscaledTileFrame extends javax.swing.JFrame { +public class TileTesterFrame extends javax.swing.JFrame { private Tile tile; - /** - * Creates new form UnscaledBlockTileFrame - */ - public UnscaledTileFrame() { + public TileTesterFrame() { initComponents(); this.tileCB.setModel(createTileTypeComboBoxModel()); this.orientationCB.setModel(createOrientationComboBoxModel()); this.incomingSideCB.setModel(createOrientationComboBoxModel()); this.directionCB.setModel(createDirectionComboBoxModel(true)); - //drawTile(); - addTile(); + createTile(); + + pack(); + + setVisible(true); } private ComboBoxModel createTileTypeComboBoxModel() { @@ -97,75 +92,78 @@ private ComboBoxModel createDirectionComboBoxModel(boolean dontCare) return directionModel; } - private void addTile() { - if (this.tile != null) { - Logger.trace("Removing tile " + this.tile.getId()); - this.cPanel.remove((JComponent) this.tile); - this.tile = null; + private void createTile() { + if (tile != null) { + Logger.trace("Removing tile " + tile.getId()); + canvas.remove(tile); + tile = null; } - TileType tileType = (TileType) this.tileCB.getSelectedItem(); - Orientation orientation = (Orientation) this.orientationCB.getSelectedItem(); + TileType tileType = (TileType) tileCB.getSelectedItem(); + Orientation orientation = (Orientation) orientationCB.getSelectedItem(); if (TileType.SWITCH == tileType || TileType.CROSS == tileType) { - this.directionCB.setModel(createDirectionComboBoxModel(false)); + directionCB.setModel(createDirectionComboBoxModel(false)); } else { - this.directionCB.setModel(createDirectionComboBoxModel(true)); + directionCB.setModel(createDirectionComboBoxModel(true)); } Direction direction = (Direction) this.directionCB.getSelectedItem(); - boolean showOutline = this.drawOutlineCB.isSelected(); - - int w = this.cPanel.getWidth(); - int h = this.cPanel.getHeight(); - - int x; - int y; - if (TileType.CROSS == tileType) { - switch (orientation) { - case SOUTH -> { - x = w / 2 + 200; - y = h / 2 - 150; - } - case WEST -> { - x = w / 2 + 400; - y = h / 2 + 50; - } - case NORTH -> { - x = w / 2 + 200; - y = h / 2 + 250; - } - default -> { - x = w / 2; - y = h / 2 + 50; - } - } - } else { - x = w / 2 - 200; - y = h / 2 - 200; - } - - Point center; - if (TileType.CROSS.equals(tileType)) { - center = new Point(x - 200, y); - } else { - center = new Point(x, y); - } - - Tile newTile = TileFactory.createTile(tileType, orientation, direction, center, showOutline); - newTile.setScaleImage(false); + boolean scale = !scaleCB.isSelected(); + boolean showCenter = showCenterCB.isSelected(); + + int w = canvas.getWidth(); + int h = canvas.getHeight(); + + int x = w / 2; + int y = h / 2; + Point tileCenter = new Point(x, y); + tileCenter = LayoutUtil.snapToGrid(tileCenter); + +// if (TileType.CROSS == tileType) { +// switch (orientation) { +// case SOUTH -> { +// x = w / 2 + 200; +// y = h / 2 - 150; +// } +// case WEST -> { +// x = w / 2 + 400; +// y = h / 2 + 50; +// } +// case NORTH -> { +// x = w / 2 + 200; +// y = h / 2 + 250; +// } +// default -> { +// x = w / 2; +// y = h / 2 + 50; +// } +// } +// } else { +// x = w / 2 - 200; +// y = h / 2 - 200; +// } +// Point center; +// if (TileType.CROSS.equals(tileType)) { +// center = new Point(x - 200, y); +// } else { +// center = new Point(x, y); +// } + Tile newTile = TileFactory.createTile(tileType, orientation, direction, tileCenter); + newTile.setScaleImage(scale); + newTile.setDrawCenterPoint(showCenter); //tile.setPropertyChangeListener(this); Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); newTile.setIncomingSide(incomingSide); - newTile.setDrawRoute(this.displayRouteCB.isSelected()); + newTile.setDrawRoute(displayRouteCB.isSelected()); newTile.setTrackRouteColor(Color.blue); Logger.trace("Adding tile " + newTile.getId() + " " + newTile.xyToString()); //this.cPanel.add((JComponent) newTile); - this.cPanel.add(newTile); + this.canvas.add(newTile); this.tile = newTile; } @@ -183,6 +181,10 @@ private AccessoryValue getAccessoryState() { } private void changeAccesoryState() { + if(tile instanceof Sensor) { + tile.setActive(this.redRB.isSelected()); + } + if (tile instanceof Switch aSwitch) { if (this.displayRouteCB.isSelected()) { aSwitch.setRouteValue(getAccessoryState()); @@ -201,7 +203,7 @@ private void changeAccesoryState() { } } - this.tile.repaint(); + //this.tile.repaint(); } // @Override @@ -227,15 +229,14 @@ private void changeAccesoryState() { // tile.drawCenterPoint(g2d, Color.red); // } // } - @Override - public void paint(Graphics g) { - long started = System.currentTimeMillis(); - super.paint(g); - - long now = System.currentTimeMillis(); - Logger.trace("Duration: " + (now - started) + " ms."); - } - +// @Override +// public void paint(Graphics g) { +// long started = System.currentTimeMillis(); +// super.paint(g); +// +// long now = System.currentTimeMillis(); +// Logger.trace("Duration: " + (now - started) + " ms."); +// } private void changeDirection() { Direction direction = (Direction) this.directionCB.getSelectedItem(); this.tile.setDirection(direction); @@ -247,39 +248,38 @@ private void changeDirection() { } private void rotateTile() { - this.tile.rotate(); - - if (TileType.CROSS == tile.getTileType()) { - int x = tile.getCenterX(); - int y = tile.getCenterY(); - int w = tile.getWidth() * 10; - int h = tile.getHeight() * 10; - - //calculate a new centerpoint for cross - switch (tile.getOrientation()) { - case SOUTH -> { - x = x + w / 2; - y = y - h / 4; - } - case WEST -> { - x = x + w / 4; - y = y + h / 2; - } - case NORTH -> { - x = x - w / 2; - y = y + h / 4; - } - default -> { - x = x - w / 4; - y = y - h / 2; - } - } - tile.setCenter(new Point(x, y)); - } - - this.orientationCB.setSelectedItem(tile.getOrientation()); - - //this.repaint(); + Orientation newOrientation = tile.rotate(); + orientationCB.setSelectedItem(newOrientation); + +// if (TileType.CROSS == tile.getTileType()) { +// int x = tile.getCenterX(); +// int y = tile.getCenterY(); +// int w = tile.getWidth() * 10; +// int h = tile.getHeight() * 10; +// +// //calculate a new centerpoint for cross +// switch (tile.getOrientation()) { +// case SOUTH -> { +// x = x + w / 2; +// y = y - h / 4; +// } +// case WEST -> { +// x = x + w / 4; +// y = y + h / 2; +// } +// case NORTH -> { +// x = x - w / 2; +// y = y + h / 4; +// } +// default -> { +// x = x - w / 4; +// y = y - h / 2; +// } +// } +// tile.setCenter(new Point(x, y)); +// } + //this.canvas.repaint(this.tile.getTileBounds()); + //tile.repaint(); } private void changeOrientation() { @@ -326,12 +326,12 @@ private void showRoute() { String tileId = tile.getId(); Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); - TileEvent tileEvent; + //TileEvent tileEvent; if (tile.isJunction()) { AccessoryValue routeState = getAccessoryState(); - tileEvent = new TileEvent(tileId, true, incomingSide, routeState); + //tileEvent = new TileEvent(tileId, true, incomingSide, routeState); } else { - tileEvent = new TileEvent(tileId, true, incomingSide); + //tileEvent = new TileEvent(tileId, true, incomingSide); } //TileCache.fireTileEventListener(tileEvent); @@ -340,9 +340,9 @@ private void showRoute() { //repaint(); } - private void showOutline() { - //repaint(); - } +// private void showOutline() { +// //repaint(); +// } private void changeIncomingSide() { Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); @@ -369,11 +369,14 @@ private void initComponents() { greenRB = new javax.swing.JRadioButton(); redRB = new javax.swing.JRadioButton(); displayRouteCB = new javax.swing.JCheckBox(); - drawOutlineCB = new javax.swing.JCheckBox(); - cPanel = new javax.swing.JPanel(); + scaleCB = new javax.swing.JCheckBox(); + showCenterCB = new javax.swing.JCheckBox(); + canvas = new jcs.ui.layout.tiles.DotGridCanvas(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + nPanel.setMinimumSize(new java.awt.Dimension(860, 36)); + nPanel.setPreferredSize(new java.awt.Dimension(1020, 36)); java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); flowLayout1.setAlignOnBaseline(true); nPanel.setLayout(flowLayout1); @@ -460,20 +463,26 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { }); nPanel.add(displayRouteCB); - drawOutlineCB.setText("Outline"); - drawOutlineCB.addActionListener(new java.awt.event.ActionListener() { + scaleCB.setText("Scale"); + scaleCB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + scaleCBActionPerformed(evt); + } + }); + nPanel.add(scaleCB); + + showCenterCB.setText("Center"); + showCenterCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - drawOutlineCBActionPerformed(evt); + showCenterCBActionPerformed(evt); } }); - nPanel.add(drawOutlineCB); + nPanel.add(showCenterCB); getContentPane().add(nPanel, java.awt.BorderLayout.NORTH); - cPanel.setPreferredSize(new java.awt.Dimension(800, 800)); - cPanel.setLayout(null); - getContentPane().add(cPanel, java.awt.BorderLayout.CENTER); - cPanel.getAccessibleContext().setAccessibleDescription(""); + canvas.setPreferredSize(new java.awt.Dimension(600, 600)); + getContentPane().add(canvas, java.awt.BorderLayout.CENTER); pack(); }// //GEN-END:initComponents @@ -483,10 +492,7 @@ private void rotateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN- }//GEN-LAST:event_rotateButtonActionPerformed private void tileCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tileCBActionPerformed - addTile(); - //this.tile.repaint(); - - this.repaint(); + createTile(); }//GEN-LAST:event_tileCBActionPerformed private void orientationCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_orientationCBActionPerformed @@ -513,14 +519,19 @@ private void displayRouteCBActionPerformed(java.awt.event.ActionEvent evt) {//GE showRoute(); }//GEN-LAST:event_displayRouteCBActionPerformed - private void drawOutlineCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_drawOutlineCBActionPerformed - showOutline(); - }//GEN-LAST:event_drawOutlineCBActionPerformed + private void scaleCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_scaleCBActionPerformed + this.tile.setScaleImage(!this.scaleCB.isSelected()); + this.tile.setBounds(this.tile.getTileBounds()); + }//GEN-LAST:event_scaleCBActionPerformed private void incomingSideCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_incomingSideCBActionPerformed changeIncomingSide(); }//GEN-LAST:event_incomingSideCBActionPerformed + private void showCenterCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showCenterCBActionPerformed + this.tile.setDrawCenterPoint(this.showCenterCB.isSelected()); + }//GEN-LAST:event_showCenterCBActionPerformed + /** * @param args the command line arguments */ @@ -533,20 +544,17 @@ public static void main(String args[]) { /* Create and display the form */ java.awt.EventQueue.invokeLater(() -> { - UnscaledTileFrame app = new UnscaledTileFrame(); - app.setTitle("Unscaled Tile Tester"); - //app.pack(); + TileTesterFrame app = new TileTesterFrame(); + app.setTitle("Tile Tester"); app.setLocationRelativeTo(null); - app.setVisible(true); }); } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.ButtonGroup accessoryBG; - private javax.swing.JPanel cPanel; + private jcs.ui.layout.tiles.DotGridCanvas canvas; private javax.swing.JComboBox directionCB; private javax.swing.JCheckBox displayRouteCB; - private javax.swing.JCheckBox drawOutlineCB; private javax.swing.JRadioButton greenRB; private javax.swing.JLabel inComingLbl; private javax.swing.JComboBox incomingSideCB; @@ -555,6 +563,8 @@ public static void main(String args[]) { private javax.swing.JComboBox orientationCB; private javax.swing.JRadioButton redRB; private javax.swing.JButton rotateButton; + private javax.swing.JCheckBox scaleCB; + private javax.swing.JCheckBox showCenterCB; private javax.swing.JComboBox tileCB; // End of variables declaration//GEN-END:variables } From 11edd00824785d47247c367613e170415c6d4df0 Mon Sep 17 00:00:00 2001 From: fja-itank Date: Mon, 27 Jan 2025 13:22:17 +0100 Subject: [PATCH 09/70] Fix Cross --- nb-configuration.xml | 40 +- src/main/java/jcs/ui/layout/tiles/Block.java | 784 +----------- src/main/java/jcs/ui/layout/tiles/Cross.java | 656 +--------- src/main/java/jcs/ui/layout/tiles/Tile.java | 1132 +---------------- .../jcs/ui/layout/tiles/TileTesterFrame.form | 455 +------ .../jcs/ui/layout/tiles/TileTesterFrame.java | 571 +-------- 6 files changed, 6 insertions(+), 3632 deletions(-) diff --git a/nb-configuration.xml b/nb-configuration.xml index e5ed60ac..5490e808 100644 --- a/nb-configuration.xml +++ b/nb-configuration.xml @@ -1,39 +1 @@ - - - - - - apache20 - true - 4 - 2 - 4 - 2 - 2 - none - 2 - 2 - true - 2 - 200 - true - none - 4 - 4 - 8 - 80 - true - project - all - - + apache20 true 4 2 4 2 2 none 2 2 true 2 200 true none 4 4 8 80 true project all true true LF false \ No newline at end of file diff --git a/src/main/java/jcs/ui/layout/tiles/Block.java b/src/main/java/jcs/ui/layout/tiles/Block.java index 105cfcdb..e98fa594 100755 --- a/src/main/java/jcs/ui/layout/tiles/Block.java +++ b/src/main/java/jcs/ui/layout/tiles/Block.java @@ -1,783 +1 @@ -/* - * Copyright 2024 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout.tiles; - -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.Image; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.geom.Ellipse2D; -import java.awt.image.BufferedImage; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import jcs.entities.BlockBean; -import jcs.entities.BlockBean.BlockState; -import jcs.entities.LocomotiveBean; -import jcs.entities.TileBean; -import jcs.entities.TileBean.Orientation; -import static jcs.entities.TileBean.Orientation.EAST; -import static jcs.entities.TileBean.Orientation.NORTH; -import static jcs.entities.TileBean.Orientation.SOUTH; -import static jcs.entities.TileBean.Orientation.WEST; -import jcs.entities.TileBean.TileType; -import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; -import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; -import static jcs.ui.layout.tiles.Tile.GRID; -import static jcs.ui.layout.tiles.Tile.RENDER_HEIGHT; -import static jcs.ui.layout.tiles.Tile.RENDER_WIDTH; -import jcs.ui.util.ImageUtil; -import org.tinylog.Logger; - -public class Block extends Tile { - - public static final int BLOCK_WIDTH = DEFAULT_WIDTH * 3; - public static final int BLOCK_HEIGHT = DEFAULT_HEIGHT * 3; - - public Block(TileBean tileBean) { - super(tileBean); - setModel(new DefaultTileModel(tileBean.getOrientation())); - changeRenderSize(); - populateModel(); - } - - public Block(Orientation orientation, Point center) { - this(orientation, center.x, center.y); - } - - public Block(Orientation orientation, int x, int y) { - this(orientation, x, y, tileWidth(orientation, TileType.BLOCK), tileHeight(orientation, TileType.BLOCK)); - } - - public Block(Orientation orientation, int x, int y, int width, int height) { - super(TileType.BLOCK, orientation, x, y, width, height); - setModel(new DefaultTileModel(orientation)); - changeRenderSize(); - } - - private void changeRenderSize() { - Orientation tileOrientation = model.getTileOrienation(); - if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { - this.renderWidth = RENDER_WIDTH * 3; - this.renderHeight = RENDER_HEIGHT; - } else { - this.renderWidth = RENDER_WIDTH; - this.renderHeight = RENDER_HEIGHT * 3; - } - } - - @Override - public Set getAltPoints() { - int xx = this.tileX; - int yy = this.tileY; - Set alternatives = new HashSet<>(); - - if (Orientation.EAST.equals(getOrientation()) || Orientation.WEST.equals(getOrientation())) { - // West - Point wp = new Point((xx - DEFAULT_WIDTH), yy); - Point ep = new Point((xx + DEFAULT_WIDTH), yy); - alternatives.add(wp); - alternatives.add(ep); - } else { - Point np = new Point(xx, (yy - DEFAULT_HEIGHT)); - Point sp = new Point(xx, (yy + DEFAULT_HEIGHT)); - alternatives.add(np); - alternatives.add(sp); - } - - return alternatives; - } - - @Override - public Set getAllPoints() { - Set aps = new HashSet<>(); - aps.add(getCenter()); - aps.addAll(getAltPoints()); - return aps; - } - - public Point getAltPoint(String suffix) { - int cx = this.getCenterX(); - int cy = this.getCenterY(); - if ("+".equals(suffix)) { - return switch (this.getOrientation()) { - case WEST -> - new Point(cx - Tile.GRID * 2, cy); - case NORTH -> - new Point(cx, cy - Tile.GRID * 2); - case SOUTH -> - new Point(cx, cy + Tile.GRID * 2); - default -> - new Point(cx + Tile.GRID * 2, cy); - }; - } else { - return switch (this.getOrientation()) { - case EAST -> - new Point(cx - Tile.GRID * 2, cy); - case SOUTH -> - new Point(cx, cy - Tile.GRID * 2); - case NORTH -> - new Point(cx, cy + Tile.GRID * 2); - default -> - new Point(cx + Tile.GRID * 2, cy); - }; - } - } - - @Override - public boolean isBlock() { - return true; - } - - @Override - public Map getNeighborPoints() { - Map neighbors = new HashMap<>(); - Orientation orientation = this.getOrientation(); - int cx = this.getCenterX(); - int cy = this.getCenterY(); - - // Horizontal - if (Orientation.EAST == orientation || Orientation.WEST == orientation) { - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 4, cy)); - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 4, cy)); - } else { - // Vertical - neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 4)); - neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 4)); - } - return neighbors; - } - - @Override - public Map getEdgePoints() { - Map edgeConnections = new HashMap<>(); - Orientation orientation = this.getOrientation(); - int cx = this.getCenterX(); - int cy = this.getCenterY(); - - // Horizontal - if (Orientation.EAST == orientation || Orientation.WEST == orientation) { - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID * 3, cy)); - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID * 3, cy)); - } else { - // Vertical - edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 3)); - edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 3)); - } - return edgeConnections; - } - - public Point getNeighborPoint(String suffix) { - int cx = getCenterX(); - int cy = getCenterY(); - if ("+".equals(suffix)) { - return switch (getOrientation()) { - case WEST -> - new Point(cx - Tile.GRID * 4, cy); - case NORTH -> - new Point(cx, cy - Tile.GRID * 4); - case SOUTH -> - new Point(cx, cy + Tile.GRID * 4); - default -> - new Point(cx + Tile.GRID * 4, cy); - }; - } else { - return switch (getOrientation()) { - case EAST -> - new Point(cx - Tile.GRID * 4, cy); - case SOUTH -> - new Point(cx, cy - Tile.GRID * 4); - case NORTH -> - new Point(cx, cy + Tile.GRID * 4); - default -> - new Point(cx + Tile.GRID * 4, cy); - }; - } - } - - public Orientation getTravelDirection(String suffix) { - if ("+".equals(suffix)) { - return getOrientation(); - } else { - return switch (getOrientation()) { - case EAST -> - Orientation.WEST; - case SOUTH -> - Orientation.NORTH; - case NORTH -> - Orientation.SOUTH; - default -> - Orientation.EAST; - }; - } - } - - @Override - public String getIdSuffix(Tile other) { - String suffix = null; - Orientation match = null; - if (isAdjacent(other)) { - Map blockSides = this.getEdgePoints(); - Map otherSides = other.getEdgePoints(); - - for (Orientation bo : Orientation.values()) { - Point bp = blockSides.get(bo); - - if (bp != null) { - for (Orientation oo : Orientation.values()) { - Point op = otherSides.get(oo); - if (op != null) { - if (op.equals(bp)) { - match = bo; - break; - } - } - } - } - } - } - - Orientation tileOrientation = model.getTileOrienation(); - if (match != null) { - if (Orientation.EAST == tileOrientation && Orientation.EAST == match) { - suffix = "+"; - } - if (Orientation.WEST == tileOrientation && Orientation.WEST == match) { - suffix = "+"; - } - if (Orientation.EAST == tileOrientation && Orientation.WEST == match) { - suffix = "-"; - } - if (Orientation.WEST == tileOrientation && Orientation.EAST == match) { - suffix = "-"; - } - if (Orientation.NORTH == tileOrientation && Orientation.NORTH == match) { - suffix = "+"; - } - if (Orientation.NORTH == tileOrientation && Orientation.SOUTH == match) { - suffix = "-"; - } - if (Orientation.SOUTH == tileOrientation && Orientation.SOUTH == match) { - suffix = "+"; - } - if (Orientation.SOUTH == tileOrientation && Orientation.NORTH == match) { - suffix = "-"; - } - } - return suffix; - } - - @Override - public Orientation rotate() { - Orientation tileOrientation = model.getTileOrienation(); - super.rotate(); - - int w = tileWidth(tileOrientation, TileType.BLOCK); - int h = tileHeight(tileOrientation, TileType.BLOCK); - - Dimension d = new Dimension(w, h); - setPreferredSize(d); - setSize(d); - changeRenderSize(); - - setBounds(getTileBounds()); - - //repaint(getTileBounds()); - return tileOrientation; - } - - /** - * Depending on the block status change the background color
- * - Red: Occupied
- * - Green: Departure
- * - Magenta: Arrival / entering
- * - Yellow: reserved
- * - White: all clear / default
- * - * @return the Color which belong with the current Block State - */ - Color getBlockStateColor() { - return getBlockStateColor(this.model.getBlockState()); - } - - protected Color getBlockStateColor(BlockState blockState) { - return switch (blockState) { - case GHOST -> - new Color(250, 0, 0); - case LOCKED -> - new Color(250, 250, 210); - case OCCUPIED -> - new Color(250, 210, 210); - case OUT_OF_ORDER -> - new Color(190, 190, 190); - case OUTBOUND -> - new Color(210, 250, 210); - case INBOUND -> - new Color(250, 210, 250); - default -> - new Color(255, 255, 255); - }; - } - - public static String getDepartureSuffix(Orientation tileOrientation, boolean reverseArrival, LocomotiveBean.Direction direction) { - if (LocomotiveBean.Direction.FORWARDS == direction) { - if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { - if (reverseArrival) { - return "-"; - } else { - return "+"; - } - } else { - if (reverseArrival) { - return "+"; - } else { - return "-"; - } - } - } else { - if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { - if (reverseArrival) { - return "+"; - } else { - return "-"; - } - } else { - if (reverseArrival) { - return "-"; - } else { - return "+"; - } - } - } - } - - @Override - public void renderTile(Graphics2D g2) { - int xx = 20; - int yy = 50; - int rw = RENDER_WIDTH * 3 - 40; - int rh = 300; - - g2.setStroke(new BasicStroke(3, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); - - g2.setPaint(Color.darkGray); - g2.drawRoundRect(xx, yy, rw, rh, 15, 15); - - Color blockStateColor = getBlockStateColor(); - //Logger.trace("Block " + this.id + " State: " + this.getBlockBean().getBlockState().getState() + " Color: " + blockStateColor.toString()); - g2.setPaint(blockStateColor); - g2.fillRoundRect(xx, yy, rw, rh, 15, 15); - - g2.setStroke(new BasicStroke(20, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); - g2.setPaint(Color.darkGray); - g2.drawLine(rw + GRID, yy - 0, rw + GRID, yy + 300); - - //When there is a locomotive in the block mark the direction of travel. - //The default, forwards is in the direction of the block orientation, i.e. the + - if (model.getLocomotive() != null && model.getLocomotive().getName() != null) { - renderDirectionArrow(g2); - } - - drawName(g2); - } - - private void renderDirectionArrow(Graphics2D g2) { - //The default, forwards is in the direction of the block orientation, i.e. the + - Orientation tileOrientation = model.getTileOrienation(); - BlockBean bb = this.getBlockBean(); - boolean reverseArrival = model.isReverseArrival(); - - LocomotiveBean.Direction logicalDirection; - if (bb.getLogicalDirection() != null) { - logicalDirection = model.getLogicalDirection(); - } else { - logicalDirection = model.getLocomotive().getDirection(); - } - - String departureSuffix = model.getDepartureSuffix(); - if (departureSuffix == null) { - departureSuffix = Block.getDepartureSuffix(tileOrientation, reverseArrival, logicalDirection); - } - - //Logger.trace(this.getId()+" LogicalDirection is " + (bb.getLogicalDirection() != null ? "Set" : "Not Set") + " Dir: " + logicalDirection.getDirection() + " Orientation: " + orientation.getOrientation() + " departureSuffix: " + departureSuffix); - if ("+".equals(departureSuffix)) { - if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { - switch (logicalDirection) { - case LocomotiveBean.Direction.FORWARDS -> { - if (reverseArrival) { - renderLeftArrow(g2); - } else { - renderRightArrow(g2); - } - } - case LocomotiveBean.Direction.BACKWARDS -> { - if (reverseArrival) { - renderRightArrow(g2); - } else { - renderLeftArrow(g2); - } - } - } - } else { - switch (logicalDirection) { - case LocomotiveBean.Direction.BACKWARDS -> { - if (reverseArrival) { - renderLeftArrow(g2); - } else { - renderRightArrow(g2); - } - } - case LocomotiveBean.Direction.FORWARDS -> { - if (reverseArrival) { - renderRightArrow(g2); - } else { - renderLeftArrow(g2); - } - } - } - } - } else { - if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { - switch (logicalDirection) { - case LocomotiveBean.Direction.FORWARDS -> { - if (reverseArrival) { - renderLeftArrow(g2); - } else { - renderRightArrow(g2); - } - } - case LocomotiveBean.Direction.BACKWARDS -> { - if (reverseArrival) { - renderRightArrow(g2); - } else { - renderLeftArrow(g2); - } - } - } - } else { - switch (logicalDirection) { - case LocomotiveBean.Direction.BACKWARDS -> { - if (reverseArrival) { - renderLeftArrow(g2); - } else { - renderRightArrow(g2); - } - } - case LocomotiveBean.Direction.FORWARDS -> { - if (reverseArrival) { - renderRightArrow(g2); - } else { - renderLeftArrow(g2); - } - } - } - } - } - } - - private void renderLeftArrow(Graphics2D g2) { - //Logger.trace(this.getId()+" LogicalDirection is " + this.getBlockBean().getLogicalDirection() + " Orientation: " + this.getOrientation() + " departureSuffix: " + this.getBlockBean().getDepartureSuffix()); - g2.fillPolygon(new int[]{0, 50, 50,}, new int[]{200, 150, 250}, 3); - } - - private void renderRightArrow(Graphics2D g2) { - //Logger.trace(this.getId()+" LogicalDirection is " + this.getBlockBean().getLogicalDirection() + " Orientation: " + this.getOrientation() + " departureSuffix: " + this.getBlockBean().getDepartureSuffix()); - g2.fillPolygon(new int[]{1180, 1130, 1130,}, new int[]{200, 150, 250}, 3); - } - - @Override - public void renderTileRoute(Graphics2D g2d) { - if (model.isShowBlockState()) { - backgroundColor = getBlockStateColor(model.getBlockState()); - } - } - - protected void overlayLocImage() { - int ww = tileImage.getWidth(); - int hh = tileImage.getHeight(); - Orientation tileOrientation = model.getTileOrienation(); - - BufferedImage overlay = new BufferedImage(ww, hh, BufferedImage.TYPE_INT_ARGB); - Graphics2D g2i = overlay.createGraphics(); - - Image locImage = getLocImage(); - if (locImage != null) { - String departureSuffix = model.getDepartureSuffix(); - boolean reverseImage = model.isReverseArrival(); - - Logger.trace("LocImage w: " + locImage.getWidth(null) + " h: " + locImage.getHeight(null)); - // scale it to max h of 45 - int size = 45; - float aspect = (float) locImage.getHeight(null) / (float) locImage.getWidth(null); - //TODO: Use Scalr? - locImage = locImage.getScaledInstance(size, (int) (size * aspect), Image.SCALE_SMOOTH); - - //Depending on the block orientation the image needs to be rotated and flipped - //Incase the departure suffix is NOT set center the locomotive image - int w, h, xx, yy; - switch (tileOrientation) { - case WEST -> { - w = locImage.getWidth(null); - h = locImage.getHeight(null); - - if (null == departureSuffix) { - xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w; - } else { - switch (departureSuffix) { - case "+" -> { - xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w - 25; - } - default -> { - xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w + 10; - } - } - } - yy = DEFAULT_HEIGHT / 2 - h / 2; - - if (reverseImage) { - locImage = ImageUtil.flipVertically(locImage); - } - } - case SOUTH -> { - locImage = ImageUtil.flipHorizontally(locImage); - locImage = ImageUtil.rotate(locImage, 90); - - w = locImage.getWidth(null); - h = locImage.getHeight(null); - xx = DEFAULT_WIDTH / 2 - w / 2; - - if (null == departureSuffix) { - yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h; - } else { - switch (departureSuffix) { - case "-" -> { - yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h - 25; - } - default -> { - yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h + 10; - } - } - } - if (reverseImage) { - locImage = ImageUtil.flipHorizontally(locImage); - } - //g2d.drawImage(locImage, xx, yy, null); - } - case NORTH -> { - locImage = ImageUtil.flipHorizontally(locImage); - locImage = ImageUtil.rotate(locImage, 90); - - w = locImage.getWidth(null); - h = locImage.getHeight(null); - xx = DEFAULT_WIDTH / 2 - w / 2; - - if (null == departureSuffix) { - int minY = BLOCK_HEIGHT / 2 - getHeight() / 2 + h; - yy = minY; - } else { - switch (departureSuffix) { - case "+" -> { - yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h - 25; - } - default -> { - yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h + 10; - } - } - } - if (reverseImage) { - locImage = ImageUtil.flipHorizontally(locImage); - } - } - default -> { - w = locImage.getWidth(null); - h = locImage.getHeight(null); - if (null == departureSuffix) { - xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w; - } else { - switch (departureSuffix) { - case "-" -> { - xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w - 25; - } - default -> { - xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w + 10; - } - } - } - yy = DEFAULT_HEIGHT / 2 - h / 2; - - if (reverseImage) { - locImage = ImageUtil.flipVertically(locImage); - } - } - } - - g2i.drawImage(tileImage, 0, 0, null); - g2i.drawImage(locImage, xx, yy, null); - g2i.dispose(); - tileImage = overlay; - } - } - - private Image getLocImage() { - if (model.getLocomotive() != null && model.getLocomotive().getLocIcon() != null) { - return model.getLocomotive().getLocIcon(); - } else { - return null; - } - } - - public String getBlockText() { - String blockText; - if (blockBean != null && blockBean.getDescription() != null) { - if (blockBean.getLocomotive() != null && blockBean.getLocomotive().getName() != null && BlockState.GHOST != blockBean.getBlockState()) { - blockText = blockBean.getLocomotive().getName(); - } else { - if (blockBean.getDescription().length() > 0) { - blockText = blockBean.getDescription(); - } else { - blockText = getId(); - } - } - } else { - // Design mode show description when available - if (blockBean != null && blockBean.getDescription() != null && blockBean.getDescription().length() > 0) { - blockText = blockBean.getDescription(); - } else { - blockText = getId(); - } - } - return blockText; - } - - @Override - public void drawName(Graphics2D g2d) { - if (!model.isOverlayImage()) { - g2d.setPaint(Color.black); - - Font currentFont = g2d.getFont(); - Font newFont = currentFont.deriveFont(currentFont.getSize() * 10.0F); - g2d.setFont(newFont); - - String blockText = getBlockText(); - - // Scale the text if necessary - int textWidth = g2d.getFontMetrics().stringWidth(blockText); - double fontscale = 10.0; - if (textWidth > 845) { - fontscale = fontscale * 847.0 / textWidth; - newFont = currentFont.deriveFont(currentFont.getSize() * (float) fontscale); - g2d.setFont(newFont); - textWidth = g2d.getFontMetrics().stringWidth(blockText); - } - - int textHeight = g2d.getFontMetrics().getHeight(); - Orientation tileOrientation = model.getTileOrienation(); - - switch (tileOrientation) { - case EAST -> { - drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) - textWidth / 2, RENDER_GRID + textHeight / 3, 0, blockText); - } - case WEST -> { - drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) + textWidth / 2, RENDER_GRID - textHeight / 3, 180, blockText); - } - case NORTH -> { - drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) - textWidth / 2, RENDER_GRID + textHeight / 3, 0, blockText); - } - case SOUTH -> { - drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) + textWidth / 2, RENDER_GRID - textHeight / 3, 180, blockText); - } - } - // reset to the original font - newFont = currentFont.deriveFont(currentFont.getSize() * 1.0F); - g2d.setFont(newFont); - } - } - - @Override - public Rectangle getTileBounds() { - int multiplier = (model.isScaleImage() ? 1 : 10); - Orientation tileOrientation = model.getTileOrienation(); - - int xx, yy; - if (tileOrientation == Orientation.EAST || tileOrientation == Orientation.WEST) { - xx = tileX - GRID * multiplier - GRID * multiplier * 2; - yy = tileY - GRID * multiplier; - } else { - xx = tileX - GRID * multiplier; - yy = tileY - GRID * multiplier - GRID * multiplier * 2; - } - - if (model.isScaleImage()) { - return new Rectangle(xx, yy, tileWidth(tileOrientation, TileType.BLOCK), tileHeight(tileOrientation, TileType.BLOCK)); - } else { - return new Rectangle(xx, yy, renderWidth, renderHeight); - } - } - - @Override - protected void paintComponent(Graphics g) { - long started = System.currentTimeMillis(); - - Graphics2D g2 = (Graphics2D) g.create(); - drawTile(g2); - g2.dispose(); - - if (model.isOverlayImage()) { - overlayLocImage(); - } - - g.drawImage(tileImage, 0, 0, null); - long now = System.currentTimeMillis(); - Logger.trace(id + " Duration: " + (now - started) + " ms."); - } - - @Override - protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { - //A block has 2 alternate points - //1st square - //2nd square holds the centerpoint - //3rd square - Orientation tileOrientation = model.getTileOrienation(); - double dX1, dX2, dX3, dY1, dY2, dY3; - if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { - dX1 = renderWidth / 3 / 2 - size / 2 / 2; - dY1 = renderHeight / 2 - size / 2 / 2; - dX2 = renderWidth / 2 - size / 2; - dY2 = renderHeight / 2 - size / 2; - dX3 = renderWidth - renderWidth / 3 / 2 - size / 2 / 2; - dY3 = renderHeight / 2 - size / 2 / 2; - } else { - dX1 = renderWidth / 2 - size / 2 / 2; - dY1 = renderHeight / 3 / 2 - size / 2 / 2; - dX2 = renderHeight / 2 - size / 2; - dY2 = renderWidth / 2 - size / 2; - dY3 = renderWidth / 2 - size / 2 / 2; - dX3 = renderHeight - renderHeight / 3 / 2 - size / 2 / 2; - } - - g2d.setColor(color); - g2d.fill(new Ellipse2D.Double(dX1, dY1, size / 2, size / 2)); - g2d.fill(new Ellipse2D.Double(dX2, dY2, size, size)); - g2d.fill(new Ellipse2D.Double(dX3, dY3, size / 2, size / 2)); - } - -} +/* * Copyright 2024 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; 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.Image; import java.awt.Point; import java.awt.Rectangle; import java.awt.geom.Ellipse2D; import java.awt.image.BufferedImage; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import jcs.entities.BlockBean; import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.EAST; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; import static jcs.ui.layout.tiles.Tile.GRID; import static jcs.ui.layout.tiles.Tile.RENDER_HEIGHT; import static jcs.ui.layout.tiles.Tile.RENDER_WIDTH; import jcs.ui.util.ImageUtil; import org.tinylog.Logger; public class Block extends Tile { public static final int BLOCK_WIDTH = DEFAULT_WIDTH * 3; public static final int BLOCK_HEIGHT = DEFAULT_HEIGHT * 3; public Block(TileBean tileBean) { super(tileBean); setModel(new DefaultTileModel(tileBean.getOrientation())); changeRenderSize(); populateModel(); } public Block(Orientation orientation, Point center) { this(orientation, center.x, center.y); } public Block(Orientation orientation, int x, int y) { this(orientation, x, y, tileWidth(orientation, TileType.BLOCK), tileHeight(orientation, TileType.BLOCK)); } public Block(Orientation orientation, int x, int y, int width, int height) { super(TileType.BLOCK, orientation, x, y, width, height); setModel(new DefaultTileModel(orientation)); changeRenderSize(); } private void changeRenderSize() { Orientation tileOrientation = model.getTileOrienation(); if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { this.renderWidth = RENDER_WIDTH * 3; this.renderHeight = RENDER_HEIGHT; } else { this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT * 3; } } @Override public Set getAltPoints() { int xx = this.tileX; int yy = this.tileY; Set alternatives = new HashSet<>(); if (Orientation.EAST.equals(getOrientation()) || Orientation.WEST.equals(getOrientation())) { // West Point wp = new Point((xx - DEFAULT_WIDTH), yy); Point ep = new Point((xx + DEFAULT_WIDTH), yy); alternatives.add(wp); alternatives.add(ep); } else { Point np = new Point(xx, (yy - DEFAULT_HEIGHT)); Point sp = new Point(xx, (yy + DEFAULT_HEIGHT)); alternatives.add(np); alternatives.add(sp); } return alternatives; } @Override public Set getAllPoints() { Set aps = new HashSet<>(); aps.add(getCenter()); aps.addAll(getAltPoints()); return aps; } public Point getAltPoint(String suffix) { int cx = this.getCenterX(); int cy = this.getCenterY(); if ("+".equals(suffix)) { return switch (this.getOrientation()) { case WEST -> new Point(cx - Tile.GRID * 2, cy); case NORTH -> new Point(cx, cy - Tile.GRID * 2); case SOUTH -> new Point(cx, cy + Tile.GRID * 2); default -> new Point(cx + Tile.GRID * 2, cy); }; } else { return switch (this.getOrientation()) { case EAST -> new Point(cx - Tile.GRID * 2, cy); case SOUTH -> new Point(cx, cy - Tile.GRID * 2); case NORTH -> new Point(cx, cy + Tile.GRID * 2); default -> new Point(cx + Tile.GRID * 2, cy); }; } } @Override public boolean isBlock() { return true; } @Override public Map getNeighborPoints() { Map neighbors = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); // Horizontal if (Orientation.EAST == orientation || Orientation.WEST == orientation) { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 4, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 4, cy)); } else { // Vertical neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 4)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 4)); } return neighbors; } @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); // Horizontal if (Orientation.EAST == orientation || Orientation.WEST == orientation) { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID * 3, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID * 3, cy)); } else { // Vertical edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 3)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 3)); } return edgeConnections; } public Point getNeighborPoint(String suffix) { int cx = getCenterX(); int cy = getCenterY(); if ("+".equals(suffix)) { return switch (getOrientation()) { case WEST -> new Point(cx - Tile.GRID * 4, cy); case NORTH -> new Point(cx, cy - Tile.GRID * 4); case SOUTH -> new Point(cx, cy + Tile.GRID * 4); default -> new Point(cx + Tile.GRID * 4, cy); }; } else { return switch (getOrientation()) { case EAST -> new Point(cx - Tile.GRID * 4, cy); case SOUTH -> new Point(cx, cy - Tile.GRID * 4); case NORTH -> new Point(cx, cy + Tile.GRID * 4); default -> new Point(cx + Tile.GRID * 4, cy); }; } } public Orientation getTravelDirection(String suffix) { if ("+".equals(suffix)) { return getOrientation(); } else { return switch (getOrientation()) { case EAST -> Orientation.WEST; case SOUTH -> Orientation.NORTH; case NORTH -> Orientation.SOUTH; default -> Orientation.EAST; }; } } @Override public String getIdSuffix(Tile other) { String suffix = null; Orientation match = null; if (isAdjacent(other)) { Map blockSides = this.getEdgePoints(); Map otherSides = other.getEdgePoints(); for (Orientation bo : Orientation.values()) { Point bp = blockSides.get(bo); if (bp != null) { for (Orientation oo : Orientation.values()) { Point op = otherSides.get(oo); if (op != null) { if (op.equals(bp)) { match = bo; break; } } } } } } Orientation tileOrientation = model.getTileOrienation(); if (match != null) { if (Orientation.EAST == tileOrientation && Orientation.EAST == match) { suffix = "+"; } if (Orientation.WEST == tileOrientation && Orientation.WEST == match) { suffix = "+"; } if (Orientation.EAST == tileOrientation && Orientation.WEST == match) { suffix = "-"; } if (Orientation.WEST == tileOrientation && Orientation.EAST == match) { suffix = "-"; } if (Orientation.NORTH == tileOrientation && Orientation.NORTH == match) { suffix = "+"; } if (Orientation.NORTH == tileOrientation && Orientation.SOUTH == match) { suffix = "-"; } if (Orientation.SOUTH == tileOrientation && Orientation.SOUTH == match) { suffix = "+"; } if (Orientation.SOUTH == tileOrientation && Orientation.NORTH == match) { suffix = "-"; } } return suffix; } @Override public Orientation rotate() { super.rotate(); Orientation tileOrientation = model.getTileOrienation(); int w = tileWidth(tileOrientation, TileType.BLOCK); int h = tileHeight(tileOrientation, TileType.BLOCK); Dimension d = new Dimension(w, h); setPreferredSize(d); setSize(d); changeRenderSize(); setBounds(getTileBounds()); return model.getTileOrienation(); } /** * Depending on the block status change the background color
* - Red: Occupied
* - Green: Departure
* - Magenta: Arrival / entering
* - Yellow: reserved
* - White: all clear / default
* * @return the Color which belong with the current Block State */ Color getBlockStateColor() { return getBlockStateColor(this.model.getBlockState()); } protected Color getBlockStateColor(BlockState blockState) { return switch (blockState) { case GHOST -> new Color(250, 0, 0); case LOCKED -> new Color(250, 250, 210); case OCCUPIED -> new Color(250, 210, 210); case OUT_OF_ORDER -> new Color(190, 190, 190); case OUTBOUND -> new Color(210, 250, 210); case INBOUND -> new Color(250, 210, 250); default -> new Color(255, 255, 255); }; } public static String getDepartureSuffix(Orientation tileOrientation, boolean reverseArrival, LocomotiveBean.Direction direction) { if (LocomotiveBean.Direction.FORWARDS == direction) { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { if (reverseArrival) { return "-"; } else { return "+"; } } else { if (reverseArrival) { return "+"; } else { return "-"; } } } else { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { if (reverseArrival) { return "+"; } else { return "-"; } } else { if (reverseArrival) { return "-"; } else { return "+"; } } } } @Override public void renderTile(Graphics2D g2) { int xx = 20; int yy = 50; int rw = RENDER_WIDTH * 3 - 40; int rh = 300; g2.setStroke(new BasicStroke(3, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); g2.setPaint(Color.darkGray); g2.drawRoundRect(xx, yy, rw, rh, 15, 15); Color blockStateColor = getBlockStateColor(); //Logger.trace("Block " + this.id + " State: " + this.getBlockBean().getBlockState().getState() + " Color: " + blockStateColor.toString()); g2.setPaint(blockStateColor); g2.fillRoundRect(xx, yy, rw, rh, 15, 15); g2.setStroke(new BasicStroke(20, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); g2.setPaint(Color.darkGray); g2.drawLine(rw + GRID, yy - 0, rw + GRID, yy + 300); //When there is a locomotive in the block mark the direction of travel. //The default, forwards is in the direction of the block orientation, i.e. the + if (model.getLocomotive() != null && model.getLocomotive().getName() != null) { renderDirectionArrow(g2); } drawName(g2); } private void renderDirectionArrow(Graphics2D g2) { //The default, forwards is in the direction of the block orientation, i.e. the + Orientation tileOrientation = model.getTileOrienation(); BlockBean bb = this.getBlockBean(); boolean reverseArrival = model.isReverseArrival(); LocomotiveBean.Direction logicalDirection; if (bb.getLogicalDirection() != null) { logicalDirection = model.getLogicalDirection(); } else { logicalDirection = model.getLocomotive().getDirection(); } String departureSuffix = model.getDepartureSuffix(); if (departureSuffix == null) { departureSuffix = Block.getDepartureSuffix(tileOrientation, reverseArrival, logicalDirection); } //Logger.trace(this.getId()+" LogicalDirection is " + (bb.getLogicalDirection() != null ? "Set" : "Not Set") + " Dir: " + logicalDirection.getDirection() + " Orientation: " + orientation.getOrientation() + " departureSuffix: " + departureSuffix); if ("+".equals(departureSuffix)) { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { switch (logicalDirection) { case LocomotiveBean.Direction.FORWARDS -> { if (reverseArrival) { renderLeftArrow(g2); } else { renderRightArrow(g2); } } case LocomotiveBean.Direction.BACKWARDS -> { if (reverseArrival) { renderRightArrow(g2); } else { renderLeftArrow(g2); } } } } else { switch (logicalDirection) { case LocomotiveBean.Direction.BACKWARDS -> { if (reverseArrival) { renderLeftArrow(g2); } else { renderRightArrow(g2); } } case LocomotiveBean.Direction.FORWARDS -> { if (reverseArrival) { renderRightArrow(g2); } else { renderLeftArrow(g2); } } } } } else { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { switch (logicalDirection) { case LocomotiveBean.Direction.FORWARDS -> { if (reverseArrival) { renderLeftArrow(g2); } else { renderRightArrow(g2); } } case LocomotiveBean.Direction.BACKWARDS -> { if (reverseArrival) { renderRightArrow(g2); } else { renderLeftArrow(g2); } } } } else { switch (logicalDirection) { case LocomotiveBean.Direction.BACKWARDS -> { if (reverseArrival) { renderLeftArrow(g2); } else { renderRightArrow(g2); } } case LocomotiveBean.Direction.FORWARDS -> { if (reverseArrival) { renderRightArrow(g2); } else { renderLeftArrow(g2); } } } } } } private void renderLeftArrow(Graphics2D g2) { //Logger.trace(this.getId()+" LogicalDirection is " + this.getBlockBean().getLogicalDirection() + " Orientation: " + this.getOrientation() + " departureSuffix: " + this.getBlockBean().getDepartureSuffix()); g2.fillPolygon(new int[]{0, 50, 50,}, new int[]{200, 150, 250}, 3); } private void renderRightArrow(Graphics2D g2) { //Logger.trace(this.getId()+" LogicalDirection is " + this.getBlockBean().getLogicalDirection() + " Orientation: " + this.getOrientation() + " departureSuffix: " + this.getBlockBean().getDepartureSuffix()); g2.fillPolygon(new int[]{1180, 1130, 1130,}, new int[]{200, 150, 250}, 3); } @Override public void renderTileRoute(Graphics2D g2d) { if (model.isShowBlockState()) { backgroundColor = getBlockStateColor(model.getBlockState()); } } protected void overlayLocImage() { int ww = tileImage.getWidth(); int hh = tileImage.getHeight(); Orientation tileOrientation = model.getTileOrienation(); BufferedImage overlay = new BufferedImage(ww, hh, BufferedImage.TYPE_INT_ARGB); Graphics2D g2i = overlay.createGraphics(); Image locImage = getLocImage(); if (locImage != null) { String departureSuffix = model.getDepartureSuffix(); boolean reverseImage = model.isReverseArrival(); Logger.trace("LocImage w: " + locImage.getWidth(null) + " h: " + locImage.getHeight(null)); // scale it to max h of 45 int size = 45; float aspect = (float) locImage.getHeight(null) / (float) locImage.getWidth(null); //TODO: Use Scalr? locImage = locImage.getScaledInstance(size, (int) (size * aspect), Image.SCALE_SMOOTH); //Depending on the block orientation the image needs to be rotated and flipped //Incase the departure suffix is NOT set center the locomotive image int w, h, xx, yy; switch (tileOrientation) { case WEST -> { w = locImage.getWidth(null); h = locImage.getHeight(null); if (null == departureSuffix) { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w; } else { switch (departureSuffix) { case "+" -> { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w - 25; } default -> { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w + 10; } } } yy = DEFAULT_HEIGHT / 2 - h / 2; if (reverseImage) { locImage = ImageUtil.flipVertically(locImage); } } case SOUTH -> { locImage = ImageUtil.flipHorizontally(locImage); locImage = ImageUtil.rotate(locImage, 90); w = locImage.getWidth(null); h = locImage.getHeight(null); xx = DEFAULT_WIDTH / 2 - w / 2; if (null == departureSuffix) { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h; } else { switch (departureSuffix) { case "-" -> { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h - 25; } default -> { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h + 10; } } } if (reverseImage) { locImage = ImageUtil.flipHorizontally(locImage); } } case NORTH -> { locImage = ImageUtil.flipHorizontally(locImage); locImage = ImageUtil.rotate(locImage, 90); w = locImage.getWidth(null); h = locImage.getHeight(null); xx = DEFAULT_WIDTH / 2 - w / 2; if (null == departureSuffix) { int minY = BLOCK_HEIGHT / 2 - getHeight() / 2 + h; yy = minY; } else { switch (departureSuffix) { case "+" -> { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h - 25; } default -> { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h + 10; } } } if (reverseImage) { locImage = ImageUtil.flipHorizontally(locImage); } } default -> { w = locImage.getWidth(null); h = locImage.getHeight(null); if (null == departureSuffix) { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w; } else { switch (departureSuffix) { case "-" -> { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w - 25; } default -> { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w + 10; } } } yy = DEFAULT_HEIGHT / 2 - h / 2; if (reverseImage) { locImage = ImageUtil.flipVertically(locImage); } } } g2i.drawImage(tileImage, 0, 0, null); g2i.drawImage(locImage, xx, yy, null); g2i.dispose(); tileImage = overlay; } } private Image getLocImage() { if (model.getLocomotive() != null && model.getLocomotive().getLocIcon() != null) { return model.getLocomotive().getLocIcon(); } else { return null; } } public String getBlockText() { String blockText; if (blockBean != null && blockBean.getDescription() != null) { if (blockBean.getLocomotive() != null && blockBean.getLocomotive().getName() != null && BlockState.GHOST != blockBean.getBlockState()) { blockText = blockBean.getLocomotive().getName(); } else { if (blockBean.getDescription().length() > 0) { blockText = blockBean.getDescription(); } else { blockText = getId(); } } } else { // Design mode show description when available if (blockBean != null && blockBean.getDescription() != null && blockBean.getDescription().length() > 0) { blockText = blockBean.getDescription(); } else { blockText = getId(); } } return blockText; } @Override public void drawName(Graphics2D g2d) { if (!model.isOverlayImage()) { g2d.setPaint(Color.black); Font currentFont = g2d.getFont(); Font newFont = currentFont.deriveFont(currentFont.getSize() * 10.0F); g2d.setFont(newFont); String blockText = getBlockText(); // Scale the text if necessary int textWidth = g2d.getFontMetrics().stringWidth(blockText); double fontscale = 10.0; if (textWidth > 845) { fontscale = fontscale * 847.0 / textWidth; newFont = currentFont.deriveFont(currentFont.getSize() * (float) fontscale); g2d.setFont(newFont); textWidth = g2d.getFontMetrics().stringWidth(blockText); } int textHeight = g2d.getFontMetrics().getHeight(); Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case EAST -> { drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) - textWidth / 2, RENDER_GRID + textHeight / 3, 0, blockText); } case WEST -> { drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) + textWidth / 2, RENDER_GRID - textHeight / 3, 180, blockText); } case NORTH -> { drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) - textWidth / 2, RENDER_GRID + textHeight / 3, 0, blockText); } case SOUTH -> { drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) + textWidth / 2, RENDER_GRID - textHeight / 3, 180, blockText); } } // reset to the original font newFont = currentFont.deriveFont(currentFont.getSize() * 1.0F); g2d.setFont(newFont); } } @Override public Rectangle getTileBounds() { int multiplier = (model.isScaleImage() ? 1 : 10); Orientation tileOrientation = model.getTileOrienation(); int xx, yy; if (tileOrientation == Orientation.EAST || tileOrientation == Orientation.WEST) { xx = tileX - GRID * multiplier - GRID * multiplier * 2; yy = tileY - GRID * multiplier; } else { xx = tileX - GRID * multiplier; yy = tileY - GRID * multiplier - GRID * multiplier * 2; } if (model.isScaleImage()) { return new Rectangle(xx, yy, tileWidth(tileOrientation, TileType.BLOCK), tileHeight(tileOrientation, TileType.BLOCK)); } else { return new Rectangle(xx, yy, renderWidth, renderHeight); } } @Override protected void paintComponent(Graphics g) { long started = System.currentTimeMillis(); Graphics2D g2 = (Graphics2D) g.create(); drawTile(g2); g2.dispose(); if (model.isOverlayImage()) { overlayLocImage(); } g.drawImage(tileImage, 0, 0, null); long now = System.currentTimeMillis(); Logger.trace(id + " Duration: " + (now - started) + " ms."); } @Override protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { //A block has 2 alternate points //1st square //2nd square holds the centerpoint //3rd square Orientation tileOrientation = model.getTileOrienation(); double dX1, dX2, dX3, dY1, dY2, dY3; if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { dX1 = renderWidth / 3 / 2 - size / 2 / 2; dY1 = renderHeight / 2 - size / 2 / 2; dX2 = renderWidth / 2 - size / 2; dY2 = renderHeight / 2 - size / 2; dX3 = renderWidth - renderWidth / 3 / 2 - size / 2 / 2; dY3 = renderHeight / 2 - size / 2 / 2; } else { dX1 = renderWidth / 2 - size / 2 / 2; dY1 = renderHeight / 3 / 2 - size / 2 / 2; dX2 = renderHeight / 2 - size / 2; dY2 = renderWidth / 2 - size / 2; dY3 = renderWidth / 2 - size / 2 / 2; dX3 = renderHeight - renderHeight / 3 / 2 - size / 2 / 2; } g2d.setColor(color); g2d.fill(new Ellipse2D.Double(dX1, dY1, size / 2, size / 2)); g2d.fill(new Ellipse2D.Double(dX2, dY2, size, size)); g2d.fill(new Ellipse2D.Double(dX3, dY3, size / 2, size / 2)); } } \ No newline at end of file diff --git a/src/main/java/jcs/ui/layout/tiles/Cross.java b/src/main/java/jcs/ui/layout/tiles/Cross.java index 72e03d11..7b35150e 100644 --- a/src/main/java/jcs/ui/layout/tiles/Cross.java +++ b/src/main/java/jcs/ui/layout/tiles/Cross.java @@ -1,655 +1 @@ -/* - * Copyright 2023 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout.tiles; - -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.geom.Ellipse2D; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import jcs.entities.AccessoryBean.AccessoryValue; -import static jcs.entities.AccessoryBean.AccessoryValue.GREEN; -import static jcs.entities.AccessoryBean.AccessoryValue.RED; -import jcs.entities.TileBean; -import jcs.entities.TileBean.Direction; -import jcs.entities.TileBean.Orientation; -import static jcs.entities.TileBean.Orientation.NORTH; -import static jcs.entities.TileBean.Orientation.SOUTH; -import static jcs.entities.TileBean.Orientation.WEST; -import jcs.entities.TileBean.TileType; -import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; -import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; -import static jcs.ui.layout.tiles.Tile.GRID; -import static jcs.ui.layout.tiles.Tile.tileHeight; -import static jcs.ui.layout.tiles.Tile.tileWidth; -import org.tinylog.Logger; - -public class Cross extends Switch { - - public static final int CROSS_WIDTH = DEFAULT_WIDTH * 2; - public static final int CROSS_HEIGHT = DEFAULT_HEIGHT * 2; - - public static final Color VERY_LIGHT_RED = new Color(255, 102, 102); - public static final Color LIGHT_RED = new Color(255, 51, 51); - public static final Color DARK_RED = new Color(204, 0, 0); - - public static final Color VERY_LIGHT_GREEN = new Color(102, 255, 102); - public static final Color LIGHT_GREEN = new Color(0, 255, 51); - public static final Color DARK_GREEN = new Color(0, 153, 0); - - public Cross(Orientation orientation, Direction direction, Point center) { - this(orientation, direction, center.x, center.y); - } - - public Cross(Orientation orientation, Direction direction, int x, int y) { - this(orientation, direction, x, y, tileWidth(orientation, TileType.CROSS), tileHeight(orientation, TileType.CROSS)); - } - - public Cross(Orientation orientation, Direction direction, int x, int y, int width, int height) { - super(TileType.CROSS, orientation, direction, x, y, width, height); - changeRenderSizeAndOffsets(); - } - - public Cross(TileBean tileBean) { - super(tileBean, tileWidth(tileBean.getOrientation(), TileType.CROSS), tileHeight(tileBean.getOrientation(), TileType.CROSS)); - changeRenderSizeAndOffsets(); - } - - private void changeRenderSizeAndOffsets() { - //Reset offsets - this.offsetY = 0; - this.renderOffsetY = 0; - this.offsetX = 0; - this.renderOffsetX = 0; - - if (isHorizontal()) { - //this.width = DEFAULT_WIDTH * 2; - //this.height = DEFAULT_HEIGHT; - this.renderWidth = RENDER_GRID * 4; - this.renderHeight = RENDER_GRID * 2; - - this.offsetY = 0; - this.renderOffsetY = 0; - } else { - //this.width = DEFAULT_WIDTH; - //this.height = DEFAULT_HEIGHT * 2; - this.renderWidth = RENDER_GRID * 2; - this.renderHeight = RENDER_GRID * 4; - - this.offsetX = 0; - this.renderOffsetX = 0; - } - - //Due to the asymetical shape (center is on the left) - //the offset has to be changed with the rotation - switch (getOrientation()) { - case SOUTH -> { - this.offsetY = +GRID; - this.renderOffsetY = RENDER_GRID; - } - case WEST -> { - this.offsetX = -GRID; - this.renderOffsetX = -RENDER_GRID; - } - case NORTH -> { - this.offsetY = -GRID; - this.renderOffsetY = -RENDER_GRID; - } - default -> { - //East so default - this.offsetX = +GRID; - this.renderOffsetX = +RENDER_GRID; - } - } - } - -// private void changeRenderSize() { -// if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { -// this.renderWidth = RENDER_WIDTH * 2; -// this.renderHeight = RENDER_HEIGHT; -// } else { -// this.renderWidth = RENDER_WIDTH; -// this.renderHeight = RENDER_HEIGHT * 2; -// } -// } - /** - * A Cross has a width in horizontal position of 2 tiles and a height of 1 tile in Vertical position.
- * - * @return the set of center point which mark the position of the Cross - */ - @Override - public Set getAltPoints() { - Set alternatives = new HashSet<>(); - - switch (getOrientation()) { - case SOUTH -> { - Point sp = new Point(tileX, (tileY + DEFAULT_HEIGHT)); - alternatives.add(sp); - } - case WEST -> { - Point wp = new Point((tileX - DEFAULT_WIDTH), tileY); - alternatives.add(wp); - } - case NORTH -> { - Point np = new Point(tileX, (tileY - DEFAULT_HEIGHT)); - alternatives.add(np); - } - default -> { - //East so default - Point ep = new Point((tileX + DEFAULT_WIDTH), tileY); - alternatives.add(ep); - } - } - return alternatives; - } - - @Override - public Map getNeighborPoints() { - Map neighbors = new HashMap<>(); - Orientation orientation = this.getOrientation(); - Direction direction = this.getDirection(); - int cx = this.getCenterX(); - int cy = this.getCenterY(); - - switch (orientation) { - case SOUTH -> { - neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); - neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 4)); - - if (Direction.LEFT == direction) { - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy + Tile.GRID * 2)); - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); - } else { - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy + Tile.GRID * 2)); - } - } - case WEST -> { - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 4, cy)); - - if (Direction.LEFT == direction) { - neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); - neighbors.put(Orientation.SOUTH, new Point(cx - Tile.GRID * 2, cy + Tile.GRID * 2)); - } else { - neighbors.put(Orientation.NORTH, new Point(cx - Tile.GRID * 2, cy - Tile.GRID * 2)); - neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); - } - } - case NORTH -> { - neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 4)); - neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); - - if (Direction.LEFT == direction) { - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy - Tile.GRID * 2)); - } else { - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy - Tile.GRID * 2)); - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); - } - } - default -> { - //EAST - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 4, cy)); - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); - - if (Direction.LEFT == direction) { - neighbors.put(Orientation.NORTH, new Point(cx + Tile.GRID * 2, cy - Tile.GRID * 2)); - neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); - } else { - neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); - neighbors.put(Orientation.SOUTH, new Point(cx + Tile.GRID * 2, cy + Tile.GRID * 2)); - } - } - } - return neighbors; - } - - @Override - public Map getEdgePoints() { - Map edgeConnections = new HashMap<>(); - Orientation orientation = this.getOrientation(); - Direction direction = this.getDirection(); - int cx = this.getCenterX(); - int cy = this.getCenterY(); - - switch (orientation) { - case SOUTH -> { - edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); - edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 3)); - - if (Direction.LEFT == direction) { - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy + Tile.GRID * 2)); - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); - } else { - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy + Tile.GRID * 2)); - } - } - case WEST -> { - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID * 3, cy)); - - if (Direction.LEFT == direction) { - edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); - edgeConnections.put(Orientation.SOUTH, new Point(cx - Tile.GRID * 2, cy + Tile.GRID)); - } else { - edgeConnections.put(Orientation.NORTH, new Point(cx - Tile.GRID * 2, cy - Tile.GRID)); - edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); - } - } - case NORTH -> { - edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 3)); - edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); - - if (Direction.LEFT == direction) { - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy - Tile.GRID * 2)); - } else { - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy - Tile.GRID * 2)); - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); - } - } - default -> { - //EAST - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID * 3, cy)); - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); - - if (Direction.LEFT == direction) { - edgeConnections.put(Orientation.NORTH, new Point(cx + Tile.GRID * 2, cy - Tile.GRID)); - edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); - } else { - edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); - edgeConnections.put(Orientation.SOUTH, new Point(cx + Tile.GRID * 2, cy + Tile.GRID)); - } - } - } - return edgeConnections; - } - - @Override - protected void renderStraight(Graphics2D g2, Color color) { - int xx, yy, w, h; - xx = 0; - yy = 170; - w = RENDER_WIDTH; - h = 60; - - g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - g2.fillRect(xx, yy, w, h); - } - - @Override - protected void renderRouteStraight(Graphics2D g2, Color color) { - int xx, yy, w, h; - xx = 0; - yy = 190; - w = RENDER_WIDTH; - h = 20; - - g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - g2.fillRect(xx, yy, w, h); - } - - protected void renderStraight2(Graphics2D g2, Color color) { - int xx, yy, w, h; - xx = RENDER_WIDTH; - yy = 170; - w = RENDER_WIDTH; - h = 60; - - g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - g2.fillRect(xx, yy, w, h); - } - - protected void renderRouteStraight2(Graphics2D g2, Color color) { - int xx, yy, w, h; - xx = RENDER_WIDTH; - yy = 190; - w = RENDER_WIDTH; - h = 20; - - g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - g2.fillRect(xx, yy, w, h); - } - - @Override - protected void renderDiagonal(Graphics2D g2, Color color) { - int[] xPoints, yPoints; - if (Direction.RIGHT.equals(getDirection())) { - xPoints = new int[]{400, 400, 167, 230}; - yPoints = new int[]{170, 230, 0, 0}; - } else { - xPoints = new int[]{400, 400, 170, 230}; - yPoints = new int[]{230, 170, 400, 400}; - } - - g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - g2.fillPolygon(xPoints, yPoints, xPoints.length); - } - - @Override - protected void renderRouteDiagonal(Graphics2D g2, Color color) { - int[] xPoints, yPoints; - if (Direction.RIGHT.equals(getDirection())) { - xPoints = new int[]{420, 400, 190, 210}; - yPoints = new int[]{210, 210, 0, 0}; - } else { - xPoints = new int[]{400, 400, 190, 210}; - yPoints = new int[]{210, 190, 400, 400}; - } - - g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - g2.fillPolygon(xPoints, yPoints, xPoints.length); - } - - protected void renderDiagonal2(Graphics2D g2, Color color) { - int[] xPoints, yPoints; - if (Direction.RIGHT.equals(getDirection())) { - xPoints = new int[]{400, 400, 570, 630}; - yPoints = new int[]{170, 230, 400, 400}; - } else { - xPoints = new int[]{400, 400, 570, 630}; - yPoints = new int[]{230, 170, 0, 0}; - } - - g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - g2.fillPolygon(xPoints, yPoints, xPoints.length); - } - - protected void renderRouteDiagonal2(Graphics2D g2, Color color) { - int[] xPoints, yPoints; - if (Direction.RIGHT.equals(getDirection())) { - xPoints = new int[]{400, 380, 590, 610}; - yPoints = new int[]{190, 190, 400, 400}; - } else { - xPoints = new int[]{400, 380, 590, 610}; - yPoints = new int[]{210, 210, 0, 0}; - } - - g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - g2.setPaint(Color.cyan); - g2.fillPolygon(xPoints, yPoints, xPoints.length); - } - - @Override - public void renderTile(Graphics2D g2) { - if (accessoryValue == null) { - this.accessoryValue = AccessoryValue.OFF; - } - - switch (accessoryValue) { - case RED -> { - renderStraight2(g2, Cross.LIGHT_RED); - renderDiagonal(g2, Cross.LIGHT_RED); - renderStraight(g2, Cross.DARK_RED); - renderDiagonal2(g2, Cross.DARK_RED); - } - case GREEN -> { - renderDiagonal(g2, Cross.VERY_LIGHT_GREEN); - renderDiagonal2(g2, Cross.VERY_LIGHT_GREEN); - renderStraight(g2, Cross.DARK_GREEN); - renderStraight2(g2, Cross.DARK_GREEN); - } - default -> { - renderStraight(g2, trackColor); - renderStraight2(g2, trackColor); - renderDiagonal(g2, trackColor); - renderDiagonal2(g2, trackColor); - } - } - } - - @Override - public void renderTileRoute(Graphics2D g2) { - if (routeValue == null) { - routeValue = AccessoryValue.OFF; - } - if (incomingSide == null) { - incomingSide = getOrientation(); - } - - if (isHorizontal()) { - if (AccessoryValue.GREEN == routeValue && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteDiagonal(g2, trackRouteColor); - renderRouteDiagonal2(g2, trackRouteColor); - } else if (AccessoryValue.GREEN == routeValue && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { - renderRouteStraight(g2, trackRouteColor); - renderRouteStraight2(g2, trackRouteColor); - } else if (AccessoryValue.RED == routeValue && Orientation.EAST == getOrientation()) { - if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { - renderRouteStraight2(g2, trackRouteColor); - renderRouteDiagonal(g2, trackRouteColor); - } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteDiagonal2(g2, trackRouteColor); - renderRouteStraight(g2, trackRouteColor); - } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteStraight2(g2, trackRouteColor); - renderRouteDiagonal(g2, trackRouteColor); - } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { - renderRouteStraight(g2, trackColor); - renderRouteDiagonal2(g2, trackColor); - } - } else if (AccessoryValue.RED == routeValue && Orientation.WEST == getOrientation()) { - if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { - renderRouteStraight(g2, trackRouteColor); - renderRouteDiagonal2(g2, trackRouteColor); - } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteDiagonal(g2, trackRouteColor); - renderRouteStraight2(g2, trackRouteColor); - } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteStraight(g2, trackRouteColor); - renderRouteDiagonal2(g2, trackRouteColor); - } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { - renderRouteStraight2(g2, trackColor); - renderRouteDiagonal(g2, trackColor); - } - } - } else { - if (AccessoryValue.GREEN == routeValue && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteStraight(g2, trackRouteColor); - renderRouteStraight2(g2, trackRouteColor); - } else if (AccessoryValue.GREEN == routeValue && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { - renderRouteDiagonal(g2, trackRouteColor); - renderRouteDiagonal2(g2, trackRouteColor); - } else if (AccessoryValue.RED == routeValue && Orientation.SOUTH == getOrientation()) { - if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteStraight2(g2, trackRouteColor); - renderRouteDiagonal(g2, trackRouteColor); - } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { - renderRouteDiagonal2(g2, trackRouteColor); - renderRouteStraight(g2, trackRouteColor); - } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { - renderRouteStraight(g2, trackRouteColor); - renderRouteDiagonal2(g2, trackRouteColor); - } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteStraight2(g2, trackColor); - renderRouteDiagonal(g2, trackColor); - } - } else if (AccessoryValue.RED == routeValue && Orientation.NORTH == getOrientation()) { - if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteStraight(g2, trackRouteColor); - renderRouteDiagonal2(g2, trackRouteColor); - } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { - renderRouteDiagonal(g2, trackRouteColor); - renderRouteStraight2(g2, trackRouteColor); - } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { - renderRouteStraight2(g2, trackRouteColor); - renderRouteDiagonal(g2, trackRouteColor); - } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteStraight(g2, trackColor); - renderRouteDiagonal2(g2, trackColor); - } - } - } - } - - @Override - public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { - if (from != null && to != null && this.getDirection() != null) { - switch (this.getDirection()) { - case LEFT -> { - if (this.isHorizontal()) { - if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { - return AccessoryValue.GREEN; - } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { - return AccessoryValue.GREEN; - } else if ((from == Orientation.NORTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.NORTH)) { - return AccessoryValue.RED; - } else if ((from == Orientation.EAST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.EAST)) { - return AccessoryValue.RED; - } else { - return AccessoryValue.OFF; - } - } else { - //Vertical - if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { - return AccessoryValue.GREEN; - } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { - return AccessoryValue.GREEN; - } else if ((from == Orientation.SOUTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.SOUTH)) { - return AccessoryValue.RED; - } else if ((from == Orientation.EAST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.EAST)) { - return AccessoryValue.RED; - } else { - return AccessoryValue.OFF; - } - } - } - case RIGHT -> { - if (this.isHorizontal()) { - if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { - return AccessoryValue.GREEN; - } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { - return AccessoryValue.GREEN; - } else if ((from == Orientation.NORTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.NORTH)) { - return AccessoryValue.RED; - } else if ((from == Orientation.WEST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.WEST)) { - return AccessoryValue.RED; - } else { - return AccessoryValue.OFF; - } - } else { - //Vertical - if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { - return AccessoryValue.GREEN; - } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { - return AccessoryValue.GREEN; - } else if ((from == Orientation.SOUTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.SOUTH)) { - return AccessoryValue.RED; - } else if ((from == Orientation.WEST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.WEST)) { - return AccessoryValue.RED; - } else { - return AccessoryValue.OFF; - } - } - } - default -> { - return AccessoryValue.OFF; - } - } - } else { - return AccessoryValue.OFF; - } - } - - @Override - protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { - //A Cross has 1 alternate point - //1st square holds the centerpoint - //2nd square - double dX1, dX2, dY1, dY2; - Orientation tileOrientation = model.getTileOrienation(); - switch (tileOrientation) { - case SOUTH -> { - dX1 = renderWidth / 2 - size / 2; - dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; - dX2 = renderWidth / 2 + renderWidth - size / 4; - dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; - } - case WEST -> { - dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; - dY1 = renderHeight / 2 - size / 2; - dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; - dY2 = renderHeight / 2 - size / 4; - } - case NORTH -> { - dX1 = renderWidth / 2 - size / 2; - dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; - dX2 = renderWidth / 2 + renderWidth - size / 4; - dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; - } - default -> { - //East - dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; - dY1 = renderHeight / 2 - size / 2; - dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; - dY2 = renderHeight / 2 - size / 4; - } - } - - g2d.setColor(color); - g2d.fill(new Ellipse2D.Double(dX1, dY1, size, size)); - g2d.fill(new Ellipse2D.Double(dX2, dY2, size / 2, size / 2)); - } - - @Override - public Rectangle getTileBounds() { - int multiplier = (model.isScaleImage() ? 1 : 10); - int xx, yy; - //Centerpoint is inbalanced - Orientation tileOrientation = model.getTileOrienation(); - switch (tileOrientation) { - case SOUTH -> { - xx = tileX - GRID * multiplier; - yy = tileY - GRID * multiplier; - } - case WEST -> { - xx = tileX - GRID * multiplier - GRID * 2 * multiplier; - yy = tileY - GRID * multiplier; - } - case NORTH -> { - xx = tileX - GRID * multiplier; - yy = tileY - GRID * multiplier - GRID * 2 * multiplier; - } - default -> { - //East - xx = tileX - GRID * multiplier; - yy = tileY - GRID * multiplier; - } - } - - if (model.isScaleImage()) { - return new Rectangle(xx, yy, tileWidth(tileOrientation, TileType.CROSS), tileHeight(tileOrientation, TileType.CROSS)); - } else { - return new Rectangle(xx, yy, renderWidth, renderHeight); - } - } - -} +/* * Copyright 2023 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.geom.Ellipse2D; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import jcs.entities.AccessoryBean.AccessoryValue; import static jcs.entities.AccessoryBean.AccessoryValue.GREEN; import static jcs.entities.AccessoryBean.AccessoryValue.RED; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; import static jcs.ui.layout.tiles.Tile.GRID; import static jcs.ui.layout.tiles.Tile.tileHeight; import static jcs.ui.layout.tiles.Tile.tileWidth; import org.tinylog.Logger; public class Cross extends Switch { public static final int CROSS_WIDTH = DEFAULT_WIDTH * 2; public static final int CROSS_HEIGHT = DEFAULT_HEIGHT * 2; public static final Color VERY_LIGHT_RED = new Color(255, 102, 102); public static final Color LIGHT_RED = new Color(255, 51, 51); public static final Color DARK_RED = new Color(204, 0, 0); public static final Color VERY_LIGHT_GREEN = new Color(102, 255, 102); public static final Color LIGHT_GREEN = new Color(0, 255, 51); public static final Color DARK_GREEN = new Color(0, 153, 0); public Cross(Orientation orientation, Direction direction, Point center) { this(orientation, direction, center.x, center.y); } public Cross(Orientation orientation, Direction direction, int x, int y) { this(orientation, direction, x, y, tileWidth(orientation, TileType.CROSS), tileHeight(orientation, TileType.CROSS)); } public Cross(Orientation orientation, Direction direction, int x, int y, int width, int height) { super(TileType.CROSS, orientation, direction, x, y, width, height); changeRenderSizeAndOffsets(); } public Cross(TileBean tileBean) { super(tileBean, tileWidth(tileBean.getOrientation(), TileType.CROSS), tileHeight(tileBean.getOrientation(), TileType.CROSS)); changeRenderSizeAndOffsets(); } /** * A Cross has a width in horizontal position of 2 tiles and a height of 1 tile in Vertical position.
* * @return the set of center point which mark the position of the Cross */ @Override public Set getAltPoints() { Set alternatives = new HashSet<>(); switch (getOrientation()) { case SOUTH -> { Point sp = new Point(tileX, (tileY + DEFAULT_HEIGHT)); alternatives.add(sp); } case WEST -> { Point wp = new Point((tileX - DEFAULT_WIDTH), tileY); alternatives.add(wp); } case NORTH -> { Point np = new Point(tileX, (tileY - DEFAULT_HEIGHT)); alternatives.add(np); } default -> { //East so default Point ep = new Point((tileX + DEFAULT_WIDTH), tileY); alternatives.add(ep); } } return alternatives; } @Override public Map getNeighborPoints() { Map neighbors = new HashMap<>(); Orientation orientation = this.getOrientation(); Direction direction = this.getDirection(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 4)); if (Direction.LEFT == direction) { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy + Tile.GRID * 2)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); } else { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy + Tile.GRID * 2)); } } case WEST -> { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 4, cy)); if (Direction.LEFT == direction) { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx - Tile.GRID * 2, cy + Tile.GRID * 2)); } else { neighbors.put(Orientation.NORTH, new Point(cx - Tile.GRID * 2, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); } } case NORTH -> { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 4)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); if (Direction.LEFT == direction) { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy - Tile.GRID * 2)); } else { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy - Tile.GRID * 2)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); } } default -> { //EAST neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 4, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); if (Direction.LEFT == direction) { neighbors.put(Orientation.NORTH, new Point(cx + Tile.GRID * 2, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); } else { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx + Tile.GRID * 2, cy + Tile.GRID * 2)); } } } return neighbors; } @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); Orientation orientation = this.getOrientation(); Direction direction = this.getDirection(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 3)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy + Tile.GRID * 2)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); } else { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy + Tile.GRID * 2)); } } case WEST -> { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID * 3, cy)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx - Tile.GRID * 2, cy + Tile.GRID)); } else { edgeConnections.put(Orientation.NORTH, new Point(cx - Tile.GRID * 2, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); } } case NORTH -> { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 3)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy - Tile.GRID * 2)); } else { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy - Tile.GRID * 2)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); } } default -> { //EAST edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID * 3, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.NORTH, new Point(cx + Tile.GRID * 2, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); } else { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx + Tile.GRID * 2, cy + Tile.GRID)); } } } return edgeConnections; } @Override protected void renderStraight(Graphics2D g2, Color color) { int xx, yy, w, h; xx = 0; yy = 170; w = RENDER_WIDTH; h = 60; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } @Override protected void renderRouteStraight(Graphics2D g2, Color color) { int xx, yy, w, h; xx = 0; yy = 190; w = RENDER_WIDTH; h = 20; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } protected void renderStraight2(Graphics2D g2, Color color) { int xx, yy, w, h; xx = RENDER_WIDTH; yy = 170; w = RENDER_WIDTH; h = 60; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } protected void renderRouteStraight2(Graphics2D g2, Color color) { int xx, yy, w, h; xx = RENDER_WIDTH; yy = 190; w = RENDER_WIDTH; h = 20; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } @Override protected void renderDiagonal(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{400, 400, 167, 230}; yPoints = new int[]{170, 230, 0, 0}; } else { xPoints = new int[]{400, 400, 170, 230}; yPoints = new int[]{230, 170, 400, 400}; } g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillPolygon(xPoints, yPoints, xPoints.length); } @Override protected void renderRouteDiagonal(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{420, 400, 190, 210}; yPoints = new int[]{210, 210, 0, 0}; } else { xPoints = new int[]{400, 400, 190, 210}; yPoints = new int[]{210, 190, 400, 400}; } g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillPolygon(xPoints, yPoints, xPoints.length); } protected void renderDiagonal2(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{400, 400, 570, 630}; yPoints = new int[]{170, 230, 400, 400}; } else { xPoints = new int[]{400, 400, 570, 630}; yPoints = new int[]{230, 170, 0, 0}; } g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillPolygon(xPoints, yPoints, xPoints.length); } protected void renderRouteDiagonal2(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{400, 380, 590, 610}; yPoints = new int[]{190, 190, 400, 400}; } else { xPoints = new int[]{400, 380, 590, 610}; yPoints = new int[]{210, 210, 0, 0}; } g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.setPaint(Color.cyan); g2.fillPolygon(xPoints, yPoints, xPoints.length); } @Override public void renderTile(Graphics2D g2) { if (accessoryValue == null) { this.accessoryValue = AccessoryValue.OFF; } switch (accessoryValue) { case RED -> { renderStraight2(g2, Cross.LIGHT_RED); renderDiagonal(g2, Cross.LIGHT_RED); renderStraight(g2, Cross.DARK_RED); renderDiagonal2(g2, Cross.DARK_RED); } case GREEN -> { renderDiagonal(g2, Cross.VERY_LIGHT_GREEN); renderDiagonal2(g2, Cross.VERY_LIGHT_GREEN); renderStraight(g2, Cross.DARK_GREEN); renderStraight2(g2, Cross.DARK_GREEN); } default -> { renderStraight(g2, trackColor); renderStraight2(g2, trackColor); renderDiagonal(g2, trackColor); renderDiagonal2(g2, trackColor); } } } @Override public void renderTileRoute(Graphics2D g2) { if (routeValue == null) { routeValue = AccessoryValue.OFF; } if (incomingSide == null) { incomingSide = getOrientation(); } if (isHorizontal()) { if (AccessoryValue.GREEN == routeValue && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteDiagonal(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (AccessoryValue.GREEN == routeValue && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteStraight2(g2, trackRouteColor); } else if (AccessoryValue.RED == routeValue && Orientation.EAST == getOrientation()) { if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight2(g2, trackRouteColor); renderRouteDiagonal(g2, trackRouteColor); } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteDiagonal2(g2, trackRouteColor); renderRouteStraight(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight2(g2, trackRouteColor); renderRouteDiagonal(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight(g2, trackColor); renderRouteDiagonal2(g2, trackColor); } } else if (AccessoryValue.RED == routeValue && Orientation.WEST == getOrientation()) { if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteDiagonal(g2, trackRouteColor); renderRouteStraight2(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight2(g2, trackColor); renderRouteDiagonal(g2, trackColor); } } } else { if (AccessoryValue.GREEN == routeValue && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteStraight2(g2, trackRouteColor); } else if (AccessoryValue.GREEN == routeValue && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { renderRouteDiagonal(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (AccessoryValue.RED == routeValue && Orientation.SOUTH == getOrientation()) { if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight2(g2, trackRouteColor); renderRouteDiagonal(g2, trackRouteColor); } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteDiagonal2(g2, trackRouteColor); renderRouteStraight(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight2(g2, trackColor); renderRouteDiagonal(g2, trackColor); } } else if (AccessoryValue.RED == routeValue && Orientation.NORTH == getOrientation()) { if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteDiagonal(g2, trackRouteColor); renderRouteStraight2(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight2(g2, trackRouteColor); renderRouteDiagonal(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight(g2, trackColor); renderRouteDiagonal2(g2, trackColor); } } } } @Override public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { if (from != null && to != null && this.getDirection() != null) { switch (this.getDirection()) { case LEFT -> { if (this.isHorizontal()) { if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.NORTH)) { return AccessoryValue.RED; } else if ((from == Orientation.EAST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.EAST)) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } else { //Vertical if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if ((from == Orientation.SOUTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.SOUTH)) { return AccessoryValue.RED; } else if ((from == Orientation.EAST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.EAST)) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } } case RIGHT -> { if (this.isHorizontal()) { if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.NORTH)) { return AccessoryValue.RED; } else if ((from == Orientation.WEST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.WEST)) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } else { //Vertical if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if ((from == Orientation.SOUTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.SOUTH)) { return AccessoryValue.RED; } else if ((from == Orientation.WEST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.WEST)) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } } default -> { return AccessoryValue.OFF; } } } else { return AccessoryValue.OFF; } } @Override protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { //A Cross has 1 alternate point //1st square holds the centerpoint //2nd square double dX1, dX2, dY1, dY2; Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case SOUTH -> { dX1 = renderWidth / 2 - size / 2; dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; dX2 = renderWidth / 2 + renderWidth - size / 4; dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; } case WEST -> { dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; dY1 = renderHeight / 2 - size / 2; dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; dY2 = renderHeight / 2 - size / 4; } case NORTH -> { dX1 = renderWidth / 2 - size / 2; dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; dX2 = renderWidth / 2 + renderWidth - size / 4; dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; } default -> { //East dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; dY1 = renderHeight / 2 - size / 2; dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; dY2 = renderHeight / 2 - size / 4; } } g2d.setColor(color); g2d.fill(new Ellipse2D.Double(dX1, dY1, size, size)); g2d.fill(new Ellipse2D.Double(dX2, dY2, size / 2, size / 2)); } @Override public Rectangle getTileBounds() { Orientation tileOrientation = model.getTileOrienation(); int xx, yy, w, h, multiplier; if (model.isScaleImage()) { w = tileWidth(tileOrientation, TileType.CROSS); h = tileHeight(tileOrientation, TileType.CROSS); multiplier = 1; } else { w = renderWidth; h = renderHeight; multiplier = 10; } switch (tileOrientation) { case SOUTH -> { xx = tileX - GRID * multiplier; yy = tileY - GRID * multiplier; } case WEST -> { xx = tileX - GRID * multiplier - GRID * 2 * multiplier; yy = tileY - GRID * multiplier; } case NORTH -> { xx = tileX - GRID * multiplier; yy = tileY - GRID * multiplier - GRID * 2 * multiplier; } default -> { //East xx = tileX - GRID * multiplier; yy = tileY - GRID * multiplier; } } Logger.trace(id + " O: " + tileOrientation + " Cur Cp: " + xyToString() + " New DsP: (" + xx + ", " + yy + ") W: " + w + " H: " + h + " M: " + multiplier + " Ox: " + offsetX + " Oy: " + offsetY); if (model.isScaleImage()) { return new Rectangle(xx, yy, tileWidth(tileOrientation, TileType.CROSS), tileHeight(tileOrientation, TileType.CROSS)); } else { return new Rectangle(xx, yy, renderWidth, renderHeight); } } private void changeRenderSizeAndOffsets() { //Reset offsets this.offsetY = 0; this.renderOffsetY = 0; this.offsetX = 0; this.renderOffsetX = 0; if (isHorizontal()) { //this.width = DEFAULT_WIDTH * 2; //this.height = DEFAULT_HEIGHT; this.renderWidth = RENDER_GRID * 4; this.renderHeight = RENDER_GRID * 2; this.offsetY = 0; this.renderOffsetY = 0; } else { //this.width = DEFAULT_WIDTH; //this.height = DEFAULT_HEIGHT * 2; this.renderWidth = RENDER_GRID * 2; this.renderHeight = RENDER_GRID * 4; this.offsetX = 0; this.renderOffsetX = 0; } //Due to the asymetical shape (center is on the left) //the offset has to be changed with the rotation Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case SOUTH -> { this.offsetY = +GRID; this.renderOffsetY = RENDER_GRID; } case WEST -> { this.offsetX = -GRID; this.renderOffsetX = -RENDER_GRID; } case NORTH -> { this.offsetY = -GRID; this.renderOffsetY = -RENDER_GRID; } default -> { //East so default this.offsetX = +GRID; this.renderOffsetX = +RENDER_GRID; } } } @Override public Orientation rotate() { super.rotate(); Orientation tileOrientation = model.getTileOrienation(); int w = tileWidth(tileOrientation, TileType.CROSS); int h = tileHeight(tileOrientation, TileType.CROSS); //the centerpoin can shift as a cross is inbalanced int multiplier = (model.isScaleImage() ? 1 : 10); int x, y; switch (tileOrientation) { case SOUTH -> { //the centerpoint remains the same x = tileX; y = tileY; } case WEST -> { // centerpoint shifts to the 2nd square x = tileX; // - GRID * multiplier - GRID * 2 * multiplier; y = tileY; // - GRID * multiplier; } case NORTH -> { x = tileX; // - GRID * multiplier; y = tileY; // - GRID * multiplier - GRID * 2 * multiplier; } default -> { //East x = tileX; y = tileY; } } Dimension d = new Dimension(w, h); setPreferredSize(d); setSize(d); changeRenderSizeAndOffsets(); //set the new center this.tileX = x; this.tileY = y; Logger.trace(id + " O: " + tileOrientation + " Cur Cp: " + xyToString() + " New CP: (" + x + ", " + y + ") W: " + w + " H: " + h + " M: " + multiplier + " Ox: " + offsetX + " Oy: " + offsetY); setBounds(getTileBounds()); return tileOrientation; } } \ No newline at end of file diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java index fdf6acf3..dfd1939e 100755 --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -1,1131 +1 @@ -/* - * Copyright 2024 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout.tiles; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.geom.AffineTransform; -import java.awt.geom.Ellipse2D; -import java.awt.image.AffineTransformOp; -import java.awt.image.BufferedImage; -import java.beans.PropertyChangeListener; -import java.io.Serializable; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import javax.swing.JComponent; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import jcs.entities.AccessoryBean; -import jcs.entities.AccessoryBean.AccessoryValue; -import jcs.entities.AccessoryBean.SignalType; -import jcs.entities.BlockBean; -import jcs.entities.BlockBean.BlockState; -import jcs.entities.LocomotiveBean; -import jcs.entities.SensorBean; -import jcs.entities.TileBean; -import jcs.entities.TileBean.Direction; -import jcs.entities.TileBean.Orientation; -import jcs.entities.TileBean.TileType; -import jcs.ui.layout.LayoutUtil; -import static jcs.ui.layout.tiles.Block.BLOCK_HEIGHT; -import static jcs.ui.layout.tiles.Block.BLOCK_WIDTH; -import org.imgscalr.Scalr; -import org.imgscalr.Scalr.Method; -import org.imgscalr.Scalr.Mode; -import org.tinylog.Logger; - -/** - * Basic graphic element to display a track, turnout, etc on the screen.
- * By default the drawing of a Tile is Horizontal from L to R or West to East.
- * The default orientation is East. - * - *

- * The default size of a Tile is 40 tileX 40 pixels.
- * The center point of a Tile is stored and always snapped to the nearest grid point.
- * The basic grid is 20x 20 pixels.
- * - *

- * A Tile can be rotated (always clockwise).
- * Rotation will change the orientation from East -> South -> West -> North -> East.
- * - *

- * A Tile is rendered to a Buffered Image to speed up the display - */ -public abstract class Tile extends JComponent { //implements TileEventListener { //, ItemSelectable { - - public static final int GRID = 20; - public static final int DEFAULT_WIDTH = GRID * 2; - public static final int DEFAULT_HEIGHT = GRID * 2; - - static final int RENDER_GRID = GRID * 10; - static final int RENDER_WIDTH = RENDER_GRID * 2; - static final int RENDER_HEIGHT = RENDER_GRID * 2; - - public static final Color DEFAULT_BACKGROUND_COLOR = Color.white; - public static final Color DEFAULT_TRACK_COLOR = Color.lightGray; - public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.blue; - public static final Color DEFAULT_SELECTED_COLOR = Color.yellow; - - public static final String MODEL_CHANGED_PROPERTY = "model"; - public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled"; - - /** - * The data model that determines the button's state. - */ - protected TileModel model = null; - - protected String id; - protected Integer tileX; - protected Integer tileY; - - protected int renderWidth; - protected int renderHeight; - - //protected Orientation tileOrientation; - protected Direction tileDirection; - - protected TileType tileType; - protected String accessoryId; - protected String sensorId; - - protected AccessoryValue accessoryValue; - protected AccessoryValue routeValue; - - protected SignalType signalType; - protected AccessoryBean.SignalValue signalValue; - - protected TileBean tileBean; - protected AccessoryBean accessoryBean; - protected SensorBean sensorBean; - protected BlockBean blockBean; - - protected List neighbours; - - protected int offsetX = 0; - protected int offsetY = 0; - - protected int renderOffsetX = 0; - protected int renderOffsetY = 0; - - protected Color selectedColor; - protected Color trackColor; - protected Color trackRouteColor; - protected Orientation incomingSide; - - protected Color backgroundColor; - protected boolean drawName = true; - - protected BufferedImage tileImage; - - protected PropertyChangeListener propertyChangeListener; - - protected ChangeListener changeListener = null; - protected ActionListener actionListener = null; - - protected transient ChangeEvent changeEvent; - - private Handler handler; - - protected Tile(TileType tileType, Orientation orientation, Point center, int width, int height) { - this(tileType, orientation, Direction.CENTER, center.x, center.y, width, height); - } - - protected Tile(TileType tileType, Orientation orientation, int x, int y, int width, int height) { - this(tileType, orientation, Direction.CENTER, x, y, width, height); - } - - protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { - this(tileType, orientation, direction, x, y, width, height, null, null); - } - - protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height, Color backgroundColor, Color selectedColor) { - this.tileType = tileType; - //this.tileOrientation = orientation; - //model.setTileOrienation(orientation); - this.tileDirection = direction; - this.tileX = x; - this.tileY = y; - - setLayout(null); - Dimension d = new Dimension(width, height); - setSize(d); - setPreferredSize(d); - - this.renderWidth = RENDER_WIDTH; - this.renderHeight = RENDER_HEIGHT; - - this.trackColor = DEFAULT_TRACK_COLOR; - this.backgroundColor = backgroundColor; - this.selectedColor = selectedColor; - - if (this.backgroundColor == null) { - this.backgroundColor = DEFAULT_BACKGROUND_COLOR; - } - if (this.selectedColor == null) { - this.selectedColor = DEFAULT_SELECTED_COLOR; - } - } - - protected Tile(TileBean tileBean) { - this(tileBean, tileWidth(tileBean.getOrientation(), tileBean.getTileType()), tileHeight(tileBean.getOrientation(), tileBean.getTileType())); - } - - protected Tile(TileBean tileBean, int width, int height) { - this.tileBean = tileBean; - //Quick properties - this.id = tileBean.getId(); - this.tileType = tileBean.getTileType(); - //this.tileOrientation = tileBean.getOrientation(); - //this.model.setTileOrienation(tileBean.getOrientation()); - this.tileDirection = tileBean.getDirection(); - this.tileX = tileBean.getX(); - this.tileY = tileBean.getY(); - - this.accessoryId = tileBean.getAccessoryId(); - this.accessoryBean = tileBean.getAccessoryBean(); - this.signalType = tileBean.getSignalType(); - - this.sensorId = tileBean.getSensorId(); - this.sensorBean = tileBean.getSensorBean(); - this.blockBean = tileBean.getBlockBean(); - - setLayout(null); - Dimension d = new Dimension(width, height); - setSize(d); - setPreferredSize(d); - - this.trackColor = DEFAULT_TRACK_COLOR; - this.backgroundColor = DEFAULT_BACKGROUND_COLOR; - this.selectedColor = DEFAULT_SELECTED_COLOR; - this.renderWidth = RENDER_WIDTH; - this.renderHeight = RENDER_HEIGHT; - } - - protected static int tileWidth(Orientation orientation, TileType tileType) { - if (Orientation.EAST == orientation || Orientation.WEST == orientation) { - if (null == tileType) { - return DEFAULT_WIDTH; - } else { - return switch (tileType) { - case BLOCK -> - BLOCK_WIDTH; - case CROSS -> - DEFAULT_WIDTH * 2; - default -> - DEFAULT_WIDTH; - }; - } - } else { - return DEFAULT_WIDTH; - } - } - - protected static int tileHeight(Orientation orientation, TileType tileType) { - if (Orientation.EAST == orientation || Orientation.WEST == orientation) { - return DEFAULT_HEIGHT; - } else { - if (null == tileType) { - return DEFAULT_HEIGHT; - } else { - return switch (tileType) { - case BLOCK -> - BLOCK_HEIGHT; - case CROSS -> - DEFAULT_HEIGHT * 2; - default -> - DEFAULT_HEIGHT; - }; - } - } - } - - protected void populateModel() { - if (this.blockBean != null) { - this.model.setBlockState(this.blockBean.getBlockState()); - this.model.setLocomotive(this.blockBean.getLocomotive()); - this.model.setArrivalSuffix(this.blockBean.getArrivalSuffix()); - this.model.setLogicalDirection(LocomotiveBean.Direction.get(this.blockBean.getLogicalDirection())); - } - } - - public TileBean getTileBean() { - if (tileBean == null) { - tileBean = new TileBean(); - tileBean.setId(this.id); - tileBean.setX(this.tileX); - tileBean.setY(this.tileY); - tileBean.setTileType(this.tileType); - //tileBean.setTileOrientation(this.tileOrientation.getOrientation()); - tileBean.setTileOrientation(this.model.getTileOrienation().getOrientation()); - - tileBean.setTileDirection(this.tileDirection.getDirection()); - tileBean.setSignalType(this.signalType); - tileBean.setAccessoryId(this.accessoryId); - tileBean.setSensorId(this.sensorId); - tileBean.setAccessoryBean(this.accessoryBean); - tileBean.setSensorBean(this.sensorBean); - tileBean.setBlockBean(this.blockBean); - } - return tileBean; - } - - public boolean isSelected() { - return model.isSelected(); - } - - public void setSelected(boolean b) { - //boolean oldValue = isSelected(); - model.setSelected(b); - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public SignalType getSignalType() { - return signalType; - } - - public void setSignalType(SignalType signalType) { - this.signalType = signalType; - } - - public Integer getTileX() { - return tileX; - } - - public Integer getTileY() { - return tileY; - } - - public Point getCenter() { - return new Point(this.tileX, this.tileY); - } - - public void setCenter(Point center) { - tileX = center.x; - tileY = center.y; - if (tileBean != null) { - tileBean.setCenter(center); - } - } - - public Orientation getOrientation() { - //return tileOrientation; - return model.getTileOrienation(); - } - - public void setOrientation(Orientation orientation) { - //this.tileOrientation = orientation; - model.setTileOrienation(orientation); - if (tileBean != null) { - tileBean.setOrientation(orientation); - } - } - - public Direction getDirection() { - return tileDirection; - } - - public void setDirection(Direction direction) { - this.tileDirection = direction; - if (tileBean != null) { - tileBean.setDirection(direction); - } - } - - public String getAccessoryId() { - return accessoryId; - } - - public void setAccessoryId(String accessoryId) { - this.accessoryId = accessoryId; - if (tileBean != null) { - tileBean.setAccessoryId(accessoryId); - } - } - - public String getSensorId() { - return sensorId; - } - - public void setSensorId(String sensorId) { - this.sensorId = sensorId; - } - - public boolean isActive() { - return model.isSensorActive(); - } - - public void setActive(boolean active) { - model.setSensorActive(active); - } - - public BlockState getBlockState() { - return model.getBlockState(); - } - - public void setBlockState(BlockState blockState) { - if (blockBean != null) { - blockBean.setBlockState(blockState); - LocomotiveBean locomotive = model.getLocomotive(); - model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (blockState == BlockState.OCCUPIED || blockState == BlockState.INBOUND || blockState == BlockState.OUTBOUND)); - } - model.setBlockState(blockState); - } - - public String getDepartureSuffix() { - return model.getDepartureSuffix(); - } - - public void setDepartureSuffix(String suffix) { - if (blockBean != null) { - blockBean.setDepartureSuffix(suffix); - } - model.setDepartureSuffix(suffix); - } - - public boolean isReverseArrival() { - return model.isReverseArrival(); - } - - public void setReverseArrival(boolean reverseArrival) { - if (blockBean != null) { - blockBean.setReverseArrival(reverseArrival); - } - model.setReverseArrival(reverseArrival); - } - - public LocomotiveBean.Direction getLogicalDirection() { - return model.getLogicalDirection(); - } - - public void setLogicalDirection(LocomotiveBean.Direction logicalDirection) { - if (blockBean != null) { - blockBean.setLogicalDirection(logicalDirection.getDirection()); - } - model.setLogicalDirection(logicalDirection); - } - - public LocomotiveBean getLocomotive() { - return model.getLocomotive(); - } - - public void setLocomotive(LocomotiveBean locomotive) { - if (blockBean != null) { - blockBean.setLocomotive(locomotive); - model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (model.getBlockState() == BlockState.OCCUPIED || model.getBlockState() == BlockState.INBOUND || model.getBlockState() == BlockState.OUTBOUND)); - } - - model.setLocomotive(locomotive); - } - - public AccessoryBean getAccessoryBean() { - return accessoryBean; - } - - public void setAccessoryBean(AccessoryBean accessoryBean) { - this.accessoryBean = accessoryBean; - - if (accessoryBean != null) { - accessoryId = accessoryBean.getId(); - signalValue = accessoryBean.getSignalValue(); - signalType = SignalType.getSignalType(accessoryBean.getType()); - } else { - accessoryId = null; - signalType = SignalType.NONE; - signalValue = AccessoryBean.SignalValue.OFF; - } - } - - public AccessoryValue getAccessoryValue() { - if (this.accessoryValue == null) { - return AccessoryValue.OFF; - } else { - return accessoryValue; - } - } - - public void setAccessoryValue(AccessoryValue value) { - this.accessoryValue = value; - repaint(); - } - - public AccessoryValue getRouteValue() { - if (routeValue == null) { - return AccessoryValue.OFF; - } else { - return routeValue; - } - } - - public void setRouteValue(AccessoryValue value) { - this.routeValue = value; - repaint(); - } - - public AccessoryBean.SignalValue getSignalValue() { - return signalValue; - } - - public void setSignalValue(AccessoryBean.SignalValue signalValue) { - this.signalValue = signalValue; - repaint(); - } - - public SensorBean getSensorBean() { - return sensorBean; - } - - public void setSensorBean(SensorBean sensorBean) { - this.sensorBean = sensorBean; - } - - public BlockBean getBlockBean() { - return blockBean; - } - - public void setBlockBean(BlockBean blockBean) { - this.blockBean = blockBean; - } - - public void setRenderWidth(int renderWidth) { - this.renderWidth = renderWidth; - } - - public void setRenderHeight(int renderHeight) { - this.renderHeight = renderHeight; - } - - public int getRenderOffsetX() { - return renderOffsetX; - } - - public void setRenderOffsetX(int renderOffsetX) { - this.renderOffsetX = renderOffsetX; - } - - public int getRenderOffsetY() { - return renderOffsetY; - } - - public void setRenderOffsetY(int renderOffsetY) { - this.renderOffsetY = renderOffsetY; - } - - public TileBean.TileType getTileType() { - return this.tileType; - } - - public final void setTileType(TileType tileType) { - this.tileType = tileType; - } - - public Color getTrackColor() { - return trackColor; - } - - public final void setTrackColor(Color trackColor) { - this.trackColor = trackColor; - } - - public Color getTrackRouteColor() { - return trackRouteColor; - } - - public void setTrackRouteColor(Color trackRouteColor) { - this.trackRouteColor = trackRouteColor; - } - - public Color getSelectedColor() { - return selectedColor; - } - - public void setSelectedColor(Color selectedColor) { - this.selectedColor = selectedColor; - } - - public Orientation getIncomingSide() { - return incomingSide; - } - - public void setIncomingSide(Orientation incomingSide) { - this.incomingSide = incomingSide; - } - - public Color getBackgroundColor() { - return backgroundColor; - } - - public void setBackgroundColor(Color backgroundColor) { - this.backgroundColor = backgroundColor; - } - - public boolean isDrawRoute() { - return model.isShowRoute(); - } - - public void setDrawRoute(boolean drawRoute) { - this.model.setShowRoute(drawRoute); - } - - public int getRenderWidth() { - return renderWidth; - } - - public int getRenderHeight() { - return renderHeight; - } - - abstract void renderTile(Graphics2D g2d); - - abstract void renderTileRoute(Graphics2D g2d); - - public abstract Map getNeighborPoints(); - - public abstract Map getEdgePoints(); - - public abstract Set getAllPoints(); - - /** - * Draw the Tile - * - * @param g2d The graphics handle - */ - public void drawTile(Graphics2D g2d) { - // by default and image is rendered in the EAST orientation - Orientation tileOrientation = model.getTileOrienation(); -// if (tileOrientation == null) { -// tileOrientation = Orientation.EAST; -// } - - BufferedImage bf = createImage(); - Graphics2D g2di = bf.createGraphics(); - - //Avoid errors - if (model.isShowRoute() && incomingSide == null) { - incomingSide = getOrientation(); - } - - if (model.isSelected()) { - g2di.setBackground(selectedColor); - } else { - g2di.setBackground(backgroundColor); - } - - g2di.clearRect(0, 0, renderWidth, renderHeight); - int ox = 0, oy = 0; - - AffineTransform trans = new AffineTransform(); - switch (tileOrientation) { - case SOUTH -> { - trans.rotate(Math.PI / 2, renderWidth / 2, renderHeight / 2); - ox = (renderHeight - renderWidth) / 2; - oy = (renderWidth - renderHeight) / 2; - trans.translate(-ox, -oy); - } - case WEST -> { - trans.rotate(Math.PI, renderWidth / 2, renderHeight / 2); - trans.translate(ox, oy); - } - case NORTH -> { - trans.rotate(-Math.PI / 2, renderWidth / 2, renderHeight / 2); - ox = (renderHeight - renderWidth) / 2; - oy = (renderWidth - renderHeight) / 2; - trans.translate(-ox, -oy); - } - default -> { - trans.rotate(0.0, this.renderWidth / 2, this.renderHeight / 2); - trans.translate(ox, oy); - } - } - - //Logger.trace(tileOrientation.getOrientation() + " renderWidth: " + renderWidth + " renderHeight: " + renderHeight + " CP: (" + renderWidth / 2 + "," + renderHeight / 2 + ")"); - //Logger.trace(tileOrientation.getOrientation() + " ox: " + ox + " oy: " + oy); - g2di.setTransform(trans); - - renderTile(g2di); - - if (model.isShowRoute()) { - renderTileRoute(g2di); - } - - if (model.isShowCenter()) { - drawCenterPoint(g2di); - } - - // Scale the image back... - if (model.isScaleImage()) { - tileImage = Scalr.resize(bf, Method.AUTOMATIC, Mode.FIT_EXACT, getWidth(), getHeight(), Scalr.OP_ANTIALIAS); - } else { - tileImage = bf; - } - - g2di.dispose(); - } - - public BufferedImage getTileImage() { - return tileImage; - } - - /** - * Render a tile image Always starts at (0,0) used the default width and height - * - * @param g2 the Graphic context - */ - public void drawName(Graphics2D g2) { - } - - protected void drawCenterPoint(Graphics2D g2d) { - drawCenterPoint(g2d, Color.magenta); - } - - protected void drawCenterPoint(Graphics2D g2, Color color) { - drawCenterPoint(g2, color, 60); - } - - protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { - double dX = (renderWidth / 2 - size / 2); - double dY = (renderHeight / 2 - size / 2); - - g2d.setColor(color); - g2d.fill(new Ellipse2D.Double(dX, dY, size, size)); - } - - /** - * Rotate the tile clockwise 90 deg - * - * @return the new Orientation - */ - public Orientation rotate() { - Orientation tileOrientation = model.getTileOrienation(); - switch (tileOrientation) { - case EAST -> - setOrientation(Orientation.SOUTH); - case SOUTH -> - setOrientation(Orientation.WEST); - case WEST -> - setOrientation(Orientation.NORTH); - default -> - setOrientation(Orientation.EAST); - } - return model.getTileOrienation(); - } - - public void flipHorizontal() { - Orientation tileOrientation = model.getTileOrienation(); - if (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) { - rotate(); - rotate(); - } - } - - public void flipVertical() { - Orientation tileOrientation = model.getTileOrienation(); - if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { - rotate(); - rotate(); - } - } - - @Override - public void move(int newX, int newY) { - Point cs = LayoutUtil.snapToGrid(newX, newY); - setCenter(cs); - } - - protected static void drawRotate(Graphics2D g2d, double x, double y, int angle, String text) { - g2d.translate((float) x, (float) y); - g2d.rotate(Math.toRadians(angle)); - g2d.drawString(text, 0, 0); - g2d.rotate(-Math.toRadians(angle)); - g2d.translate(-x, -y); - } - - public static BufferedImage flipHorizontally(BufferedImage source) { - BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); - - AffineTransform flip = AffineTransform.getScaleInstance(1, -1); - flip.translate(0, -source.getHeight()); - AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); - - op.filter(source, output); - - return output; - } - - public static BufferedImage flipVertically(BufferedImage source) { - BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); - - AffineTransform flip = AffineTransform.getScaleInstance(-1, 1); - flip.translate(-source.getWidth(), 0); - AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); - - op.filter(source, output); - - return output; - } - - public Set getAltPoints() { - return Collections.EMPTY_SET; - } - - public final int getOffsetX() { - return offsetX; - } - - public void setOffsetX(int offsetX) { - this.offsetX = offsetX; - } - - public final int getOffsetY() { - return offsetY; - } - - public void setOffsetY(int offsetY) { - this.offsetY = offsetY; - } - - protected BufferedImage createImage() { - return new BufferedImage(renderWidth, renderHeight, BufferedImage.TYPE_INT_RGB); - } - - public int getCenterX() { - if (tileX > 0) { - return this.tileX; - } else { - return GRID; - } - } - - public int getCenterY() { - if (tileY > 0) { - return this.tileY; - } else { - return GRID; - } - } - - public boolean isDrawName() { - return drawName; - } - - public void setDrawName(boolean drawName) { - this.drawName = drawName; - } - - public boolean isScaleImage() { - return model.isScaleImage(); - } - - public void setScaleImage(boolean scaleImage) { - Dimension d; - if (scaleImage) { - d = new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); - } else { - d = new Dimension(renderWidth, renderHeight); - } - - setSize(d); - setPreferredSize(d); - - model.setScaleImage(scaleImage); - } - - public boolean isDrawCenterPoint() { - return model.isShowCenter(); - } - - public void setDrawCenterPoint(boolean drawCenterPoint) { - model.setShowCenter(drawCenterPoint); - } - - @Override - public String toString() { - return this.getClass().getSimpleName() - + " {id: " - + this.id - + ", orientation: " - + getOrientation() - + ", direction: " - + getDirection() - + ", center: " - + xyToString() - + "}"; - } - - public String xyToString() { - return "(" + this.tileX + "," + this.tileY + ")"; - } - - /** - * The main route of the tile is horizontal - * - * @return true when main route goes from East to West or vv - */ - public boolean isHorizontal() { - Orientation tileOrientation = model.getTileOrienation(); - return (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) && TileType.CURVED != tileType; - } - - /** - * The main route of the tile is vertical - * - * @return true when main route goes from North to South or vv - */ - public boolean isVertical() { - Orientation tileOrientation = model.getTileOrienation(); - return (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) && TileType.CURVED != tileType; - } - - public boolean isJunction() { - return TileType.SWITCH == tileType || TileType.CROSS == tileType; - } - - public boolean isBlock() { - return TileType.BLOCK == tileType; - } - - public boolean isDirectional() { - return TileType.STRAIGHT_DIR == tileType; - } - - /** - * The main route of the tile is diagonal - * - * @return true when main route goes from North to East or West to South and vv - */ - public boolean isDiagonal() { - return TileType.CURVED == tileType; - } - - public boolean isCrossing() { - return TileType.CROSSING == tileType; - } - - public List getNeighbours() { - return neighbours; - } - - public void setNeighbours(List neighbours) { - this.neighbours = neighbours; - } - - public String getIdSuffix(Tile other) { - return ""; - } - - public Map getNeighborOrientations() { - Map edgeOrientations = new HashMap<>(); - - Map neighborPoints = getNeighborPoints(); - - for (Orientation o : Orientation.values()) { - edgeOrientations.put(neighborPoints.get(o), o); - } - return edgeOrientations; - } - - public Map getEdgeOrientations() { - Map edgeOrientations = new HashMap<>(); - - Map edgeConnections = getEdgePoints(); - - for (Orientation o : Orientation.values()) { - edgeOrientations.put(edgeConnections.get(o), o); - } - return edgeOrientations; - } - - public boolean isAdjacent(Tile other) { - boolean adjacent = false; - - if (other != null) { - Collection thisEdgePoints = getEdgePoints().values(); - Collection otherEdgePoints = other.getEdgePoints().values(); - - for (Point p : thisEdgePoints) { - adjacent = otherEdgePoints.contains(p); - if (adjacent) { - break; - } - } - } - - return adjacent; - } - - /** - * When the tile has a specific direction a train may travel,
- * then this method will indicate whether the other tile is in on the side where the arrow is pointing to. - * - * @param other A Tile - * @return true where other is on the side of this tile where the arrow points to - */ - public boolean isArrowDirection(Tile other) { - return true; - } - - public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { - return AccessoryValue.OFF; - } - - public TileModel getModel() { - return model; - } - - public void setModel(TileModel newModel) { - TileModel oldModel = getModel(); - - if (oldModel != null) { - oldModel.removeChangeListener(changeListener); - oldModel.removeActionListener(actionListener); - changeListener = null; - actionListener = null; - } - - model = newModel; - - if (newModel != null) { - changeListener = createChangeListener(); - actionListener = createActionListener(); - - newModel.addChangeListener(changeListener); - newModel.addActionListener(actionListener); - } - - firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel); - if (newModel != oldModel) { - revalidate(); - repaint(); - } - } - -// public TileUI getUI() { -// return (TileUI) ui; -// } -// public void setUI(TileUI ui) { -// super.setUI(ui); -// } - @Override - public void updateUI() { - } - - protected ChangeListener createChangeListener() { - return getHandler(); - } - - protected ActionListener createActionListener() { - return getHandler(); - } - - private Handler getHandler() { - if (handler == null) { - handler = new Handler(); - } - return handler; - } - - class Handler implements ActionListener, ChangeListener, Serializable { - - @Override - public void stateChanged(ChangeEvent e) { - //Object source = e.getSource(); - - fireStateChanged(); - repaint(); - } - - @Override - public void actionPerformed(ActionEvent event) { - fireActionPerformed(event); - } - } - - protected void fireStateChanged() { - Object[] listeners = listenerList.getListenerList(); - //reverse order - for (int i = listeners.length - 2; i >= 0; i -= 2) { - if (listeners[i] == ChangeListener.class) { - // Lazily create the event: - if (changeEvent == null) { - changeEvent = new ChangeEvent(this); - } - ((ChangeListener) listeners[i + 1]).stateChanged(changeEvent); - } - } - } - - protected void fireActionPerformed(ActionEvent event) { - Object[] listeners = listenerList.getListenerList(); - ActionEvent e = null; - // reverse - for (int i = listeners.length - 2; i >= 0; i -= 2) { - if (listeners[i] == ActionListener.class) { - // Lazily create the event: - if (e == null) { - String actionCommand = event.getActionCommand(); - //if(actionCommand == null) { - // actionCommand = getActionCommand(); - //} - e = new ActionEvent(Tile.this, ActionEvent.ACTION_PERFORMED, actionCommand, event.getWhen(), event.getModifiers()); - } - ((ActionListener) listeners[i + 1]).actionPerformed(e); - } - } - } - - public Rectangle getTileBounds() { - //return new Rectangle(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); - - if (model.isScaleImage()) { - return new Rectangle(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); - } else { - return new Rectangle(tileX - renderWidth / 2, tileY - renderHeight / 2, renderWidth, renderHeight); - } - - } - - @Override - protected void paintComponent(Graphics g) { - long started = System.currentTimeMillis(); - - Graphics2D g2 = (Graphics2D) g.create(); - //Graphics2D g2 = (Graphics2D) g.create(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); - drawTile(g2); - g2.dispose(); - - g.drawImage(tileImage, 0, 0, null); - - long now = System.currentTimeMillis(); - Logger.trace(id + " Duration: " + (now - started) + " ms. Tile (" + tileX + "," + tileY + ")"); - } - -} +/* * Copyright 2024 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.AffineTransform; import java.awt.geom.Ellipse2D; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; import java.beans.PropertyChangeListener; import java.io.Serializable; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import javax.swing.JComponent; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.AccessoryValue; import jcs.entities.AccessoryBean.SignalType; import jcs.entities.BlockBean; import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; import jcs.entities.SensorBean; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import jcs.entities.TileBean.TileType; import jcs.ui.layout.LayoutUtil; import static jcs.ui.layout.tiles.Block.BLOCK_HEIGHT; import static jcs.ui.layout.tiles.Block.BLOCK_WIDTH; import org.imgscalr.Scalr; import org.imgscalr.Scalr.Method; import org.imgscalr.Scalr.Mode; import org.tinylog.Logger; /** * Basic graphic element to display a track, turnout, etc on the screen.
* By default the drawing of a Tile is Horizontal from L to R or West to East.
* The default orientation is East. * *

* The default size of a Tile is 40 tileX 40 pixels.
* The center point of a Tile is stored and always snapped to the nearest grid point.
* The basic grid is 20x 20 pixels.
* *

* A Tile can be rotated (always clockwise).
* Rotation will change the orientation from East -> South -> West -> North -> East.
* *

* A Tile is rendered to a Buffered Image to speed up the display */ public abstract class Tile extends JComponent { //implements TileEventListener { //, ItemSelectable { public static final int GRID = 20; public static final int DEFAULT_WIDTH = GRID * 2; public static final int DEFAULT_HEIGHT = GRID * 2; static final int RENDER_GRID = GRID * 10; static final int RENDER_WIDTH = RENDER_GRID * 2; static final int RENDER_HEIGHT = RENDER_GRID * 2; public static final Color DEFAULT_BACKGROUND_COLOR = Color.white; public static final Color DEFAULT_TRACK_COLOR = Color.lightGray; public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.blue; public static final Color DEFAULT_SELECTED_COLOR = Color.yellow; public static final String MODEL_CHANGED_PROPERTY = "model"; public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled"; /** * The data model that determines the button's state. */ protected TileModel model = null; protected String id; protected Integer tileX; protected Integer tileY; protected int renderWidth; protected int renderHeight; //protected Orientation tileOrientation; protected Direction tileDirection; protected TileType tileType; protected String accessoryId; protected String sensorId; protected AccessoryValue accessoryValue; protected AccessoryValue routeValue; protected SignalType signalType; protected AccessoryBean.SignalValue signalValue; protected TileBean tileBean; protected AccessoryBean accessoryBean; protected SensorBean sensorBean; protected BlockBean blockBean; protected List neighbours; protected int offsetX = 0; protected int offsetY = 0; protected int renderOffsetX = 0; protected int renderOffsetY = 0; protected Color selectedColor; protected Color trackColor; protected Color trackRouteColor; protected Orientation incomingSide; protected Color backgroundColor; protected boolean drawName = true; protected BufferedImage tileImage; protected PropertyChangeListener propertyChangeListener; protected ChangeListener changeListener = null; protected ActionListener actionListener = null; protected transient ChangeEvent changeEvent; private Handler handler; protected Tile(TileType tileType, Orientation orientation, Point center, int width, int height) { this(tileType, orientation, Direction.CENTER, center.x, center.y, width, height); } protected Tile(TileType tileType, Orientation orientation, int x, int y, int width, int height) { this(tileType, orientation, Direction.CENTER, x, y, width, height); } protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { this(tileType, orientation, direction, x, y, width, height, null, null); } protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height, Color backgroundColor, Color selectedColor) { this.tileType = tileType; //this.tileOrientation = orientation; //model.setTileOrienation(orientation); this.tileDirection = direction; this.tileX = x; this.tileY = y; setLayout(null); Dimension d = new Dimension(width, height); setSize(d); setPreferredSize(d); this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT; this.trackColor = DEFAULT_TRACK_COLOR; this.backgroundColor = backgroundColor; this.selectedColor = selectedColor; if (this.backgroundColor == null) { this.backgroundColor = DEFAULT_BACKGROUND_COLOR; } if (this.selectedColor == null) { this.selectedColor = DEFAULT_SELECTED_COLOR; } } protected Tile(TileBean tileBean) { this(tileBean, tileWidth(tileBean.getOrientation(), tileBean.getTileType()), tileHeight(tileBean.getOrientation(), tileBean.getTileType())); } protected Tile(TileBean tileBean, int width, int height) { this.tileBean = tileBean; //Quick properties this.id = tileBean.getId(); this.tileType = tileBean.getTileType(); //this.tileOrientation = tileBean.getOrientation(); //this.model.setTileOrienation(tileBean.getOrientation()); this.tileDirection = tileBean.getDirection(); this.tileX = tileBean.getX(); this.tileY = tileBean.getY(); this.accessoryId = tileBean.getAccessoryId(); this.accessoryBean = tileBean.getAccessoryBean(); this.signalType = tileBean.getSignalType(); this.sensorId = tileBean.getSensorId(); this.sensorBean = tileBean.getSensorBean(); this.blockBean = tileBean.getBlockBean(); setLayout(null); Dimension d = new Dimension(width, height); setSize(d); setPreferredSize(d); this.trackColor = DEFAULT_TRACK_COLOR; this.backgroundColor = DEFAULT_BACKGROUND_COLOR; this.selectedColor = DEFAULT_SELECTED_COLOR; this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT; } protected static int tileWidth(Orientation orientation, TileType tileType) { if (Orientation.EAST == orientation || Orientation.WEST == orientation) { if (null == tileType) { return DEFAULT_WIDTH; } else { return switch (tileType) { case BLOCK -> BLOCK_WIDTH; case CROSS -> DEFAULT_WIDTH * 2; default -> DEFAULT_WIDTH; }; } } else { return DEFAULT_WIDTH; } } protected static int tileHeight(Orientation orientation, TileType tileType) { if (Orientation.EAST == orientation || Orientation.WEST == orientation) { return DEFAULT_HEIGHT; } else { if (null == tileType) { return DEFAULT_HEIGHT; } else { return switch (tileType) { case BLOCK -> BLOCK_HEIGHT; case CROSS -> DEFAULT_HEIGHT * 2; default -> DEFAULT_HEIGHT; }; } } } protected void populateModel() { if (this.blockBean != null) { this.model.setBlockState(this.blockBean.getBlockState()); this.model.setLocomotive(this.blockBean.getLocomotive()); this.model.setArrivalSuffix(this.blockBean.getArrivalSuffix()); this.model.setLogicalDirection(LocomotiveBean.Direction.get(this.blockBean.getLogicalDirection())); } } public TileBean getTileBean() { if (tileBean == null) { tileBean = new TileBean(); tileBean.setId(this.id); tileBean.setX(this.tileX); tileBean.setY(this.tileY); tileBean.setTileType(this.tileType); //tileBean.setTileOrientation(this.tileOrientation.getOrientation()); tileBean.setTileOrientation(this.model.getTileOrienation().getOrientation()); tileBean.setTileDirection(this.tileDirection.getDirection()); tileBean.setSignalType(this.signalType); tileBean.setAccessoryId(this.accessoryId); tileBean.setSensorId(this.sensorId); tileBean.setAccessoryBean(this.accessoryBean); tileBean.setSensorBean(this.sensorBean); tileBean.setBlockBean(this.blockBean); } return tileBean; } public boolean isSelected() { return model.isSelected(); } public void setSelected(boolean b) { //boolean oldValue = isSelected(); model.setSelected(b); } public String getId() { return id; } public void setId(String id) { this.id = id; } public SignalType getSignalType() { return signalType; } public void setSignalType(SignalType signalType) { this.signalType = signalType; } public Integer getTileX() { return tileX; } public Integer getTileY() { return tileY; } public Point getCenter() { return new Point(this.tileX, this.tileY); } public void setCenter(Point center) { tileX = center.x; tileY = center.y; if (tileBean != null) { tileBean.setCenter(center); } Logger.trace(id + " Cp: " + xyToString()); } public Orientation getOrientation() { //return tileOrientation; return model.getTileOrienation(); } public void setOrientation(Orientation orientation) { //this.tileOrientation = orientation; model.setTileOrienation(orientation); if (tileBean != null) { tileBean.setOrientation(orientation); } } public Direction getDirection() { return tileDirection; } public void setDirection(Direction direction) { this.tileDirection = direction; if (tileBean != null) { tileBean.setDirection(direction); } } public String getAccessoryId() { return accessoryId; } public void setAccessoryId(String accessoryId) { this.accessoryId = accessoryId; if (tileBean != null) { tileBean.setAccessoryId(accessoryId); } } public String getSensorId() { return sensorId; } public void setSensorId(String sensorId) { this.sensorId = sensorId; } public boolean isActive() { return model.isSensorActive(); } public void setActive(boolean active) { model.setSensorActive(active); } public BlockState getBlockState() { return model.getBlockState(); } public void setBlockState(BlockState blockState) { if (blockBean != null) { blockBean.setBlockState(blockState); LocomotiveBean locomotive = model.getLocomotive(); model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (blockState == BlockState.OCCUPIED || blockState == BlockState.INBOUND || blockState == BlockState.OUTBOUND)); } model.setBlockState(blockState); } public String getDepartureSuffix() { return model.getDepartureSuffix(); } public void setDepartureSuffix(String suffix) { if (blockBean != null) { blockBean.setDepartureSuffix(suffix); } model.setDepartureSuffix(suffix); } public boolean isReverseArrival() { return model.isReverseArrival(); } public void setReverseArrival(boolean reverseArrival) { if (blockBean != null) { blockBean.setReverseArrival(reverseArrival); } model.setReverseArrival(reverseArrival); } public LocomotiveBean.Direction getLogicalDirection() { return model.getLogicalDirection(); } public void setLogicalDirection(LocomotiveBean.Direction logicalDirection) { if (blockBean != null) { blockBean.setLogicalDirection(logicalDirection.getDirection()); } model.setLogicalDirection(logicalDirection); } public LocomotiveBean getLocomotive() { return model.getLocomotive(); } public void setLocomotive(LocomotiveBean locomotive) { if (blockBean != null) { blockBean.setLocomotive(locomotive); model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (model.getBlockState() == BlockState.OCCUPIED || model.getBlockState() == BlockState.INBOUND || model.getBlockState() == BlockState.OUTBOUND)); } model.setLocomotive(locomotive); } public AccessoryBean getAccessoryBean() { return accessoryBean; } public void setAccessoryBean(AccessoryBean accessoryBean) { this.accessoryBean = accessoryBean; if (accessoryBean != null) { accessoryId = accessoryBean.getId(); signalValue = accessoryBean.getSignalValue(); signalType = SignalType.getSignalType(accessoryBean.getType()); } else { accessoryId = null; signalType = SignalType.NONE; signalValue = AccessoryBean.SignalValue.OFF; } } public AccessoryValue getAccessoryValue() { if (this.accessoryValue == null) { return AccessoryValue.OFF; } else { return accessoryValue; } } public void setAccessoryValue(AccessoryValue value) { this.accessoryValue = value; repaint(); } public AccessoryValue getRouteValue() { if (routeValue == null) { return AccessoryValue.OFF; } else { return routeValue; } } public void setRouteValue(AccessoryValue value) { this.routeValue = value; repaint(); } public AccessoryBean.SignalValue getSignalValue() { return signalValue; } public void setSignalValue(AccessoryBean.SignalValue signalValue) { this.signalValue = signalValue; repaint(); } public SensorBean getSensorBean() { return sensorBean; } public void setSensorBean(SensorBean sensorBean) { this.sensorBean = sensorBean; } public BlockBean getBlockBean() { return blockBean; } public void setBlockBean(BlockBean blockBean) { this.blockBean = blockBean; } public void setRenderWidth(int renderWidth) { this.renderWidth = renderWidth; } public void setRenderHeight(int renderHeight) { this.renderHeight = renderHeight; } public int getRenderOffsetX() { return renderOffsetX; } public void setRenderOffsetX(int renderOffsetX) { this.renderOffsetX = renderOffsetX; } public int getRenderOffsetY() { return renderOffsetY; } public void setRenderOffsetY(int renderOffsetY) { this.renderOffsetY = renderOffsetY; } public TileBean.TileType getTileType() { return this.tileType; } public final void setTileType(TileType tileType) { this.tileType = tileType; } public Color getTrackColor() { return trackColor; } public final void setTrackColor(Color trackColor) { this.trackColor = trackColor; } public Color getTrackRouteColor() { return trackRouteColor; } public void setTrackRouteColor(Color trackRouteColor) { this.trackRouteColor = trackRouteColor; } public Color getSelectedColor() { return selectedColor; } public void setSelectedColor(Color selectedColor) { this.selectedColor = selectedColor; } public Orientation getIncomingSide() { return incomingSide; } public void setIncomingSide(Orientation incomingSide) { this.incomingSide = incomingSide; } public Color getBackgroundColor() { return backgroundColor; } public void setBackgroundColor(Color backgroundColor) { this.backgroundColor = backgroundColor; } public boolean isDrawRoute() { return model.isShowRoute(); } public void setDrawRoute(boolean drawRoute) { this.model.setShowRoute(drawRoute); } public int getRenderWidth() { return renderWidth; } public int getRenderHeight() { return renderHeight; } abstract void renderTile(Graphics2D g2d); abstract void renderTileRoute(Graphics2D g2d); public abstract Map getNeighborPoints(); public abstract Map getEdgePoints(); public abstract Set getAllPoints(); /** * Draw the Tile * * @param g2d The graphics handle */ public void drawTile(Graphics2D g2d) { // by default and image is rendered in the EAST orientation Orientation tileOrientation = model.getTileOrienation(); // if (tileOrientation == null) { // tileOrientation = Orientation.EAST; // } BufferedImage bf = createImage(); Graphics2D g2di = bf.createGraphics(); //Avoid errors if (model.isShowRoute() && incomingSide == null) { incomingSide = getOrientation(); } if (model.isSelected()) { g2di.setBackground(selectedColor); } else { g2di.setBackground(backgroundColor); } g2di.clearRect(0, 0, renderWidth, renderHeight); int ox = 0, oy = 0; AffineTransform trans = new AffineTransform(); switch (tileOrientation) { case SOUTH -> { trans.rotate(Math.PI / 2, renderWidth / 2, renderHeight / 2); ox = (renderHeight - renderWidth) / 2; oy = (renderWidth - renderHeight) / 2; trans.translate(-ox, -oy); } case WEST -> { trans.rotate(Math.PI, renderWidth / 2, renderHeight / 2); trans.translate(ox, oy); } case NORTH -> { trans.rotate(-Math.PI / 2, renderWidth / 2, renderHeight / 2); ox = (renderHeight - renderWidth) / 2; oy = (renderWidth - renderHeight) / 2; trans.translate(-ox, -oy); } default -> { trans.rotate(0.0, this.renderWidth / 2, this.renderHeight / 2); trans.translate(ox, oy); } } //Logger.trace(tileOrientation.getOrientation() + " renderWidth: " + renderWidth + " renderHeight: " + renderHeight + " CP: (" + renderWidth / 2 + "," + renderHeight / 2 + ")"); //Logger.trace(tileOrientation.getOrientation() + " ox: " + ox + " oy: " + oy); g2di.setTransform(trans); renderTile(g2di); if (model.isShowRoute()) { renderTileRoute(g2di); } if (model.isShowCenter()) { drawCenterPoint(g2di); } // Scale the image back... if (model.isScaleImage()) { tileImage = Scalr.resize(bf, Method.AUTOMATIC, Mode.FIT_EXACT, getWidth(), getHeight(), Scalr.OP_ANTIALIAS); } else { tileImage = bf; } g2di.dispose(); Logger.trace(id + " Cp: " + xyToString()); } public BufferedImage getTileImage() { return tileImage; } /** * Render a tile image Always starts at (0,0) used the default width and height * * @param g2 the Graphic context */ public void drawName(Graphics2D g2) { } protected void drawCenterPoint(Graphics2D g2d) { drawCenterPoint(g2d, Color.magenta); } protected void drawCenterPoint(Graphics2D g2, Color color) { drawCenterPoint(g2, color, 60); } protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { double dX = (renderWidth / 2 - size / 2); double dY = (renderHeight / 2 - size / 2); g2d.setColor(color); g2d.fill(new Ellipse2D.Double(dX, dY, size, size)); } /** * Rotate the tile clockwise 90 deg * * @return the new Orientation */ public Orientation rotate() { Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case EAST -> setOrientation(Orientation.SOUTH); case SOUTH -> setOrientation(Orientation.WEST); case WEST -> setOrientation(Orientation.NORTH); default -> setOrientation(Orientation.EAST); } return model.getTileOrienation(); } public void flipHorizontal() { Orientation tileOrientation = model.getTileOrienation(); if (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) { rotate(); rotate(); } } public void flipVertical() { Orientation tileOrientation = model.getTileOrienation(); if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { rotate(); rotate(); } } @Override public void move(int newX, int newY) { Point cs = LayoutUtil.snapToGrid(newX, newY); setCenter(cs); } protected static void drawRotate(Graphics2D g2d, double x, double y, int angle, String text) { g2d.translate((float) x, (float) y); g2d.rotate(Math.toRadians(angle)); g2d.drawString(text, 0, 0); g2d.rotate(-Math.toRadians(angle)); g2d.translate(-x, -y); } public static BufferedImage flipHorizontally(BufferedImage source) { BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); AffineTransform flip = AffineTransform.getScaleInstance(1, -1); flip.translate(0, -source.getHeight()); AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); op.filter(source, output); return output; } public static BufferedImage flipVertically(BufferedImage source) { BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); AffineTransform flip = AffineTransform.getScaleInstance(-1, 1); flip.translate(-source.getWidth(), 0); AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); op.filter(source, output); return output; } public Set getAltPoints() { return Collections.EMPTY_SET; } public final int getOffsetX() { return offsetX; } public void setOffsetX(int offsetX) { this.offsetX = offsetX; } public final int getOffsetY() { return offsetY; } public void setOffsetY(int offsetY) { this.offsetY = offsetY; } protected BufferedImage createImage() { return new BufferedImage(renderWidth, renderHeight, BufferedImage.TYPE_INT_RGB); } public int getCenterX() { if (tileX > 0) { return this.tileX; } else { return GRID; } } public int getCenterY() { if (tileY > 0) { return this.tileY; } else { return GRID; } } public boolean isDrawName() { return drawName; } public void setDrawName(boolean drawName) { this.drawName = drawName; } public boolean isScaleImage() { return model.isScaleImage(); } public void setScaleImage(boolean scaleImage) { Dimension d; if (scaleImage) { d = new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); } else { d = new Dimension(renderWidth, renderHeight); } setSize(d); setPreferredSize(d); model.setScaleImage(scaleImage); } public boolean isDrawCenterPoint() { return model.isShowCenter(); } public void setDrawCenterPoint(boolean drawCenterPoint) { model.setShowCenter(drawCenterPoint); } @Override public String toString() { return this.getClass().getSimpleName() + " {id: " + this.id + ", orientation: " + getOrientation() + ", direction: " + getDirection() + ", center: " + xyToString() + "}"; } public String xyToString() { return "(" + this.tileX + "," + this.tileY + ")"; } /** * The main route of the tile is horizontal * * @return true when main route goes from East to West or vv */ public boolean isHorizontal() { Orientation tileOrientation = model.getTileOrienation(); return (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) && TileType.CURVED != tileType; } /** * The main route of the tile is vertical * * @return true when main route goes from North to South or vv */ public boolean isVertical() { Orientation tileOrientation = model.getTileOrienation(); return (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) && TileType.CURVED != tileType; } public boolean isJunction() { return TileType.SWITCH == tileType || TileType.CROSS == tileType; } public boolean isBlock() { return TileType.BLOCK == tileType; } public boolean isDirectional() { return TileType.STRAIGHT_DIR == tileType; } /** * The main route of the tile is diagonal * * @return true when main route goes from North to East or West to South and vv */ public boolean isDiagonal() { return TileType.CURVED == tileType; } public boolean isCrossing() { return TileType.CROSSING == tileType; } public List getNeighbours() { return neighbours; } public void setNeighbours(List neighbours) { this.neighbours = neighbours; } public String getIdSuffix(Tile other) { return ""; } public Map getNeighborOrientations() { Map edgeOrientations = new HashMap<>(); Map neighborPoints = getNeighborPoints(); for (Orientation o : Orientation.values()) { edgeOrientations.put(neighborPoints.get(o), o); } return edgeOrientations; } public Map getEdgeOrientations() { Map edgeOrientations = new HashMap<>(); Map edgeConnections = getEdgePoints(); for (Orientation o : Orientation.values()) { edgeOrientations.put(edgeConnections.get(o), o); } return edgeOrientations; } public boolean isAdjacent(Tile other) { boolean adjacent = false; if (other != null) { Collection thisEdgePoints = getEdgePoints().values(); Collection otherEdgePoints = other.getEdgePoints().values(); for (Point p : thisEdgePoints) { adjacent = otherEdgePoints.contains(p); if (adjacent) { break; } } } return adjacent; } /** * When the tile has a specific direction a train may travel,
* then this method will indicate whether the other tile is in on the side where the arrow is pointing to. * * @param other A Tile * @return true where other is on the side of this tile where the arrow points to */ public boolean isArrowDirection(Tile other) { return true; } public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { return AccessoryValue.OFF; } public TileModel getModel() { return model; } public void setModel(TileModel newModel) { TileModel oldModel = getModel(); if (oldModel != null) { oldModel.removeChangeListener(changeListener); oldModel.removeActionListener(actionListener); changeListener = null; actionListener = null; } model = newModel; if (newModel != null) { changeListener = createChangeListener(); actionListener = createActionListener(); newModel.addChangeListener(changeListener); newModel.addActionListener(actionListener); } firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel); if (newModel != oldModel) { revalidate(); repaint(); } } // public TileUI getUI() { // return (TileUI) ui; // } // public void setUI(TileUI ui) { // super.setUI(ui); // } @Override public void updateUI() { } protected ChangeListener createChangeListener() { return getHandler(); } protected ActionListener createActionListener() { return getHandler(); } private Handler getHandler() { if (handler == null) { handler = new Handler(); } return handler; } class Handler implements ActionListener, ChangeListener, Serializable { @Override public void stateChanged(ChangeEvent e) { //Object source = e.getSource(); fireStateChanged(); repaint(); } @Override public void actionPerformed(ActionEvent event) { fireActionPerformed(event); } } protected void fireStateChanged() { Object[] listeners = listenerList.getListenerList(); //reverse order for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == ChangeListener.class) { // Lazily create the event: if (changeEvent == null) { changeEvent = new ChangeEvent(this); } ((ChangeListener) listeners[i + 1]).stateChanged(changeEvent); } } } protected void fireActionPerformed(ActionEvent event) { Object[] listeners = listenerList.getListenerList(); ActionEvent e = null; // reverse for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == ActionListener.class) { // Lazily create the event: if (e == null) { String actionCommand = event.getActionCommand(); //if(actionCommand == null) { // actionCommand = getActionCommand(); //} e = new ActionEvent(Tile.this, ActionEvent.ACTION_PERFORMED, actionCommand, event.getWhen(), event.getModifiers()); } ((ActionListener) listeners[i + 1]).actionPerformed(e); } } } public Rectangle getTileBounds() { if (model.isScaleImage()) { return new Rectangle(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); } else { return new Rectangle(tileX - renderWidth / 2, tileY - renderHeight / 2, renderWidth, renderHeight); } } @Override protected void paintComponent(Graphics g) { long started = System.currentTimeMillis(); Graphics2D g2 = (Graphics2D) g.create(); //Graphics2D g2 = (Graphics2D) g.create(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); drawTile(g2); g2.dispose(); g.drawImage(tileImage, 0, 0, null); long now = System.currentTimeMillis(); Logger.trace(id + " Duration: " + (now - started) + " ms. Cp: " + xyToString() + " O: " + model.getTileOrienation()); } } \ No newline at end of file diff --git a/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.form b/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.form index 9b77fbc1..345a66d6 100644 --- a/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.form +++ b/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.form @@ -1,454 +1 @@ - - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
\ No newline at end of file diff --git a/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java b/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java index c5e311b7..f8881283 100644 --- a/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java +++ b/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java @@ -1,570 +1 @@ -/* - * Copyright 2024 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout.tiles; - -import java.awt.Color; -import java.awt.Point; -import javax.swing.ComboBoxModel; -import javax.swing.DefaultComboBoxModel; -import javax.swing.UIManager; -import javax.swing.UnsupportedLookAndFeelException; -import jcs.entities.AccessoryBean; -import jcs.entities.AccessoryBean.AccessoryValue; -import jcs.entities.TileBean; -import jcs.entities.TileBean.Direction; -import jcs.entities.TileBean.Orientation; -import static jcs.entities.TileBean.Orientation.NORTH; -import static jcs.entities.TileBean.Orientation.SOUTH; -import static jcs.entities.TileBean.Orientation.WEST; -import jcs.entities.TileBean.TileType; -import jcs.ui.layout.LayoutUtil; -import jcs.ui.layout.events.TileEvent; -import org.tinylog.Logger; - -public class TileTesterFrame extends javax.swing.JFrame { - - private Tile tile; - - public TileTesterFrame() { - initComponents(); - this.tileCB.setModel(createTileTypeComboBoxModel()); - this.orientationCB.setModel(createOrientationComboBoxModel()); - this.incomingSideCB.setModel(createOrientationComboBoxModel()); - this.directionCB.setModel(createDirectionComboBoxModel(true)); - - createTile(); - - pack(); - - setVisible(true); - } - - private ComboBoxModel createTileTypeComboBoxModel() { - DefaultComboBoxModel tileTypeModel = new DefaultComboBoxModel(); - - tileTypeModel.addElement(TileBean.TileType.STRAIGHT); - tileTypeModel.addElement(TileBean.TileType.STRAIGHT_DIR); - tileTypeModel.addElement(TileBean.TileType.SENSOR); - tileTypeModel.addElement(TileBean.TileType.SIGNAL); - tileTypeModel.addElement(TileBean.TileType.END); - tileTypeModel.addElement(TileBean.TileType.CROSSING); - tileTypeModel.addElement(TileBean.TileType.CURVED); - tileTypeModel.addElement(TileBean.TileType.SWITCH); - tileTypeModel.addElement(TileBean.TileType.CROSS); - - return tileTypeModel; - } - - private ComboBoxModel createOrientationComboBoxModel() { - DefaultComboBoxModel orientationModel = new DefaultComboBoxModel(); - - orientationModel.addElement(Orientation.EAST); - orientationModel.addElement(Orientation.SOUTH); - orientationModel.addElement(Orientation.WEST); - orientationModel.addElement(Orientation.NORTH); - - return orientationModel; - } - - private ComboBoxModel createDirectionComboBoxModel(boolean dontCare) { - DefaultComboBoxModel directionModel = new DefaultComboBoxModel(); - - if (dontCare) { - directionModel.addElement(Direction.CENTER); - } else { - directionModel.addElement(Direction.LEFT); - directionModel.addElement(Direction.RIGHT); - } - - return directionModel; - } - - private void createTile() { - if (tile != null) { - Logger.trace("Removing tile " + tile.getId()); - canvas.remove(tile); - tile = null; - } - - TileType tileType = (TileType) tileCB.getSelectedItem(); - Orientation orientation = (Orientation) orientationCB.getSelectedItem(); - - if (TileType.SWITCH == tileType || TileType.CROSS == tileType) { - directionCB.setModel(createDirectionComboBoxModel(false)); - } else { - directionCB.setModel(createDirectionComboBoxModel(true)); - } - - Direction direction = (Direction) this.directionCB.getSelectedItem(); - boolean scale = !scaleCB.isSelected(); - boolean showCenter = showCenterCB.isSelected(); - - int w = canvas.getWidth(); - int h = canvas.getHeight(); - - int x = w / 2; - int y = h / 2; - Point tileCenter = new Point(x, y); - tileCenter = LayoutUtil.snapToGrid(tileCenter); - -// if (TileType.CROSS == tileType) { -// switch (orientation) { -// case SOUTH -> { -// x = w / 2 + 200; -// y = h / 2 - 150; -// } -// case WEST -> { -// x = w / 2 + 400; -// y = h / 2 + 50; -// } -// case NORTH -> { -// x = w / 2 + 200; -// y = h / 2 + 250; -// } -// default -> { -// x = w / 2; -// y = h / 2 + 50; -// } -// } -// } else { -// x = w / 2 - 200; -// y = h / 2 - 200; -// } -// Point center; -// if (TileType.CROSS.equals(tileType)) { -// center = new Point(x - 200, y); -// } else { -// center = new Point(x, y); -// } - Tile newTile = TileFactory.createTile(tileType, orientation, direction, tileCenter); - newTile.setScaleImage(scale); - newTile.setDrawCenterPoint(showCenter); - - //tile.setPropertyChangeListener(this); - Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); - newTile.setIncomingSide(incomingSide); - - newTile.setDrawRoute(displayRouteCB.isSelected()); - newTile.setTrackRouteColor(Color.blue); - - Logger.trace("Adding tile " + newTile.getId() + " " + newTile.xyToString()); - - //this.cPanel.add((JComponent) newTile); - this.canvas.add(newTile); - this.tile = newTile; - } - - private AccessoryValue getAccessoryState() { - AccessoryValue value; - if (greenRB.isSelected()) { - value = AccessoryValue.GREEN; - } else if (redRB.isSelected()) { - value = AccessoryValue.RED; - - } else { - value = AccessoryValue.OFF; - } - return value; - } - - private void changeAccesoryState() { - if(tile instanceof Sensor) { - tile.setActive(this.redRB.isSelected()); - } - - if (tile instanceof Switch aSwitch) { - if (this.displayRouteCB.isSelected()) { - aSwitch.setRouteValue(getAccessoryState()); - } else { - aSwitch.setAccessoryValue(getAccessoryState()); - } - } - - if (tile instanceof Signal aSignal) { - if (this.greenRB.isSelected()) { - aSignal.setSignalValue(AccessoryBean.SignalValue.Hp1); - } else if (this.redRB.isSelected()) { - aSignal.setSignalValue(AccessoryBean.SignalValue.Hp0); - } else { - aSignal.setSignalValue(AccessoryBean.SignalValue.OFF); - } - } - - //this.tile.repaint(); - } - -// @Override -// public void propertyChange(PropertyChangeEvent evt) { -// if ("repaintTile".equals(evt.getPropertyName())) { -// Tile t = (Tile) evt.getNewValue(); -// Logger.trace("Tile: " + t); -// //this.repaint(); -// } -// } -// @Override -// public void paint(Graphics g) { -// super.paint(g); -// Graphics2D g2d = (Graphics2D) g; -// boolean outline = this.drawOutlineCB.isSelected(); -// boolean showRoute = this.displayRouteCB.isSelected(); -// tile.setDrawRoute(showRoute); -// -// tile.drawTile(g2d, outline); -// -// if (outline) { -// tile.drawBounds(g2d); -// tile.drawCenterPoint(g2d, Color.red); -// } -// } -// @Override -// public void paint(Graphics g) { -// long started = System.currentTimeMillis(); -// super.paint(g); -// -// long now = System.currentTimeMillis(); -// Logger.trace("Duration: " + (now - started) + " ms."); -// } - private void changeDirection() { - Direction direction = (Direction) this.directionCB.getSelectedItem(); - this.tile.setDirection(direction); - - //if (TileType.CROSS == tile.getTileType()) { - // ((Cross) tile).setWidthHeightAndOffsets(); - //} - //this.repaint(); - } - - private void rotateTile() { - Orientation newOrientation = tile.rotate(); - orientationCB.setSelectedItem(newOrientation); - -// if (TileType.CROSS == tile.getTileType()) { -// int x = tile.getCenterX(); -// int y = tile.getCenterY(); -// int w = tile.getWidth() * 10; -// int h = tile.getHeight() * 10; -// -// //calculate a new centerpoint for cross -// switch (tile.getOrientation()) { -// case SOUTH -> { -// x = x + w / 2; -// y = y - h / 4; -// } -// case WEST -> { -// x = x + w / 4; -// y = y + h / 2; -// } -// case NORTH -> { -// x = x - w / 2; -// y = y + h / 4; -// } -// default -> { -// x = x - w / 4; -// y = y - h / 2; -// } -// } -// tile.setCenter(new Point(x, y)); -// } - //this.canvas.repaint(this.tile.getTileBounds()); - //tile.repaint(); - } - - private void changeOrientation() { - Orientation orientation = (Orientation) this.orientationCB.getSelectedItem(); - tile.setOrientation(orientation); - - if (TileType.CROSS == tile.getTileType()) { - //((Cross) tile).setWidthHeightAndOffsets(); - - int x = tile.getCenterX(); - int y = tile.getCenterY(); - int w = tile.getWidth() * 10; - int h = tile.getHeight() * 10; - - //calculate a new centerpoint for cross - switch (tile.getOrientation()) { - case SOUTH -> { - x = x + w / 2; - y = y - h / 4; - } - case WEST -> { - x = x + w / 4; - y = y + h / 2; - } - case NORTH -> { - x = x - w / 2; - y = y + h / 4; - } - default -> { - x = x - w / 4; - y = y - h / 2; - } - } - tile.setCenter(new Point(x, y)); - } - - //this.repaint(); - } - - private void showRoute() { - - Logger.trace("Show route on tile " + tile.getId()); - - String tileId = tile.getId(); - Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); - - //TileEvent tileEvent; - if (tile.isJunction()) { - AccessoryValue routeState = getAccessoryState(); - //tileEvent = new TileEvent(tileId, true, incomingSide, routeState); - } else { - //tileEvent = new TileEvent(tileId, true, incomingSide); - } - //TileCache.fireTileEventListener(tileEvent); - - // ((JComponent) this.tile).repaint(); - tile.setDrawRoute(displayRouteCB.isSelected()); - //repaint(); - } - -// private void showOutline() { -// //repaint(); -// } - - private void changeIncomingSide() { - Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); - tile.setIncomingSide(incomingSide); - //this.repaint(); - } - - /** - * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. - */ - @SuppressWarnings("unchecked") - // //GEN-BEGIN:initComponents - private void initComponents() { - - accessoryBG = new javax.swing.ButtonGroup(); - nPanel = new javax.swing.JPanel(); - tileCB = new javax.swing.JComboBox<>(); - orientationCB = new javax.swing.JComboBox<>(); - inComingLbl = new javax.swing.JLabel(); - incomingSideCB = new javax.swing.JComboBox<>(); - directionCB = new javax.swing.JComboBox<>(); - rotateButton = new javax.swing.JButton(); - offRB = new javax.swing.JRadioButton(); - greenRB = new javax.swing.JRadioButton(); - redRB = new javax.swing.JRadioButton(); - displayRouteCB = new javax.swing.JCheckBox(); - scaleCB = new javax.swing.JCheckBox(); - showCenterCB = new javax.swing.JCheckBox(); - canvas = new jcs.ui.layout.tiles.DotGridCanvas(); - - setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); - - nPanel.setMinimumSize(new java.awt.Dimension(860, 36)); - nPanel.setPreferredSize(new java.awt.Dimension(1020, 36)); - java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); - flowLayout1.setAlignOnBaseline(true); - nPanel.setLayout(flowLayout1); - - tileCB.setPreferredSize(new java.awt.Dimension(150, 23)); - tileCB.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - tileCBActionPerformed(evt); - } - }); - nPanel.add(tileCB); - - orientationCB.setPreferredSize(new java.awt.Dimension(100, 23)); - orientationCB.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - orientationCBActionPerformed(evt); - } - }); - nPanel.add(orientationCB); - - inComingLbl.setText("Incoming Orientation"); - nPanel.add(inComingLbl); - - incomingSideCB.setPreferredSize(new java.awt.Dimension(100, 23)); - incomingSideCB.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - incomingSideCBActionPerformed(evt); - } - }); - nPanel.add(incomingSideCB); - - directionCB.setPreferredSize(new java.awt.Dimension(100, 23)); - directionCB.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - directionCBActionPerformed(evt); - } - }); - nPanel.add(directionCB); - - rotateButton.setText("Rotate"); - rotateButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - rotateButtonActionPerformed(evt); - } - }); - nPanel.add(rotateButton); - - accessoryBG.add(offRB); - offRB.setForeground(new java.awt.Color(153, 153, 153)); - offRB.setSelected(true); - offRB.setText("Off"); - offRB.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - offRBActionPerformed(evt); - } - }); - nPanel.add(offRB); - - accessoryBG.add(greenRB); - greenRB.setForeground(new java.awt.Color(102, 255, 0)); - greenRB.setText("Green"); - greenRB.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - greenRBActionPerformed(evt); - } - }); - nPanel.add(greenRB); - - accessoryBG.add(redRB); - redRB.setForeground(new java.awt.Color(255, 0, 51)); - redRB.setText("Red"); - redRB.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - redRBActionPerformed(evt); - } - }); - nPanel.add(redRB); - - displayRouteCB.setText("Route"); - displayRouteCB.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - displayRouteCBActionPerformed(evt); - } - }); - nPanel.add(displayRouteCB); - - scaleCB.setText("Scale"); - scaleCB.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - scaleCBActionPerformed(evt); - } - }); - nPanel.add(scaleCB); - - showCenterCB.setText("Center"); - showCenterCB.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - showCenterCBActionPerformed(evt); - } - }); - nPanel.add(showCenterCB); - - getContentPane().add(nPanel, java.awt.BorderLayout.NORTH); - - canvas.setPreferredSize(new java.awt.Dimension(600, 600)); - getContentPane().add(canvas, java.awt.BorderLayout.CENTER); - - pack(); - }// //GEN-END:initComponents - - private void rotateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rotateButtonActionPerformed - rotateTile(); - }//GEN-LAST:event_rotateButtonActionPerformed - - private void tileCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tileCBActionPerformed - createTile(); - }//GEN-LAST:event_tileCBActionPerformed - - private void orientationCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_orientationCBActionPerformed - changeOrientation(); - }//GEN-LAST:event_orientationCBActionPerformed - - private void directionCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_directionCBActionPerformed - changeDirection(); - }//GEN-LAST:event_directionCBActionPerformed - - private void offRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_offRBActionPerformed - changeAccesoryState(); - }//GEN-LAST:event_offRBActionPerformed - - private void greenRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_greenRBActionPerformed - changeAccesoryState(); - }//GEN-LAST:event_greenRBActionPerformed - - private void redRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_redRBActionPerformed - changeAccesoryState(); - }//GEN-LAST:event_redRBActionPerformed - - private void displayRouteCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_displayRouteCBActionPerformed - showRoute(); - }//GEN-LAST:event_displayRouteCBActionPerformed - - private void scaleCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_scaleCBActionPerformed - this.tile.setScaleImage(!this.scaleCB.isSelected()); - this.tile.setBounds(this.tile.getTileBounds()); - }//GEN-LAST:event_scaleCBActionPerformed - - private void incomingSideCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_incomingSideCBActionPerformed - changeIncomingSide(); - }//GEN-LAST:event_incomingSideCBActionPerformed - - private void showCenterCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showCenterCBActionPerformed - this.tile.setDrawCenterPoint(this.showCenterCB.isSelected()); - }//GEN-LAST:event_showCenterCBActionPerformed - - /** - * @param args the command line arguments - */ - public static void main(String args[]) { - try { - UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { - Logger.error(ex); - } - - /* Create and display the form */ - java.awt.EventQueue.invokeLater(() -> { - TileTesterFrame app = new TileTesterFrame(); - app.setTitle("Tile Tester"); - app.setLocationRelativeTo(null); - }); - } - - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.ButtonGroup accessoryBG; - private jcs.ui.layout.tiles.DotGridCanvas canvas; - private javax.swing.JComboBox directionCB; - private javax.swing.JCheckBox displayRouteCB; - private javax.swing.JRadioButton greenRB; - private javax.swing.JLabel inComingLbl; - private javax.swing.JComboBox incomingSideCB; - private javax.swing.JPanel nPanel; - private javax.swing.JRadioButton offRB; - private javax.swing.JComboBox orientationCB; - private javax.swing.JRadioButton redRB; - private javax.swing.JButton rotateButton; - private javax.swing.JCheckBox scaleCB; - private javax.swing.JCheckBox showCenterCB; - private javax.swing.JComboBox tileCB; - // End of variables declaration//GEN-END:variables -} +/* * Copyright 2024 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.Color; import java.awt.Point; import javax.swing.ComboBoxModel; import javax.swing.DefaultComboBoxModel; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.AccessoryValue; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; import jcs.ui.layout.LayoutUtil; import jcs.ui.layout.events.TileEvent; import org.tinylog.Logger; public class TileTesterFrame extends javax.swing.JFrame { private Tile tile; public TileTesterFrame() { initComponents(); this.tileCB.setModel(createTileTypeComboBoxModel()); this.orientationCB.setModel(createOrientationComboBoxModel()); this.incomingSideCB.setModel(createOrientationComboBoxModel()); this.directionCB.setModel(createDirectionComboBoxModel(true)); createTile(); pack(); setVisible(true); } private ComboBoxModel createTileTypeComboBoxModel() { DefaultComboBoxModel tileTypeModel = new DefaultComboBoxModel(); tileTypeModel.addElement(TileBean.TileType.STRAIGHT); tileTypeModel.addElement(TileBean.TileType.STRAIGHT_DIR); tileTypeModel.addElement(TileBean.TileType.SENSOR); tileTypeModel.addElement(TileBean.TileType.SIGNAL); tileTypeModel.addElement(TileBean.TileType.END); tileTypeModel.addElement(TileBean.TileType.CROSSING); tileTypeModel.addElement(TileBean.TileType.CURVED); tileTypeModel.addElement(TileBean.TileType.SWITCH); tileTypeModel.addElement(TileBean.TileType.CROSS); return tileTypeModel; } private ComboBoxModel createOrientationComboBoxModel() { DefaultComboBoxModel orientationModel = new DefaultComboBoxModel(); orientationModel.addElement(Orientation.EAST); orientationModel.addElement(Orientation.SOUTH); orientationModel.addElement(Orientation.WEST); orientationModel.addElement(Orientation.NORTH); return orientationModel; } private ComboBoxModel createDirectionComboBoxModel(boolean dontCare) { DefaultComboBoxModel directionModel = new DefaultComboBoxModel(); if (dontCare) { directionModel.addElement(Direction.CENTER); } else { directionModel.addElement(Direction.LEFT); directionModel.addElement(Direction.RIGHT); } return directionModel; } private void createTile() { if (tile != null) { Logger.trace("Removing tile " + tile.getId()); canvas.remove(tile); tile = null; } TileType tileType = (TileType) tileCB.getSelectedItem(); Orientation orientation = (Orientation) orientationCB.getSelectedItem(); if (TileType.SWITCH == tileType || TileType.CROSS == tileType) { directionCB.setModel(createDirectionComboBoxModel(false)); } else { directionCB.setModel(createDirectionComboBoxModel(true)); } Direction direction = (Direction) this.directionCB.getSelectedItem(); boolean scale = !scaleCB.isSelected(); boolean showCenter = showCenterCB.isSelected(); int w = canvas.getWidth(); int h = canvas.getHeight(); int x = w / 2; int y = h / 2; Point tileCenter = new Point(x, y); tileCenter = LayoutUtil.snapToGrid(tileCenter); // if (TileType.CROSS == tileType) { // switch (orientation) { // case SOUTH -> { // x = w / 2 + 200; // y = h / 2 - 150; // } // case WEST -> { // x = w / 2 + 400; // y = h / 2 + 50; // } // case NORTH -> { // x = w / 2 + 200; // y = h / 2 + 250; // } // default -> { // x = w / 2; // y = h / 2 + 50; // } // } // } else { // x = w / 2 - 200; // y = h / 2 - 200; // } // Point center; // if (TileType.CROSS.equals(tileType)) { // center = new Point(x - 200, y); // } else { // center = new Point(x, y); // } Tile newTile = TileFactory.createTile(tileType, orientation, direction, tileCenter); newTile.setScaleImage(scale); newTile.setDrawCenterPoint(showCenter); //tile.setPropertyChangeListener(this); Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); newTile.setIncomingSide(incomingSide); newTile.setDrawRoute(displayRouteCB.isSelected()); newTile.setTrackRouteColor(Color.blue); Logger.trace("Adding tile " + newTile.getId() + " " + newTile.xyToString()); //this.cPanel.add((JComponent) newTile); this.canvas.add(newTile); this.tile = newTile; } private AccessoryValue getAccessoryState() { AccessoryValue value; if (greenRB.isSelected()) { value = AccessoryValue.GREEN; } else if (redRB.isSelected()) { value = AccessoryValue.RED; } else { value = AccessoryValue.OFF; } return value; } private void changeAccesoryState() { if(tile instanceof Sensor) { tile.setActive(this.redRB.isSelected()); } if (tile instanceof Switch aSwitch) { if (this.displayRouteCB.isSelected()) { aSwitch.setRouteValue(getAccessoryState()); } else { aSwitch.setAccessoryValue(getAccessoryState()); } } if (tile instanceof Signal aSignal) { if (this.greenRB.isSelected()) { aSignal.setSignalValue(AccessoryBean.SignalValue.Hp1); } else if (this.redRB.isSelected()) { aSignal.setSignalValue(AccessoryBean.SignalValue.Hp0); } else { aSignal.setSignalValue(AccessoryBean.SignalValue.OFF); } } //this.tile.repaint(); } // @Override // public void propertyChange(PropertyChangeEvent evt) { // if ("repaintTile".equals(evt.getPropertyName())) { // Tile t = (Tile) evt.getNewValue(); // Logger.trace("Tile: " + t); // //this.repaint(); // } // } // @Override // public void paint(Graphics g) { // super.paint(g); // Graphics2D g2d = (Graphics2D) g; // boolean outline = this.drawOutlineCB.isSelected(); // boolean showRoute = this.displayRouteCB.isSelected(); // tile.setDrawRoute(showRoute); // // tile.drawTile(g2d, outline); // // if (outline) { // tile.drawBounds(g2d); // tile.drawCenterPoint(g2d, Color.red); // } // } // @Override // public void paint(Graphics g) { // long started = System.currentTimeMillis(); // super.paint(g); // // long now = System.currentTimeMillis(); // Logger.trace("Duration: " + (now - started) + " ms."); // } private void changeDirection() { Direction direction = (Direction) this.directionCB.getSelectedItem(); this.tile.setDirection(direction); //if (TileType.CROSS == tile.getTileType()) { // ((Cross) tile).setWidthHeightAndOffsets(); //} //this.repaint(); } private void rotateTile() { Orientation newOrientation = tile.rotate(); orientationCB.setSelectedItem(newOrientation); // if (TileType.CROSS == tile.getTileType()) { // int x = tile.getCenterX(); // int y = tile.getCenterY(); // int w = tile.getWidth() * 10; // int h = tile.getHeight() * 10; // // //calculate a new centerpoint for cross // switch (tile.getOrientation()) { // case SOUTH -> { // x = x + w / 2; // y = y - h / 4; // } // case WEST -> { // x = x + w / 4; // y = y + h / 2; // } // case NORTH -> { // x = x - w / 2; // y = y + h / 4; // } // default -> { // x = x - w / 4; // y = y - h / 2; // } // } // tile.setCenter(new Point(x, y)); // } //this.canvas.repaint(this.tile.getTileBounds()); //tile.repaint(); } private void changeOrientation() { Orientation orientation = (Orientation) this.orientationCB.getSelectedItem(); tile.setOrientation(orientation); // if (TileType.CROSS == tile.getTileType()) { // //((Cross) tile).setWidthHeightAndOffsets(); // // int x = tile.getCenterX(); // int y = tile.getCenterY(); // int w = tile.getWidth() * 10; // int h = tile.getHeight() * 10; // // //calculate a new centerpoint for cross // switch (tile.getOrientation()) { // case SOUTH -> { // x = x + w / 2; // y = y - h / 4; // } // case WEST -> { // x = x + w / 4; // y = y + h / 2; // } // case NORTH -> { // x = x - w / 2; // y = y + h / 4; // } // default -> { // x = x - w / 4; // y = y - h / 2; // } // } // tile.setCenter(new Point(x, y)); // } //this.repaint(); } private void showRoute() { Logger.trace("Show route on tile " + tile.getId()); String tileId = tile.getId(); Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); //TileEvent tileEvent; if (tile.isJunction()) { AccessoryValue routeState = getAccessoryState(); //tileEvent = new TileEvent(tileId, true, incomingSide, routeState); } else { //tileEvent = new TileEvent(tileId, true, incomingSide); } //TileCache.fireTileEventListener(tileEvent); // ((JComponent) this.tile).repaint(); tile.setDrawRoute(displayRouteCB.isSelected()); //repaint(); } // private void showOutline() { // //repaint(); // } private void changeIncomingSide() { Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); tile.setIncomingSide(incomingSide); //this.repaint(); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { accessoryBG = new javax.swing.ButtonGroup(); nPanel = new javax.swing.JPanel(); tileCB = new javax.swing.JComboBox<>(); orientationCB = new javax.swing.JComboBox<>(); inComingLbl = new javax.swing.JLabel(); incomingSideCB = new javax.swing.JComboBox<>(); directionCB = new javax.swing.JComboBox<>(); rotateButton = new javax.swing.JButton(); offRB = new javax.swing.JRadioButton(); greenRB = new javax.swing.JRadioButton(); redRB = new javax.swing.JRadioButton(); displayRouteCB = new javax.swing.JCheckBox(); scaleCB = new javax.swing.JCheckBox(); showCenterCB = new javax.swing.JCheckBox(); canvas = new jcs.ui.layout.tiles.DotGridCanvas(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); nPanel.setMinimumSize(new java.awt.Dimension(860, 36)); nPanel.setPreferredSize(new java.awt.Dimension(1020, 36)); java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); flowLayout1.setAlignOnBaseline(true); nPanel.setLayout(flowLayout1); tileCB.setPreferredSize(new java.awt.Dimension(150, 23)); tileCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { tileCBActionPerformed(evt); } }); nPanel.add(tileCB); orientationCB.setPreferredSize(new java.awt.Dimension(100, 23)); orientationCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { orientationCBActionPerformed(evt); } }); nPanel.add(orientationCB); inComingLbl.setText("Incoming Orientation"); nPanel.add(inComingLbl); incomingSideCB.setPreferredSize(new java.awt.Dimension(100, 23)); incomingSideCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { incomingSideCBActionPerformed(evt); } }); nPanel.add(incomingSideCB); directionCB.setPreferredSize(new java.awt.Dimension(100, 23)); directionCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { directionCBActionPerformed(evt); } }); nPanel.add(directionCB); rotateButton.setText("Rotate"); rotateButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { rotateButtonActionPerformed(evt); } }); nPanel.add(rotateButton); accessoryBG.add(offRB); offRB.setForeground(new java.awt.Color(153, 153, 153)); offRB.setSelected(true); offRB.setText("Off"); offRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { offRBActionPerformed(evt); } }); nPanel.add(offRB); accessoryBG.add(greenRB); greenRB.setForeground(new java.awt.Color(102, 255, 0)); greenRB.setText("Green"); greenRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { greenRBActionPerformed(evt); } }); nPanel.add(greenRB); accessoryBG.add(redRB); redRB.setForeground(new java.awt.Color(255, 0, 51)); redRB.setText("Red"); redRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { redRBActionPerformed(evt); } }); nPanel.add(redRB); displayRouteCB.setText("Route"); displayRouteCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { displayRouteCBActionPerformed(evt); } }); nPanel.add(displayRouteCB); scaleCB.setText("Scale"); scaleCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { scaleCBActionPerformed(evt); } }); nPanel.add(scaleCB); showCenterCB.setText("Center"); showCenterCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { showCenterCBActionPerformed(evt); } }); nPanel.add(showCenterCB); getContentPane().add(nPanel, java.awt.BorderLayout.NORTH); canvas.setPreferredSize(new java.awt.Dimension(600, 600)); getContentPane().add(canvas, java.awt.BorderLayout.CENTER); pack(); }// //GEN-END:initComponents private void rotateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rotateButtonActionPerformed rotateTile(); }//GEN-LAST:event_rotateButtonActionPerformed private void tileCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tileCBActionPerformed createTile(); }//GEN-LAST:event_tileCBActionPerformed private void orientationCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_orientationCBActionPerformed changeOrientation(); }//GEN-LAST:event_orientationCBActionPerformed private void directionCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_directionCBActionPerformed changeDirection(); }//GEN-LAST:event_directionCBActionPerformed private void offRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_offRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_offRBActionPerformed private void greenRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_greenRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_greenRBActionPerformed private void redRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_redRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_redRBActionPerformed private void displayRouteCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_displayRouteCBActionPerformed showRoute(); }//GEN-LAST:event_displayRouteCBActionPerformed private void scaleCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_scaleCBActionPerformed this.tile.setScaleImage(!this.scaleCB.isSelected()); this.tile.setBounds(this.tile.getTileBounds()); }//GEN-LAST:event_scaleCBActionPerformed private void incomingSideCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_incomingSideCBActionPerformed changeIncomingSide(); }//GEN-LAST:event_incomingSideCBActionPerformed private void showCenterCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showCenterCBActionPerformed this.tile.setDrawCenterPoint(this.showCenterCB.isSelected()); }//GEN-LAST:event_showCenterCBActionPerformed /** * @param args the command line arguments */ public static void main(String args[]) { try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { Logger.error(ex); } /* Create and display the form */ java.awt.EventQueue.invokeLater(() -> { TileTesterFrame app = new TileTesterFrame(); app.setTitle("Tile Tester"); app.setLocationRelativeTo(null); }); } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.ButtonGroup accessoryBG; private jcs.ui.layout.tiles.DotGridCanvas canvas; private javax.swing.JComboBox directionCB; private javax.swing.JCheckBox displayRouteCB; private javax.swing.JRadioButton greenRB; private javax.swing.JLabel inComingLbl; private javax.swing.JComboBox incomingSideCB; private javax.swing.JPanel nPanel; private javax.swing.JRadioButton offRB; private javax.swing.JComboBox orientationCB; private javax.swing.JRadioButton redRB; private javax.swing.JButton rotateButton; private javax.swing.JCheckBox scaleCB; private javax.swing.JCheckBox showCenterCB; private javax.swing.JComboBox tileCB; // End of variables declaration//GEN-END:variables } \ No newline at end of file From 7b2ca1db8f1028b01a13723a3ac1562941e84211 Mon Sep 17 00:00:00 2001 From: Frans Jacobs <41232225+fransjacobs@users.noreply.github.com> Date: Tue, 28 Jan 2025 18:14:26 +0100 Subject: [PATCH 10/70] Tiles can be moved, extra check is needed for Block and Cross WIP --- src/main/java/jcs/ui/layout/LayoutCanvas.java | 308 ++--- src/main/java/jcs/ui/layout/TileCache.java | 101 +- src/main/java/jcs/ui/layout/tiles/Cross.java | 669 +++++++++- .../jcs/ui/layout/tiles/DefaultTileModel.java | 22 + src/main/java/jcs/ui/layout/tiles/Tile.java | 1134 ++++++++++++++++- .../java/jcs/ui/layout/tiles/TileFactory.java | 1 - .../java/jcs/ui/layout/tiles/TileModel.java | 5 + 7 files changed, 2007 insertions(+), 233 deletions(-) diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.java b/src/main/java/jcs/ui/layout/LayoutCanvas.java index 5ba67e08..fb3813da 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.java +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.java @@ -29,8 +29,6 @@ import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; -import java.awt.image.BufferedImage; -import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.ExecutorService; @@ -103,19 +101,14 @@ public enum Mode { private Point mouseLocation = new Point(); - //private BufferedImage grid; private final ExecutorService executor; - private final Set selectedTiles; - private Tile selectedTile; private RoutesDialog routesDialog; //private final Map selectedRouteElements; - private Point movingTileCenterPoint; - private BufferedImage movingTileImage; - + //private Point mousePressedPoint; public LayoutCanvas() { this(false); } @@ -127,12 +120,7 @@ public LayoutCanvas(boolean readonly) { setDoubleBuffered(true); this.readonly = readonly; -// this.tiles = new HashMap<>(); -// this.altTiles = new HashMap<>(); - - this.selectedTiles = new HashSet<>(); // this.selectedRouteElements = new HashMap<>(); - this.executor = Executors.newSingleThreadExecutor(); //this.executor = Executors.newCachedThreadPool(); @@ -166,14 +154,6 @@ public void paint(Graphics g) { Logger.trace("Duration: " + (now - started) + " ms."); } -// @Override -// protected void paintComponent(Graphics g) { -// long started = System.currentTimeMillis(); -// super.paintComponent(g); -// long now = System.currentTimeMillis(); -// Logger.trace("Duration: " + (now - started) + " ms."); -// } - @Override public Component add(Component component) { super.add(component); @@ -264,14 +244,14 @@ void loadLayoutInBackground() { } private void loadTiles() { - //boolean showValues = Mode.CONTROL.equals(mode); TileCache.loadTiles(); + removeAll(); + + selectedTile = null; - selectedTiles.clear(); for (Tile tile : TileCache.tiles.values()) { - this.add(tile); + add(tile); tile.setDrawCenterPoint(!readonly); - //tile.setBounds(tile.getTileBounds()); } repaint(); @@ -279,101 +259,77 @@ private void loadTiles() { private void mouseMoveAction(MouseEvent evt) { Point sp = LayoutUtil.snapToGrid(evt.getPoint()); - Tile tile = TileCache.findTile(sp); - if (tile != null) { + if (selectedTile != null) { setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)); } else { setCursor(Cursor.getDefaultCursor()); } } - private Tile getSelectedTile() { - Tile t = null; - if (!selectedTiles.isEmpty()) { - for (Point p : this.selectedTiles) { - //t = tiles.get(p); - t = TileCache.tiles.get(p); - if (t != null) { - return t; - } - } - } - return t; - } - private void mousePressedAction(MouseEvent evt) { Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); - //Clear any previous selection - for (Point p : selectedTiles) { - if (TileCache.containsPoint(p)) { - Tile st = TileCache.findTile(p); - st.setSelected(false); - } + Tile previousSelected = this.selectedTile; + selectedTile = TileCache.findTile(snapPoint); + if (selectedTile != null) { + selectedTile.setSelected(true); } - selectedTiles.clear(); - Tile tile = TileCache.findTile(snapPoint); - - if (tile != null) { - selectedTiles.addAll(tile.getAllPoints()); - tile.setSelected(true); - selectedTile = tile; + if (previousSelected != null && selectedTile != null && previousSelected.getId().equals(selectedTile.getId())) { + Logger.trace("Same tile " + selectedTile.getId() + " selected"); + } else if (previousSelected != null) { + previousSelected.setSelected(false); } switch (mode) { case CONTROL -> { - if (tile != null) { + if (selectedTile != null) { if (evt.getButton() == MouseEvent.BUTTON1) { - executeControlActionForTile(tile, snapPoint); + executeControlActionForTile(selectedTile, snapPoint); } else { - if (tile.isBlock()) { - showBlockPopupMenu(tile, snapPoint); + if (selectedTile.isBlock()) { + showBlockPopupMenu(selectedTile, snapPoint); } } } } case ADD -> { - if (MouseEvent.BUTTON1 == evt.getButton() && tile == null) { + if (MouseEvent.BUTTON1 == evt.getButton() && selectedTile == null) { //Only add a new tile when there is no tile on the selected snapPoint Logger.trace("Adding a new tile: " + tileType + " @ (" + snapPoint.x + ", " + snapPoint.y + ")"); - Tile addedTile = addTile(snapPoint, tileType, orientation, direction, true, !readonly); - if (addedTile != null) { - selectedTiles.addAll(addedTile.getAllPoints()); - repaint(addedTile.getTileBounds()); + selectedTile = addTile(snapPoint, tileType, orientation, direction, true, !readonly); + if (selectedTile != null) { + //selectedTiles.addAll(selectedTile.getAllPoints()); + selectedTile.setSelected(true); + repaint(selectedTile.getTileBounds()); } } else { - if (tile != null) { - Logger.debug("A tile exists at the selected position: " + tile.getTileType() + " @ (" + snapPoint.x + ", " + snapPoint.y + ") id: " + tile.getId()); + if (selectedTile != null) { + Logger.debug("A tile exists at the selected position: " + selectedTile.getTileType() + " @ (" + snapPoint.x + ", " + snapPoint.y + ") id: " + selectedTile.getId()); } else { Logger.warn("Found something (" + snapPoint.x + ", " + snapPoint.y + ")"); } } - if (MouseEvent.BUTTON3 == evt.getButton() && tile != null) { - showOperationsPopupMenu(tile, snapPoint); + if (MouseEvent.BUTTON3 == evt.getButton() && selectedTile != null) { + showOperationsPopupMenu(selectedTile, snapPoint); } } case DELETE -> { Tile toBeDeleted = (Tile) getComponentAt(snapPoint); if (toBeDeleted != null) { removeTile(toBeDeleted); - selectedTiles.clear(); + //selectedTiles.clear(); repaint(toBeDeleted.getTileBounds()); selectedTile = null; } } default -> { - Logger.trace((tile != null ? "Selected tile: " + tile.getId() + ", " + tile.xyToString() : "No tile selected")); - //if (tile == null) { - // this.selectedTiles.clear(); - //} - + Logger.trace((selectedTile != null ? "Selected tile: " + selectedTile.getId() + ", " + selectedTile.xyToString() : "No tile selected")); if (MouseEvent.BUTTON3 == evt.getButton()) { - showOperationsPopupMenu(tile, snapPoint); + showOperationsPopupMenu(selectedTile, snapPoint); } } } - } private Tile addTile(Point p, TileType tileType, Orientation orientation, Direction direction, boolean selected, boolean showCenter) { @@ -389,8 +345,6 @@ private Tile addTile(Point p, TileType tileType, Orientation orientation, Direct if (canBeAdded) { add(tile); - //tile.setBounds(tile.getTileBounds()); - TileCache.addAndSaveTile(tile); return tile; } else { @@ -409,89 +363,107 @@ void removeTile(Tile tile) { private void mouseDragAction(MouseEvent evt) { Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); - Tile selTile = getSelectedTile(); - if (selTile != null) { - movingTileImage = selTile.getTileImage(); - movingTileCenterPoint = snapPoint; - } else { - movingTileImage = null; - movingTileCenterPoint = null; + + if (selectedTile != null) { + int z = getComponentZOrder(selectedTile); + Logger.trace("Moving Tile: " + selectedTile.getId() + " Z: " + z + " @ " + selectedTile.xyToString()); + + //Put on Top + setComponentZOrder(selectedTile, 0); + int curX = snapPoint.x - Tile.GRID; + int curY = snapPoint.y - Tile.GRID; + + //check overlap in the cache + //This wil only chek the snappint, whic incas of a moving Block or Cross in not enough! + //TODO ! Needed are the alt point of the moved block or Cross. + //How to do this? + if (TileCache.containsPoint(snapPoint)) { + selectedTile.setSelectedColor(Tile.DEFAULT_WARN_COLOR); + } else { + selectedTile.setSelectedColor(Tile.DEFAULT_SELECTED_COLOR); + } + + selectedTile.setBounds(curX, curY, selectedTile.getWidth(), selectedTile.getHeight()); } - repaint(); } private void mouseReleasedAction(MouseEvent evt) { - Tile selTile = getSelectedTile(); - if (selTile != null) { - Logger.trace("Selected tile: " + selTile.getId() + ", " + selTile.xyToString()); - } - Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); - if (!LayoutCanvas.Mode.CONTROL.equals(mode) && MouseEvent.BUTTON1 == evt.getButton() && selTile != null) { - Point tp = selTile.getCenter(); - if (!tp.equals(snapPoint)) { - Logger.tag("Moving Tile from " + tp + " to " + snapPoint + " Tile to move: " + selTile); - //Check if new position is free - boolean canMove = true; - //if (tiles.containsKey(snapPoint) || altTiles.containsKey(snapPoint)) { - if (TileCache.containsPoint(snapPoint)) { - Tile tile = TileCache.findTile(snapPoint); - if (selTile.getId().equals(tile.getId())) { - //same tile so we can move - canMove = true; - } else { - Logger.debug("Position " + snapPoint + " is occupied with tile: " + tile + ", can't move tile " + selTile.getId()); - canMove = false; - } - } + boolean snapPointOccupied = TileCache.containsPoint(snapPoint); + if (!Mode.CONTROL.equals(mode) && MouseEvent.BUTTON1 == evt.getButton() && selectedTile != null) { + + boolean destinationOccupied = TileCache.containsPoints(selectedTile.getAllPoints()); - if (canMove) { - //Remove the original tile center from the tiles - Tile movingTile = TileCache.tiles.remove(tp); - if (movingTile != null) { - //Also remove from the alt points - Point oldCenter = movingTile.getCenter(); - Set oldAltPoints = movingTile.getAltPoints(); - //Logger.trace("Removing " + oldAltPoints.size() + " alt tile points"); - for (Point ep : oldAltPoints) { - TileCache.altTiles.remove(ep); - TileCache.tiles.remove(ep); - } + + Logger.trace("Selected tile: " + selectedTile.getId() + ", " + selectedTile.xyToString()+" Dest Occ "+destinationOccupied); - //Set the new center position - movingTile.setCenter(snapPoint); - //Check again, needed for tiles which are longer then 1 square, like a block - if (!TileCache.checkTileOccupation(movingTile)) { - Logger.trace("Moved Tile " + movingTile.getId() + " from " + tp + " to " + snapPoint + "..."); - TileCache.tiles.put(snapPoint, movingTile); - for (Point ep : movingTile.getAltPoints()) { - TileCache.altTiles.put(ep, movingTile); - } - selectedTiles.clear(); - selectedTiles.addAll(movingTile.getAllPoints()); - } else { - //Do not move Tile, put back where it was - movingTile.setCenter(oldCenter); - TileCache.tiles.put(oldCenter, movingTile); - for (Point ep : movingTile.getAltPoints()) { - TileCache.altTiles.put(ep, movingTile); - } - } + if (destinationOccupied || snapPointOccupied) { + Logger.debug("Can't move tile " + selectedTile.getId() + " from " + selectedTile.xyToString() + " to (" + snapPoint.x + "," + snapPoint.y + ")!"); - //if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { - //this.saveTile(movingTile); - TileCache.saveTile(movingTile); - //} - } - repaint(); - } + //selectedTile.setBounds(selectedTile.getTileX(), selectedTile.getTileY(), selectedTile.getWidth(), selectedTile.getHeight()); + selectedTile.setBounds(selectedTile.getTileBounds()); + selectedTile.setSelectedColor(Tile.DEFAULT_SELECTED_COLOR); + + } else { + TileCache.moveTile(snapPoint, selectedTile); } - } - movingTileImage = null; - movingTileCenterPoint = null; - //repaint(); +// Point tp = selectedTile.getCenter(); +// if (!tp.equals(snapPoint)) { +// +// Logger.tag("Moving Tile from " + tp + " to " + snapPoint + " Tile to move: " + selectedTile); +// //Check if new position is free +// boolean canMove = true; +// if (TileCache.containsPoint(snapPoint)) { +// Tile tile = TileCache.findTile(snapPoint); +// if (selectedTile.getId().equals(tile.getId())) { +// //same tile so we can move +// canMove = true; +// } else { +// Logger.debug("Position " + snapPoint + " is occupied with tile: " + tile + ", can't move tile " + selectedTile.getId()); +// canMove = false; +// } +// } +// +// if (canMove) { +// //Remove the original tile center from the tiles +// Tile movingTile = TileCache.tiles.remove(tp); +// if (movingTile != null) { +// //Also remove from the alt points +// Point oldCenter = movingTile.getCenter(); +// Set oldAltPoints = movingTile.getAltPoints(); +// //Logger.trace("Removing " + oldAltPoints.size() + " alt tile points"); +// for (Point ep : oldAltPoints) { +// TileCache.altTiles.remove(ep); +// TileCache.tiles.remove(ep); +// } +// +// //Set the new center position +// movingTile.setCenter(snapPoint); +// //Check again, needed for tiles which are longer then 1 square, like a block +// if (!TileCache.checkTileOccupation(movingTile)) { +// Logger.trace("Moved Tile " + movingTile.getId() + " from " + tp + " to " + snapPoint + "..."); +// TileCache.tiles.put(snapPoint, movingTile); +// for (Point ep : movingTile.getAltPoints()) { +// TileCache.altTiles.put(ep, movingTile); +// } +// } else { +// //Do not move Tile, put back where it was +// movingTile.setCenter(oldCenter); +// TileCache.tiles.put(oldCenter, movingTile); +// for (Point ep : movingTile.getAltPoints()) { +// TileCache.altTiles.put(ep, movingTile); +// } +// } +// +// TileCache.saveTile(movingTile); +// } +// //TODO is this needed? + // repaint(); + // } + // } + } } private void executeControlActionForTile(Tile tile, Point p) { @@ -510,8 +482,6 @@ private void executeControlActionForTile(Tile tile, Point p) { Block block = (Block) tile; BlockControlDialog bcd = new BlockControlDialog(getParentFrame(), block); bcd.setVisible(true); - - //this.repaint(block.getX(), block.getY(), block.getWidth(), block.getHeight()); } case SIGNAL -> this.executor.execute(() -> toggleSignal((Signal) tile)); @@ -532,7 +502,6 @@ private void toggleSwitch(Switch turnout) { turnout.setAccessoryValue(ab.getAccessoryValue()); JCS.getJcsCommandStation().switchAccessory(ab, ab.getAccessoryValue()); - //repaint(turnout.getX(), turnout.getY(), turnout.getWidth(), turnout.getHeight()); } else { Logger.trace("No AccessoryBean configured for Turnout: " + turnout.getId()); } @@ -545,7 +514,6 @@ private void toggleSignal(Signal signal) { Logger.trace("A: " + ab.getAddress() + " S: " + ab.getStates() + " P: " + ab.getState()); JCS.getJcsCommandStation().switchAccessory(ab, ab.getAccessoryValue()); - //repaint(signal.getX(), signal.getY(), signal.getWidth(), signal.getHeight()); } else { Logger.trace("No AccessoryBean configured for Signal: " + signal.getId()); } @@ -557,7 +525,6 @@ private void toggleSensor(Sensor sensor) { sb.toggle(); sensor.setActive((sb.getStatus() == 1)); Logger.trace("id: " + sb.getId() + " state " + sb.getStatus()); - //sensor.repaintTile(); SensorEvent sensorEvent = new SensorEvent(sb); fireFeedbackEvent(sensorEvent); } @@ -578,12 +545,9 @@ private void editSelectedTileProperties() { boolean showMove = false; boolean showDelete = false; - if (!this.selectedTiles.isEmpty()) { - Point tcp = this.selectedTiles.iterator().next(); - Tile tile = TileCache.findTile(tcp); - TileBean.TileType tt = tile.getTileType(); - - Logger.trace("Seleted tile " + tile.getId() + " TileType " + tt); + if (selectedTile != null) { + TileBean.TileType tt = selectedTile.getTileType(); + Logger.trace("Selected tile " + selectedTile.getId() + " TileType " + tt); switch (tt) { case END -> { @@ -603,24 +567,24 @@ private void editSelectedTileProperties() { showDelete = true; } case SENSOR -> { - SensorDialog fbd = new SensorDialog(getParentFrame(), (Sensor) tile); + SensorDialog fbd = new SensorDialog(getParentFrame(), (Sensor) selectedTile); fbd.setVisible(true); } case SIGNAL -> { - SignalDialog sd = new SignalDialog(getParentFrame(), (Signal) tile); + SignalDialog sd = new SignalDialog(getParentFrame(), (Signal) selectedTile); sd.setVisible(true); } case SWITCH -> { - SwitchDialog td = new SwitchDialog(getParentFrame(), (Switch) tile); + SwitchDialog td = new SwitchDialog(getParentFrame(), (Switch) selectedTile); td.setVisible(true); } case CROSS -> { - SwitchDialog td = new SwitchDialog(getParentFrame(), (Switch) tile); + SwitchDialog td = new SwitchDialog(getParentFrame(), (Switch) selectedTile); td.setVisible(true); } case BLOCK -> { - Logger.trace("Show BlockDialog for " + tile.getId()); - BlockDialog bd = new BlockDialog(getParentFrame(), (Block) tile, this); + Logger.trace("Show BlockDialog for " + selectedTile.getId()); + BlockDialog bd = new BlockDialog(getParentFrame(), (Block) selectedTile, this); bd.setVisible(true); } default -> { @@ -734,21 +698,16 @@ public void rotateSelectedTile() { Logger.trace("Selected Tile " + selectedTile.getId()); selectedTile = TileCache.rotateTile(selectedTile); selectedTile.setBounds(selectedTile.getTileBounds()); - //selectedTile.repaint(); - - repaint(selectedTile.getTileBounds()); } public void flipSelectedTileHorizontal() { selectedTile = TileCache.flipHorizontal(selectedTile); selectedTile.setBounds(selectedTile.getTileBounds()); - selectedTile.repaint(); } public void flipSelectedTileVertical() { selectedTile = TileCache.flipVertical(selectedTile); selectedTile.setBounds(selectedTile.getTileBounds()); - selectedTile.repaint(); } void routeLayout() { @@ -758,8 +717,6 @@ void routeLayout() { private void routeLayoutWithAStar() { //Make sure the layout is saved TileCache.saveTiles(); -// Set snapshot = new HashSet<>(tiles.values()); -// this.saveTiles(snapshot); AStar astar = new AStar(); astar.buildGraph(TileCache.getTiles()); @@ -1052,7 +1009,6 @@ private void moveMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_moveMIAct private void deleteMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_deleteMIActionPerformed if (selectedTile != null) { removeTile(selectedTile); - selectedTiles.clear(); repaint(selectedTile.getTileBounds()); selectedTile = null; } @@ -1140,7 +1096,6 @@ private void reverseArrivalSideMIActionPerformed(ActionEvent evt) {//GEN-FIRST:e block.getBlockBean().setReverseArrival(!block.getBlockBean().isReverseArrival()); this.executor.execute(() -> { PersistenceFactory.getService().persist(block.getBlockBean()); - //block.repaintTile(); }); } }//GEN-LAST:event_reverseArrivalSideMIActionPerformed @@ -1161,7 +1116,6 @@ private void toggleLocomotiveDirectionMIActionPerformed(ActionEvent evt) {//GEN- this.executor.execute(() -> { PersistenceFactory.getService().persist(block.getTileBean()); - //block.repaintTile(); }); } }//GEN-LAST:event_toggleLocomotiveDirectionMIActionPerformed @@ -1179,7 +1133,6 @@ private void toggleOutOfOrderMIActionPerformed(ActionEvent evt) {//GEN-FIRST:eve if (currentState != block.getBlockState()) { //getRouteBlockState()) { this.executor.execute(() -> { PersistenceFactory.getService().persist(block.getBlockBean()); - //block.repaintTile(); }); } @@ -1198,7 +1151,6 @@ private void resetGhostMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_res } this.executor.execute(() -> { PersistenceFactory.getService().persist(block.getBlockBean()); - //block.repaintTile(); }); } } diff --git a/src/main/java/jcs/ui/layout/TileCache.java b/src/main/java/jcs/ui/layout/TileCache.java index 361bb354..c44f5909 100644 --- a/src/main/java/jcs/ui/layout/TileCache.java +++ b/src/main/java/jcs/ui/layout/TileCache.java @@ -54,16 +54,15 @@ public class TileCache { private TileCache() { } - static void setDrawCenterPoint(boolean drawCenterPoint) { - TileCache.drawCenterPoint = drawCenterPoint; - - for (Tile tile : tiles.values()) { - //if (tile instanceof AbstractTile abstractTile) { - tile.setDrawCenterPoint(drawCenterPoint); - //} - } - } - +// static void setDrawCenterPoint(boolean drawCenterPoint) { +// TileCache.drawCenterPoint = drawCenterPoint; +// +// for (Tile tile : tiles.values()) { +// //if (tile instanceof AbstractTile abstractTile) { +// tile.setDrawCenterPoint(drawCenterPoint); +// //} +// } +// } public static void setShowValues(boolean showValues) { TileCache.showValues = showValues; @@ -225,6 +224,14 @@ static boolean checkTileOccupation(Tile tile) { return false; } + static boolean containsPoints(Set points) { + for (Point p : points) { + return tiles.containsKey(p) || altTiles.containsKey(p); + } + return false; + + } + static boolean containsPoint(Point point) { return tiles.containsKey(point) || altTiles.containsKey(point); } @@ -322,54 +329,44 @@ static void moveTile(Point snapPoint, Tile tile) { Point tp = tile.getCenter(); if (!tp.equals(snapPoint)) { //Check if new position is free - boolean canMove = true; - if (tiles.containsKey(snapPoint) || altTiles.containsKey(snapPoint)) { - Tile t = findTile(snapPoint); - if (tile.getId().equals(t.getId())) { - //same tile so we can move - canMove = true; - } else { - Logger.trace("Position " + snapPoint + " is occupied with tile: " + t + ", can't move tile " + tile.getId()); - canMove = false; - } - - if (canMove) { - //Remove the original tile center from the tiles - Tile movingTile = tiles.remove(tp); - if (movingTile != null) { - //Also remove from the alt points - Point oldCenter = movingTile.getCenter(); - Set oldAltPoints = movingTile.getAltPoints(); - //Logger.trace("Removing " + oldAltPoints.size() + " alt tile points"); - for (Point ep : oldAltPoints) { - altTiles.remove(ep); - tiles.remove(ep); - } + boolean canMove = !TileCache.containsPoint(snapPoint); + + if (canMove) { + Logger.trace("Moving from tile " + tile.getId() + " from " + tile.xyToString() + " to (" + snapPoint.x + "," + snapPoint.y + ")"); + //Remove the original tile center from the tiles + Tile movingTile = tiles.remove(tp); + if (movingTile != null) { + //Also remove from the alt points + Point oldCenter = movingTile.getCenter(); + Set oldAltPoints = movingTile.getAltPoints(); + //Logger.trace("Removing " + oldAltPoints.size() + " alt tile points"); + for (Point ep : oldAltPoints) { + altTiles.remove(ep); + tiles.remove(ep); + } - //Set the new center position - movingTile.setCenter(snapPoint); - //Check again, needed for tiles which are longer then 1 square, like a block - if (!checkTileOccupation(movingTile)) { - Logger.trace("Moved Tile " + movingTile.getId() + " from " + tp + " to " + snapPoint + "..."); - tiles.put(snapPoint, movingTile); - for (Point ep : movingTile.getAltPoints()) { - altTiles.put(ep, movingTile); - } - } else { - //Do not move Tile, put back where it was - movingTile.setCenter(oldCenter); - tiles.put(oldCenter, movingTile); - for (Point ep : movingTile.getAltPoints()) { - altTiles.put(ep, movingTile); - } + //Set the new center position + movingTile.setCenter(snapPoint); + //Check again, needed for tiles which are longer then 1 square, like a block + if (!checkTileOccupation(movingTile)) { + Logger.trace("Moved Tile " + movingTile.getId() + " from " + tp + " to " + snapPoint + "..."); + tiles.put(snapPoint, movingTile); + for (Point ep : movingTile.getAltPoints()) { + altTiles.put(ep, movingTile); } - - if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { - saveTile(movingTile); + } else { + //Do not move Tile, put back where it was + movingTile.setCenter(oldCenter); + tiles.put(oldCenter, movingTile); + for (Point ep : movingTile.getAltPoints()) { + altTiles.put(ep, movingTile); } } + + saveTile(movingTile); } } + //} } } diff --git a/src/main/java/jcs/ui/layout/tiles/Cross.java b/src/main/java/jcs/ui/layout/tiles/Cross.java index 7b35150e..4777b114 100644 --- a/src/main/java/jcs/ui/layout/tiles/Cross.java +++ b/src/main/java/jcs/ui/layout/tiles/Cross.java @@ -1 +1,668 @@ -/* * Copyright 2023 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.geom.Ellipse2D; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import jcs.entities.AccessoryBean.AccessoryValue; import static jcs.entities.AccessoryBean.AccessoryValue.GREEN; import static jcs.entities.AccessoryBean.AccessoryValue.RED; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; import static jcs.ui.layout.tiles.Tile.GRID; import static jcs.ui.layout.tiles.Tile.tileHeight; import static jcs.ui.layout.tiles.Tile.tileWidth; import org.tinylog.Logger; public class Cross extends Switch { public static final int CROSS_WIDTH = DEFAULT_WIDTH * 2; public static final int CROSS_HEIGHT = DEFAULT_HEIGHT * 2; public static final Color VERY_LIGHT_RED = new Color(255, 102, 102); public static final Color LIGHT_RED = new Color(255, 51, 51); public static final Color DARK_RED = new Color(204, 0, 0); public static final Color VERY_LIGHT_GREEN = new Color(102, 255, 102); public static final Color LIGHT_GREEN = new Color(0, 255, 51); public static final Color DARK_GREEN = new Color(0, 153, 0); public Cross(Orientation orientation, Direction direction, Point center) { this(orientation, direction, center.x, center.y); } public Cross(Orientation orientation, Direction direction, int x, int y) { this(orientation, direction, x, y, tileWidth(orientation, TileType.CROSS), tileHeight(orientation, TileType.CROSS)); } public Cross(Orientation orientation, Direction direction, int x, int y, int width, int height) { super(TileType.CROSS, orientation, direction, x, y, width, height); changeRenderSizeAndOffsets(); } public Cross(TileBean tileBean) { super(tileBean, tileWidth(tileBean.getOrientation(), TileType.CROSS), tileHeight(tileBean.getOrientation(), TileType.CROSS)); changeRenderSizeAndOffsets(); } /** * A Cross has a width in horizontal position of 2 tiles and a height of 1 tile in Vertical position.
* * @return the set of center point which mark the position of the Cross */ @Override public Set getAltPoints() { Set alternatives = new HashSet<>(); switch (getOrientation()) { case SOUTH -> { Point sp = new Point(tileX, (tileY + DEFAULT_HEIGHT)); alternatives.add(sp); } case WEST -> { Point wp = new Point((tileX - DEFAULT_WIDTH), tileY); alternatives.add(wp); } case NORTH -> { Point np = new Point(tileX, (tileY - DEFAULT_HEIGHT)); alternatives.add(np); } default -> { //East so default Point ep = new Point((tileX + DEFAULT_WIDTH), tileY); alternatives.add(ep); } } return alternatives; } @Override public Map getNeighborPoints() { Map neighbors = new HashMap<>(); Orientation orientation = this.getOrientation(); Direction direction = this.getDirection(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 4)); if (Direction.LEFT == direction) { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy + Tile.GRID * 2)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); } else { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy + Tile.GRID * 2)); } } case WEST -> { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 4, cy)); if (Direction.LEFT == direction) { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx - Tile.GRID * 2, cy + Tile.GRID * 2)); } else { neighbors.put(Orientation.NORTH, new Point(cx - Tile.GRID * 2, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); } } case NORTH -> { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 4)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); if (Direction.LEFT == direction) { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy - Tile.GRID * 2)); } else { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy - Tile.GRID * 2)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); } } default -> { //EAST neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 4, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); if (Direction.LEFT == direction) { neighbors.put(Orientation.NORTH, new Point(cx + Tile.GRID * 2, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); } else { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx + Tile.GRID * 2, cy + Tile.GRID * 2)); } } } return neighbors; } @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); Orientation orientation = this.getOrientation(); Direction direction = this.getDirection(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 3)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy + Tile.GRID * 2)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); } else { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy + Tile.GRID * 2)); } } case WEST -> { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID * 3, cy)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx - Tile.GRID * 2, cy + Tile.GRID)); } else { edgeConnections.put(Orientation.NORTH, new Point(cx - Tile.GRID * 2, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); } } case NORTH -> { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 3)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy - Tile.GRID * 2)); } else { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy - Tile.GRID * 2)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); } } default -> { //EAST edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID * 3, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.NORTH, new Point(cx + Tile.GRID * 2, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); } else { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx + Tile.GRID * 2, cy + Tile.GRID)); } } } return edgeConnections; } @Override protected void renderStraight(Graphics2D g2, Color color) { int xx, yy, w, h; xx = 0; yy = 170; w = RENDER_WIDTH; h = 60; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } @Override protected void renderRouteStraight(Graphics2D g2, Color color) { int xx, yy, w, h; xx = 0; yy = 190; w = RENDER_WIDTH; h = 20; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } protected void renderStraight2(Graphics2D g2, Color color) { int xx, yy, w, h; xx = RENDER_WIDTH; yy = 170; w = RENDER_WIDTH; h = 60; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } protected void renderRouteStraight2(Graphics2D g2, Color color) { int xx, yy, w, h; xx = RENDER_WIDTH; yy = 190; w = RENDER_WIDTH; h = 20; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } @Override protected void renderDiagonal(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{400, 400, 167, 230}; yPoints = new int[]{170, 230, 0, 0}; } else { xPoints = new int[]{400, 400, 170, 230}; yPoints = new int[]{230, 170, 400, 400}; } g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillPolygon(xPoints, yPoints, xPoints.length); } @Override protected void renderRouteDiagonal(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{420, 400, 190, 210}; yPoints = new int[]{210, 210, 0, 0}; } else { xPoints = new int[]{400, 400, 190, 210}; yPoints = new int[]{210, 190, 400, 400}; } g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillPolygon(xPoints, yPoints, xPoints.length); } protected void renderDiagonal2(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{400, 400, 570, 630}; yPoints = new int[]{170, 230, 400, 400}; } else { xPoints = new int[]{400, 400, 570, 630}; yPoints = new int[]{230, 170, 0, 0}; } g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillPolygon(xPoints, yPoints, xPoints.length); } protected void renderRouteDiagonal2(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{400, 380, 590, 610}; yPoints = new int[]{190, 190, 400, 400}; } else { xPoints = new int[]{400, 380, 590, 610}; yPoints = new int[]{210, 210, 0, 0}; } g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.setPaint(Color.cyan); g2.fillPolygon(xPoints, yPoints, xPoints.length); } @Override public void renderTile(Graphics2D g2) { if (accessoryValue == null) { this.accessoryValue = AccessoryValue.OFF; } switch (accessoryValue) { case RED -> { renderStraight2(g2, Cross.LIGHT_RED); renderDiagonal(g2, Cross.LIGHT_RED); renderStraight(g2, Cross.DARK_RED); renderDiagonal2(g2, Cross.DARK_RED); } case GREEN -> { renderDiagonal(g2, Cross.VERY_LIGHT_GREEN); renderDiagonal2(g2, Cross.VERY_LIGHT_GREEN); renderStraight(g2, Cross.DARK_GREEN); renderStraight2(g2, Cross.DARK_GREEN); } default -> { renderStraight(g2, trackColor); renderStraight2(g2, trackColor); renderDiagonal(g2, trackColor); renderDiagonal2(g2, trackColor); } } } @Override public void renderTileRoute(Graphics2D g2) { if (routeValue == null) { routeValue = AccessoryValue.OFF; } if (incomingSide == null) { incomingSide = getOrientation(); } if (isHorizontal()) { if (AccessoryValue.GREEN == routeValue && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteDiagonal(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (AccessoryValue.GREEN == routeValue && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteStraight2(g2, trackRouteColor); } else if (AccessoryValue.RED == routeValue && Orientation.EAST == getOrientation()) { if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight2(g2, trackRouteColor); renderRouteDiagonal(g2, trackRouteColor); } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteDiagonal2(g2, trackRouteColor); renderRouteStraight(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight2(g2, trackRouteColor); renderRouteDiagonal(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight(g2, trackColor); renderRouteDiagonal2(g2, trackColor); } } else if (AccessoryValue.RED == routeValue && Orientation.WEST == getOrientation()) { if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteDiagonal(g2, trackRouteColor); renderRouteStraight2(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight2(g2, trackColor); renderRouteDiagonal(g2, trackColor); } } } else { if (AccessoryValue.GREEN == routeValue && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteStraight2(g2, trackRouteColor); } else if (AccessoryValue.GREEN == routeValue && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { renderRouteDiagonal(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (AccessoryValue.RED == routeValue && Orientation.SOUTH == getOrientation()) { if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight2(g2, trackRouteColor); renderRouteDiagonal(g2, trackRouteColor); } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteDiagonal2(g2, trackRouteColor); renderRouteStraight(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight2(g2, trackColor); renderRouteDiagonal(g2, trackColor); } } else if (AccessoryValue.RED == routeValue && Orientation.NORTH == getOrientation()) { if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteDiagonal(g2, trackRouteColor); renderRouteStraight2(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight2(g2, trackRouteColor); renderRouteDiagonal(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight(g2, trackColor); renderRouteDiagonal2(g2, trackColor); } } } } @Override public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { if (from != null && to != null && this.getDirection() != null) { switch (this.getDirection()) { case LEFT -> { if (this.isHorizontal()) { if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.NORTH)) { return AccessoryValue.RED; } else if ((from == Orientation.EAST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.EAST)) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } else { //Vertical if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if ((from == Orientation.SOUTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.SOUTH)) { return AccessoryValue.RED; } else if ((from == Orientation.EAST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.EAST)) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } } case RIGHT -> { if (this.isHorizontal()) { if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.NORTH)) { return AccessoryValue.RED; } else if ((from == Orientation.WEST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.WEST)) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } else { //Vertical if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if ((from == Orientation.SOUTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.SOUTH)) { return AccessoryValue.RED; } else if ((from == Orientation.WEST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.WEST)) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } } default -> { return AccessoryValue.OFF; } } } else { return AccessoryValue.OFF; } } @Override protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { //A Cross has 1 alternate point //1st square holds the centerpoint //2nd square double dX1, dX2, dY1, dY2; Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case SOUTH -> { dX1 = renderWidth / 2 - size / 2; dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; dX2 = renderWidth / 2 + renderWidth - size / 4; dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; } case WEST -> { dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; dY1 = renderHeight / 2 - size / 2; dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; dY2 = renderHeight / 2 - size / 4; } case NORTH -> { dX1 = renderWidth / 2 - size / 2; dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; dX2 = renderWidth / 2 + renderWidth - size / 4; dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; } default -> { //East dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; dY1 = renderHeight / 2 - size / 2; dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; dY2 = renderHeight / 2 - size / 4; } } g2d.setColor(color); g2d.fill(new Ellipse2D.Double(dX1, dY1, size, size)); g2d.fill(new Ellipse2D.Double(dX2, dY2, size / 2, size / 2)); } @Override public Rectangle getTileBounds() { Orientation tileOrientation = model.getTileOrienation(); int xx, yy, w, h, multiplier; if (model.isScaleImage()) { w = tileWidth(tileOrientation, TileType.CROSS); h = tileHeight(tileOrientation, TileType.CROSS); multiplier = 1; } else { w = renderWidth; h = renderHeight; multiplier = 10; } switch (tileOrientation) { case SOUTH -> { xx = tileX - GRID * multiplier; yy = tileY - GRID * multiplier; } case WEST -> { xx = tileX - GRID * multiplier - GRID * 2 * multiplier; yy = tileY - GRID * multiplier; } case NORTH -> { xx = tileX - GRID * multiplier; yy = tileY - GRID * multiplier - GRID * 2 * multiplier; } default -> { //East xx = tileX - GRID * multiplier; yy = tileY - GRID * multiplier; } } Logger.trace(id + " O: " + tileOrientation + " Cur Cp: " + xyToString() + " New DsP: (" + xx + ", " + yy + ") W: " + w + " H: " + h + " M: " + multiplier + " Ox: " + offsetX + " Oy: " + offsetY); if (model.isScaleImage()) { return new Rectangle(xx, yy, tileWidth(tileOrientation, TileType.CROSS), tileHeight(tileOrientation, TileType.CROSS)); } else { return new Rectangle(xx, yy, renderWidth, renderHeight); } } private void changeRenderSizeAndOffsets() { //Reset offsets this.offsetY = 0; this.renderOffsetY = 0; this.offsetX = 0; this.renderOffsetX = 0; if (isHorizontal()) { //this.width = DEFAULT_WIDTH * 2; //this.height = DEFAULT_HEIGHT; this.renderWidth = RENDER_GRID * 4; this.renderHeight = RENDER_GRID * 2; this.offsetY = 0; this.renderOffsetY = 0; } else { //this.width = DEFAULT_WIDTH; //this.height = DEFAULT_HEIGHT * 2; this.renderWidth = RENDER_GRID * 2; this.renderHeight = RENDER_GRID * 4; this.offsetX = 0; this.renderOffsetX = 0; } //Due to the asymetical shape (center is on the left) //the offset has to be changed with the rotation Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case SOUTH -> { this.offsetY = +GRID; this.renderOffsetY = RENDER_GRID; } case WEST -> { this.offsetX = -GRID; this.renderOffsetX = -RENDER_GRID; } case NORTH -> { this.offsetY = -GRID; this.renderOffsetY = -RENDER_GRID; } default -> { //East so default this.offsetX = +GRID; this.renderOffsetX = +RENDER_GRID; } } } @Override public Orientation rotate() { super.rotate(); Orientation tileOrientation = model.getTileOrienation(); int w = tileWidth(tileOrientation, TileType.CROSS); int h = tileHeight(tileOrientation, TileType.CROSS); //the centerpoin can shift as a cross is inbalanced int multiplier = (model.isScaleImage() ? 1 : 10); int x, y; switch (tileOrientation) { case SOUTH -> { //the centerpoint remains the same x = tileX; y = tileY; } case WEST -> { // centerpoint shifts to the 2nd square x = tileX; // - GRID * multiplier - GRID * 2 * multiplier; y = tileY; // - GRID * multiplier; } case NORTH -> { x = tileX; // - GRID * multiplier; y = tileY; // - GRID * multiplier - GRID * 2 * multiplier; } default -> { //East x = tileX; y = tileY; } } Dimension d = new Dimension(w, h); setPreferredSize(d); setSize(d); changeRenderSizeAndOffsets(); //set the new center this.tileX = x; this.tileY = y; Logger.trace(id + " O: " + tileOrientation + " Cur Cp: " + xyToString() + " New CP: (" + x + ", " + y + ") W: " + w + " H: " + h + " M: " + multiplier + " Ox: " + offsetX + " Oy: " + offsetY); setBounds(getTileBounds()); return tileOrientation; } } \ No newline at end of file +/* + * Copyright 2023 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.geom.Ellipse2D; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import jcs.entities.AccessoryBean.AccessoryValue; +import static jcs.entities.AccessoryBean.AccessoryValue.GREEN; +import static jcs.entities.AccessoryBean.AccessoryValue.RED; +import jcs.entities.TileBean; +import jcs.entities.TileBean.Direction; +import jcs.entities.TileBean.Orientation; +import static jcs.entities.TileBean.Orientation.NORTH; +import static jcs.entities.TileBean.Orientation.SOUTH; +import static jcs.entities.TileBean.Orientation.WEST; +import jcs.entities.TileBean.TileType; +import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; +import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; +import static jcs.ui.layout.tiles.Tile.GRID; +import static jcs.ui.layout.tiles.Tile.tileHeight; +import static jcs.ui.layout.tiles.Tile.tileWidth; + +public class Cross extends Switch { + + public static final int CROSS_WIDTH = DEFAULT_WIDTH * 2; + public static final int CROSS_HEIGHT = DEFAULT_HEIGHT * 2; + + public static final Color VERY_LIGHT_RED = new Color(255, 102, 102); + public static final Color LIGHT_RED = new Color(255, 51, 51); + public static final Color DARK_RED = new Color(204, 0, 0); + + public static final Color VERY_LIGHT_GREEN = new Color(102, 255, 102); + public static final Color LIGHT_GREEN = new Color(0, 255, 51); + public static final Color DARK_GREEN = new Color(0, 153, 0); + + public Cross(Orientation orientation, Direction direction, Point center) { + this(orientation, direction, center.x, center.y); + } + + public Cross(Orientation orientation, Direction direction, int x, int y) { + this(orientation, direction, x, y, tileWidth(orientation, TileType.CROSS), tileHeight(orientation, TileType.CROSS)); + } + + public Cross(Orientation orientation, Direction direction, int x, int y, int width, int height) { + super(TileType.CROSS, orientation, direction, x, y, width, height); + changeRenderSizeAndOffsets(); + } + + public Cross(TileBean tileBean) { + super(tileBean, tileWidth(tileBean.getOrientation(), TileType.CROSS), tileHeight(tileBean.getOrientation(), TileType.CROSS)); + changeRenderSizeAndOffsets(); + } + + /** + * A Cross has a width in horizontal position of 2 tiles and a height of 1 tile in Vertical position.
+ * + * @return the set of center point which mark the position of the Cross + */ + @Override + public Set getAltPoints() { + Set alternatives = new HashSet<>(); + + switch (getOrientation()) { + case SOUTH -> { + Point sp = new Point(tileX, (tileY + DEFAULT_HEIGHT)); + alternatives.add(sp); + } + case WEST -> { + Point wp = new Point((tileX - DEFAULT_WIDTH), tileY); + alternatives.add(wp); + } + case NORTH -> { + Point np = new Point(tileX, (tileY - DEFAULT_HEIGHT)); + alternatives.add(np); + } + default -> { + //East so default + Point ep = new Point((tileX + DEFAULT_WIDTH), tileY); + alternatives.add(ep); + } + } + return alternatives; + } + + @Override + public Map getNeighborPoints() { + Map neighbors = new HashMap<>(); + Orientation orientation = this.getOrientation(); + Direction direction = this.getDirection(); + int cx = this.getCenterX(); + int cy = this.getCenterY(); + + switch (orientation) { + case SOUTH -> { + neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); + neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 4)); + + if (Direction.LEFT == direction) { + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy + Tile.GRID * 2)); + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); + } else { + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy + Tile.GRID * 2)); + } + } + case WEST -> { + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 4, cy)); + + if (Direction.LEFT == direction) { + neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); + neighbors.put(Orientation.SOUTH, new Point(cx - Tile.GRID * 2, cy + Tile.GRID * 2)); + } else { + neighbors.put(Orientation.NORTH, new Point(cx - Tile.GRID * 2, cy - Tile.GRID * 2)); + neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); + } + } + case NORTH -> { + neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 4)); + neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); + + if (Direction.LEFT == direction) { + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy - Tile.GRID * 2)); + } else { + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy - Tile.GRID * 2)); + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); + } + } + default -> { + //EAST + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 4, cy)); + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); + + if (Direction.LEFT == direction) { + neighbors.put(Orientation.NORTH, new Point(cx + Tile.GRID * 2, cy - Tile.GRID * 2)); + neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); + } else { + neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); + neighbors.put(Orientation.SOUTH, new Point(cx + Tile.GRID * 2, cy + Tile.GRID * 2)); + } + } + } + return neighbors; + } + + @Override + public Map getEdgePoints() { + Map edgeConnections = new HashMap<>(); + Orientation orientation = this.getOrientation(); + Direction direction = this.getDirection(); + int cx = this.getCenterX(); + int cy = this.getCenterY(); + + switch (orientation) { + case SOUTH -> { + edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); + edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 3)); + + if (Direction.LEFT == direction) { + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy + Tile.GRID * 2)); + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); + } else { + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy + Tile.GRID * 2)); + } + } + case WEST -> { + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID * 3, cy)); + + if (Direction.LEFT == direction) { + edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); + edgeConnections.put(Orientation.SOUTH, new Point(cx - Tile.GRID * 2, cy + Tile.GRID)); + } else { + edgeConnections.put(Orientation.NORTH, new Point(cx - Tile.GRID * 2, cy - Tile.GRID)); + edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); + } + } + case NORTH -> { + edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 3)); + edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); + + if (Direction.LEFT == direction) { + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy - Tile.GRID * 2)); + } else { + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy - Tile.GRID * 2)); + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); + } + } + default -> { + //EAST + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID * 3, cy)); + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); + + if (Direction.LEFT == direction) { + edgeConnections.put(Orientation.NORTH, new Point(cx + Tile.GRID * 2, cy - Tile.GRID)); + edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); + } else { + edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); + edgeConnections.put(Orientation.SOUTH, new Point(cx + Tile.GRID * 2, cy + Tile.GRID)); + } + } + } + return edgeConnections; + } + + @Override + protected void renderStraight(Graphics2D g2, Color color) { + int xx, yy, w, h; + xx = 0; + yy = 170; + w = RENDER_WIDTH; + h = 60; + + g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + g2.fillRect(xx, yy, w, h); + } + + @Override + protected void renderRouteStraight(Graphics2D g2, Color color) { + int xx, yy, w, h; + xx = 0; + yy = 190; + w = RENDER_WIDTH; + h = 20; + + g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + g2.fillRect(xx, yy, w, h); + } + + protected void renderStraight2(Graphics2D g2, Color color) { + int xx, yy, w, h; + xx = RENDER_WIDTH; + yy = 170; + w = RENDER_WIDTH; + h = 60; + + g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + g2.fillRect(xx, yy, w, h); + } + + protected void renderRouteStraight2(Graphics2D g2, Color color) { + int xx, yy, w, h; + xx = RENDER_WIDTH; + yy = 190; + w = RENDER_WIDTH; + h = 20; + + g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + g2.fillRect(xx, yy, w, h); + } + + @Override + protected void renderDiagonal(Graphics2D g2, Color color) { + int[] xPoints, yPoints; + if (Direction.RIGHT.equals(getDirection())) { + xPoints = new int[]{400, 400, 167, 230}; + yPoints = new int[]{170, 230, 0, 0}; + } else { + xPoints = new int[]{400, 400, 170, 230}; + yPoints = new int[]{230, 170, 400, 400}; + } + + g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + g2.fillPolygon(xPoints, yPoints, xPoints.length); + } + + @Override + protected void renderRouteDiagonal(Graphics2D g2, Color color) { + int[] xPoints, yPoints; + if (Direction.RIGHT.equals(getDirection())) { + xPoints = new int[]{420, 400, 190, 210}; + yPoints = new int[]{210, 210, 0, 0}; + } else { + xPoints = new int[]{400, 400, 190, 210}; + yPoints = new int[]{210, 190, 400, 400}; + } + + g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + g2.fillPolygon(xPoints, yPoints, xPoints.length); + } + + protected void renderDiagonal2(Graphics2D g2, Color color) { + int[] xPoints, yPoints; + if (Direction.RIGHT.equals(getDirection())) { + xPoints = new int[]{400, 400, 570, 630}; + yPoints = new int[]{170, 230, 400, 400}; + } else { + xPoints = new int[]{400, 400, 570, 630}; + yPoints = new int[]{230, 170, 0, 0}; + } + + g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + g2.fillPolygon(xPoints, yPoints, xPoints.length); + } + + protected void renderRouteDiagonal2(Graphics2D g2, Color color) { + int[] xPoints, yPoints; + if (Direction.RIGHT.equals(getDirection())) { + xPoints = new int[]{400, 380, 590, 610}; + yPoints = new int[]{190, 190, 400, 400}; + } else { + xPoints = new int[]{400, 380, 590, 610}; + yPoints = new int[]{210, 210, 0, 0}; + } + + g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + g2.setPaint(Color.cyan); + g2.fillPolygon(xPoints, yPoints, xPoints.length); + } + + @Override + public void renderTile(Graphics2D g2) { + if (accessoryValue == null) { + this.accessoryValue = AccessoryValue.OFF; + } + + switch (accessoryValue) { + case RED -> { + renderStraight2(g2, Cross.LIGHT_RED); + renderDiagonal(g2, Cross.LIGHT_RED); + renderStraight(g2, Cross.DARK_RED); + renderDiagonal2(g2, Cross.DARK_RED); + } + case GREEN -> { + renderDiagonal(g2, Cross.VERY_LIGHT_GREEN); + renderDiagonal2(g2, Cross.VERY_LIGHT_GREEN); + renderStraight(g2, Cross.DARK_GREEN); + renderStraight2(g2, Cross.DARK_GREEN); + } + default -> { + renderStraight(g2, trackColor); + renderStraight2(g2, trackColor); + renderDiagonal(g2, trackColor); + renderDiagonal2(g2, trackColor); + } + } + } + + @Override + public void renderTileRoute(Graphics2D g2) { + if (routeValue == null) { + routeValue = AccessoryValue.OFF; + } + if (incomingSide == null) { + incomingSide = getOrientation(); + } + + if (isHorizontal()) { + if (AccessoryValue.GREEN == routeValue && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { + renderRouteDiagonal(g2, trackRouteColor); + renderRouteDiagonal2(g2, trackRouteColor); + } else if (AccessoryValue.GREEN == routeValue && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { + renderRouteStraight(g2, trackRouteColor); + renderRouteStraight2(g2, trackRouteColor); + } else if (AccessoryValue.RED == routeValue && Orientation.EAST == getOrientation()) { + if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { + renderRouteStraight2(g2, trackRouteColor); + renderRouteDiagonal(g2, trackRouteColor); + } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { + renderRouteDiagonal2(g2, trackRouteColor); + renderRouteStraight(g2, trackRouteColor); + } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { + renderRouteStraight2(g2, trackRouteColor); + renderRouteDiagonal(g2, trackRouteColor); + } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { + renderRouteStraight(g2, trackColor); + renderRouteDiagonal2(g2, trackColor); + } + } else if (AccessoryValue.RED == routeValue && Orientation.WEST == getOrientation()) { + if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { + renderRouteStraight(g2, trackRouteColor); + renderRouteDiagonal2(g2, trackRouteColor); + } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { + renderRouteDiagonal(g2, trackRouteColor); + renderRouteStraight2(g2, trackRouteColor); + } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { + renderRouteStraight(g2, trackRouteColor); + renderRouteDiagonal2(g2, trackRouteColor); + } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { + renderRouteStraight2(g2, trackColor); + renderRouteDiagonal(g2, trackColor); + } + } + } else { + if (AccessoryValue.GREEN == routeValue && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { + renderRouteStraight(g2, trackRouteColor); + renderRouteStraight2(g2, trackRouteColor); + } else if (AccessoryValue.GREEN == routeValue && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { + renderRouteDiagonal(g2, trackRouteColor); + renderRouteDiagonal2(g2, trackRouteColor); + } else if (AccessoryValue.RED == routeValue && Orientation.SOUTH == getOrientation()) { + if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { + renderRouteStraight2(g2, trackRouteColor); + renderRouteDiagonal(g2, trackRouteColor); + } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { + renderRouteDiagonal2(g2, trackRouteColor); + renderRouteStraight(g2, trackRouteColor); + } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { + renderRouteStraight(g2, trackRouteColor); + renderRouteDiagonal2(g2, trackRouteColor); + } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { + renderRouteStraight2(g2, trackColor); + renderRouteDiagonal(g2, trackColor); + } + } else if (AccessoryValue.RED == routeValue && Orientation.NORTH == getOrientation()) { + if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { + renderRouteStraight(g2, trackRouteColor); + renderRouteDiagonal2(g2, trackRouteColor); + } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { + renderRouteDiagonal(g2, trackRouteColor); + renderRouteStraight2(g2, trackRouteColor); + } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { + renderRouteStraight2(g2, trackRouteColor); + renderRouteDiagonal(g2, trackRouteColor); + } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { + renderRouteStraight(g2, trackColor); + renderRouteDiagonal2(g2, trackColor); + } + } + } + } + + @Override + public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { + if (from != null && to != null && this.getDirection() != null) { + switch (this.getDirection()) { + case LEFT -> { + if (this.isHorizontal()) { + if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { + return AccessoryValue.GREEN; + } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { + return AccessoryValue.GREEN; + } else if ((from == Orientation.NORTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.NORTH)) { + return AccessoryValue.RED; + } else if ((from == Orientation.EAST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.EAST)) { + return AccessoryValue.RED; + } else { + return AccessoryValue.OFF; + } + } else { + //Vertical + if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { + return AccessoryValue.GREEN; + } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { + return AccessoryValue.GREEN; + } else if ((from == Orientation.SOUTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.SOUTH)) { + return AccessoryValue.RED; + } else if ((from == Orientation.EAST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.EAST)) { + return AccessoryValue.RED; + } else { + return AccessoryValue.OFF; + } + } + } + case RIGHT -> { + if (this.isHorizontal()) { + if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { + return AccessoryValue.GREEN; + } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { + return AccessoryValue.GREEN; + } else if ((from == Orientation.NORTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.NORTH)) { + return AccessoryValue.RED; + } else if ((from == Orientation.WEST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.WEST)) { + return AccessoryValue.RED; + } else { + return AccessoryValue.OFF; + } + } else { + //Vertical + if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { + return AccessoryValue.GREEN; + } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { + return AccessoryValue.GREEN; + } else if ((from == Orientation.SOUTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.SOUTH)) { + return AccessoryValue.RED; + } else if ((from == Orientation.WEST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.WEST)) { + return AccessoryValue.RED; + } else { + return AccessoryValue.OFF; + } + } + } + default -> { + return AccessoryValue.OFF; + } + } + } else { + return AccessoryValue.OFF; + } + } + + @Override + protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { + //A Cross has 1 alternate point + //1st square holds the centerpoint + //2nd square + double dX1, dX2, dY1, dY2; + Orientation tileOrientation = model.getTileOrienation(); + switch (tileOrientation) { + case SOUTH -> { + dX1 = renderWidth / 2 - size / 2; + dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; + dX2 = renderWidth / 2 + renderWidth - size / 4; + dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; + } + case WEST -> { + dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; + dY1 = renderHeight / 2 - size / 2; + dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; + dY2 = renderHeight / 2 - size / 4; + } + case NORTH -> { + dX1 = renderWidth / 2 - size / 2; + dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; + dX2 = renderWidth / 2 + renderWidth - size / 4; + dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; + } + default -> { + //East + dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; + dY1 = renderHeight / 2 - size / 2; + dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; + dY2 = renderHeight / 2 - size / 4; + } + } + + g2d.setColor(color); + g2d.fill(new Ellipse2D.Double(dX1, dY1, size, size)); + g2d.fill(new Ellipse2D.Double(dX2, dY2, size / 2, size / 2)); + } + + @Override + public Rectangle getTileBounds() { + Orientation tileOrientation = model.getTileOrienation(); + int xx, yy, w, h, multiplier; + if (model.isScaleImage()) { + w = tileWidth(tileOrientation, TileType.CROSS); + h = tileHeight(tileOrientation, TileType.CROSS); + multiplier = 1; + } else { + w = renderWidth; + h = renderHeight; + multiplier = 10; + } + + switch (tileOrientation) { + case SOUTH -> { + xx = tileX - GRID * multiplier; + yy = tileY - GRID * multiplier; + } + case WEST -> { + xx = tileX - GRID * multiplier - GRID * 2 * multiplier; + yy = tileY - GRID * multiplier; + } + case NORTH -> { + xx = tileX - GRID * multiplier; + yy = tileY - GRID * multiplier - GRID * 2 * multiplier; + } + default -> { + //East + xx = tileX - GRID * multiplier; + yy = tileY - GRID * multiplier; + } + } + + if (model.isScaleImage()) { + return new Rectangle(xx, yy, tileWidth(tileOrientation, TileType.CROSS), tileHeight(tileOrientation, TileType.CROSS)); + } else { + return new Rectangle(xx, yy, renderWidth, renderHeight); + } + } + + private void changeRenderSizeAndOffsets() { + //Reset offsets + this.offsetY = 0; + this.renderOffsetY = 0; + this.offsetX = 0; + this.renderOffsetX = 0; + + if (isHorizontal()) { + this.renderWidth = RENDER_GRID * 4; + this.renderHeight = RENDER_GRID * 2; + + this.offsetY = 0; + this.renderOffsetY = 0; + } else { + this.renderWidth = RENDER_GRID * 2; + this.renderHeight = RENDER_GRID * 4; + + this.offsetX = 0; + this.renderOffsetX = 0; + } + + //Due to the asymetical shape (center is on the left) + //the offset has to be changed with the rotation + Orientation tileOrientation = model.getTileOrienation(); + switch (tileOrientation) { + case SOUTH -> { + this.offsetY = +GRID; + this.renderOffsetY = RENDER_GRID; + } + case WEST -> { + this.offsetX = -GRID; + this.renderOffsetX = -RENDER_GRID; + } + case NORTH -> { + this.offsetY = -GRID; + this.renderOffsetY = -RENDER_GRID; + } + default -> { + //East so default + this.offsetX = +GRID; + this.renderOffsetX = +RENDER_GRID; + } + } + } + + @Override + public Orientation rotate() { + super.rotate(); + + Orientation tileOrientation = model.getTileOrienation(); + int w = tileWidth(tileOrientation, TileType.CROSS); + int h = tileHeight(tileOrientation, TileType.CROSS); + + Dimension d = new Dimension(w, h); + setPreferredSize(d); + setSize(d); + changeRenderSizeAndOffsets(); + + setBounds(getTileBounds()); + return tileOrientation; + } + +} diff --git a/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java b/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java index 6663ee90..d9e99fd9 100644 --- a/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java +++ b/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java @@ -15,6 +15,7 @@ */ package jcs.ui.layout.tiles; +import java.awt.Color; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemListener; @@ -40,6 +41,7 @@ public class DefaultTileModel implements TileModel { protected EventListenerList listenerList = new EventListenerList(); protected boolean selected = false; + protected Color selectedColor; protected boolean scaleImage = true; protected boolean showCenter = false; protected Orientation tileOrienation; @@ -64,6 +66,7 @@ public DefaultTileModel() { public DefaultTileModel(Orientation orientation) { this.tileOrienation = orientation; + this.selectedColor = Tile.DEFAULT_SELECTED_COLOR; } @Override @@ -77,6 +80,25 @@ public void setSelected(boolean selected) { fireStateChanged(); } + @Override + public Color getSelectedColor() { + return selectedColor; + } + + @Override + public void setSelectedColor(Color selectedColor) { + Color prevColor = selectedColor; + if (selectedColor != null) { + this.selectedColor = selectedColor; + } else { + this.selectedColor = Tile.DEFAULT_SELECTED_COLOR; + } + + if (!this.selectedColor.equals(prevColor)) { + fireStateChanged(); + } + } + @Override public boolean isScaleImage() { return scaleImage; diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java index dfd1939e..f22ea4f7 100755 --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -1 +1,1133 @@ -/* * Copyright 2024 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.AffineTransform; import java.awt.geom.Ellipse2D; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; import java.beans.PropertyChangeListener; import java.io.Serializable; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import javax.swing.JComponent; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.AccessoryValue; import jcs.entities.AccessoryBean.SignalType; import jcs.entities.BlockBean; import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; import jcs.entities.SensorBean; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import jcs.entities.TileBean.TileType; import jcs.ui.layout.LayoutUtil; import static jcs.ui.layout.tiles.Block.BLOCK_HEIGHT; import static jcs.ui.layout.tiles.Block.BLOCK_WIDTH; import org.imgscalr.Scalr; import org.imgscalr.Scalr.Method; import org.imgscalr.Scalr.Mode; import org.tinylog.Logger; /** * Basic graphic element to display a track, turnout, etc on the screen.
* By default the drawing of a Tile is Horizontal from L to R or West to East.
* The default orientation is East. * *

* The default size of a Tile is 40 tileX 40 pixels.
* The center point of a Tile is stored and always snapped to the nearest grid point.
* The basic grid is 20x 20 pixels.
* *

* A Tile can be rotated (always clockwise).
* Rotation will change the orientation from East -> South -> West -> North -> East.
* *

* A Tile is rendered to a Buffered Image to speed up the display */ public abstract class Tile extends JComponent { //implements TileEventListener { //, ItemSelectable { public static final int GRID = 20; public static final int DEFAULT_WIDTH = GRID * 2; public static final int DEFAULT_HEIGHT = GRID * 2; static final int RENDER_GRID = GRID * 10; static final int RENDER_WIDTH = RENDER_GRID * 2; static final int RENDER_HEIGHT = RENDER_GRID * 2; public static final Color DEFAULT_BACKGROUND_COLOR = Color.white; public static final Color DEFAULT_TRACK_COLOR = Color.lightGray; public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.blue; public static final Color DEFAULT_SELECTED_COLOR = Color.yellow; public static final String MODEL_CHANGED_PROPERTY = "model"; public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled"; /** * The data model that determines the button's state. */ protected TileModel model = null; protected String id; protected Integer tileX; protected Integer tileY; protected int renderWidth; protected int renderHeight; //protected Orientation tileOrientation; protected Direction tileDirection; protected TileType tileType; protected String accessoryId; protected String sensorId; protected AccessoryValue accessoryValue; protected AccessoryValue routeValue; protected SignalType signalType; protected AccessoryBean.SignalValue signalValue; protected TileBean tileBean; protected AccessoryBean accessoryBean; protected SensorBean sensorBean; protected BlockBean blockBean; protected List neighbours; protected int offsetX = 0; protected int offsetY = 0; protected int renderOffsetX = 0; protected int renderOffsetY = 0; protected Color selectedColor; protected Color trackColor; protected Color trackRouteColor; protected Orientation incomingSide; protected Color backgroundColor; protected boolean drawName = true; protected BufferedImage tileImage; protected PropertyChangeListener propertyChangeListener; protected ChangeListener changeListener = null; protected ActionListener actionListener = null; protected transient ChangeEvent changeEvent; private Handler handler; protected Tile(TileType tileType, Orientation orientation, Point center, int width, int height) { this(tileType, orientation, Direction.CENTER, center.x, center.y, width, height); } protected Tile(TileType tileType, Orientation orientation, int x, int y, int width, int height) { this(tileType, orientation, Direction.CENTER, x, y, width, height); } protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { this(tileType, orientation, direction, x, y, width, height, null, null); } protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height, Color backgroundColor, Color selectedColor) { this.tileType = tileType; //this.tileOrientation = orientation; //model.setTileOrienation(orientation); this.tileDirection = direction; this.tileX = x; this.tileY = y; setLayout(null); Dimension d = new Dimension(width, height); setSize(d); setPreferredSize(d); this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT; this.trackColor = DEFAULT_TRACK_COLOR; this.backgroundColor = backgroundColor; this.selectedColor = selectedColor; if (this.backgroundColor == null) { this.backgroundColor = DEFAULT_BACKGROUND_COLOR; } if (this.selectedColor == null) { this.selectedColor = DEFAULT_SELECTED_COLOR; } } protected Tile(TileBean tileBean) { this(tileBean, tileWidth(tileBean.getOrientation(), tileBean.getTileType()), tileHeight(tileBean.getOrientation(), tileBean.getTileType())); } protected Tile(TileBean tileBean, int width, int height) { this.tileBean = tileBean; //Quick properties this.id = tileBean.getId(); this.tileType = tileBean.getTileType(); //this.tileOrientation = tileBean.getOrientation(); //this.model.setTileOrienation(tileBean.getOrientation()); this.tileDirection = tileBean.getDirection(); this.tileX = tileBean.getX(); this.tileY = tileBean.getY(); this.accessoryId = tileBean.getAccessoryId(); this.accessoryBean = tileBean.getAccessoryBean(); this.signalType = tileBean.getSignalType(); this.sensorId = tileBean.getSensorId(); this.sensorBean = tileBean.getSensorBean(); this.blockBean = tileBean.getBlockBean(); setLayout(null); Dimension d = new Dimension(width, height); setSize(d); setPreferredSize(d); this.trackColor = DEFAULT_TRACK_COLOR; this.backgroundColor = DEFAULT_BACKGROUND_COLOR; this.selectedColor = DEFAULT_SELECTED_COLOR; this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT; } protected static int tileWidth(Orientation orientation, TileType tileType) { if (Orientation.EAST == orientation || Orientation.WEST == orientation) { if (null == tileType) { return DEFAULT_WIDTH; } else { return switch (tileType) { case BLOCK -> BLOCK_WIDTH; case CROSS -> DEFAULT_WIDTH * 2; default -> DEFAULT_WIDTH; }; } } else { return DEFAULT_WIDTH; } } protected static int tileHeight(Orientation orientation, TileType tileType) { if (Orientation.EAST == orientation || Orientation.WEST == orientation) { return DEFAULT_HEIGHT; } else { if (null == tileType) { return DEFAULT_HEIGHT; } else { return switch (tileType) { case BLOCK -> BLOCK_HEIGHT; case CROSS -> DEFAULT_HEIGHT * 2; default -> DEFAULT_HEIGHT; }; } } } protected void populateModel() { if (this.blockBean != null) { this.model.setBlockState(this.blockBean.getBlockState()); this.model.setLocomotive(this.blockBean.getLocomotive()); this.model.setArrivalSuffix(this.blockBean.getArrivalSuffix()); this.model.setLogicalDirection(LocomotiveBean.Direction.get(this.blockBean.getLogicalDirection())); } } public TileBean getTileBean() { if (tileBean == null) { tileBean = new TileBean(); tileBean.setId(this.id); tileBean.setX(this.tileX); tileBean.setY(this.tileY); tileBean.setTileType(this.tileType); //tileBean.setTileOrientation(this.tileOrientation.getOrientation()); tileBean.setTileOrientation(this.model.getTileOrienation().getOrientation()); tileBean.setTileDirection(this.tileDirection.getDirection()); tileBean.setSignalType(this.signalType); tileBean.setAccessoryId(this.accessoryId); tileBean.setSensorId(this.sensorId); tileBean.setAccessoryBean(this.accessoryBean); tileBean.setSensorBean(this.sensorBean); tileBean.setBlockBean(this.blockBean); } return tileBean; } public boolean isSelected() { return model.isSelected(); } public void setSelected(boolean b) { //boolean oldValue = isSelected(); model.setSelected(b); } public String getId() { return id; } public void setId(String id) { this.id = id; } public SignalType getSignalType() { return signalType; } public void setSignalType(SignalType signalType) { this.signalType = signalType; } public Integer getTileX() { return tileX; } public Integer getTileY() { return tileY; } public Point getCenter() { return new Point(this.tileX, this.tileY); } public void setCenter(Point center) { tileX = center.x; tileY = center.y; if (tileBean != null) { tileBean.setCenter(center); } Logger.trace(id + " Cp: " + xyToString()); } public Orientation getOrientation() { //return tileOrientation; return model.getTileOrienation(); } public void setOrientation(Orientation orientation) { //this.tileOrientation = orientation; model.setTileOrienation(orientation); if (tileBean != null) { tileBean.setOrientation(orientation); } } public Direction getDirection() { return tileDirection; } public void setDirection(Direction direction) { this.tileDirection = direction; if (tileBean != null) { tileBean.setDirection(direction); } } public String getAccessoryId() { return accessoryId; } public void setAccessoryId(String accessoryId) { this.accessoryId = accessoryId; if (tileBean != null) { tileBean.setAccessoryId(accessoryId); } } public String getSensorId() { return sensorId; } public void setSensorId(String sensorId) { this.sensorId = sensorId; } public boolean isActive() { return model.isSensorActive(); } public void setActive(boolean active) { model.setSensorActive(active); } public BlockState getBlockState() { return model.getBlockState(); } public void setBlockState(BlockState blockState) { if (blockBean != null) { blockBean.setBlockState(blockState); LocomotiveBean locomotive = model.getLocomotive(); model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (blockState == BlockState.OCCUPIED || blockState == BlockState.INBOUND || blockState == BlockState.OUTBOUND)); } model.setBlockState(blockState); } public String getDepartureSuffix() { return model.getDepartureSuffix(); } public void setDepartureSuffix(String suffix) { if (blockBean != null) { blockBean.setDepartureSuffix(suffix); } model.setDepartureSuffix(suffix); } public boolean isReverseArrival() { return model.isReverseArrival(); } public void setReverseArrival(boolean reverseArrival) { if (blockBean != null) { blockBean.setReverseArrival(reverseArrival); } model.setReverseArrival(reverseArrival); } public LocomotiveBean.Direction getLogicalDirection() { return model.getLogicalDirection(); } public void setLogicalDirection(LocomotiveBean.Direction logicalDirection) { if (blockBean != null) { blockBean.setLogicalDirection(logicalDirection.getDirection()); } model.setLogicalDirection(logicalDirection); } public LocomotiveBean getLocomotive() { return model.getLocomotive(); } public void setLocomotive(LocomotiveBean locomotive) { if (blockBean != null) { blockBean.setLocomotive(locomotive); model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (model.getBlockState() == BlockState.OCCUPIED || model.getBlockState() == BlockState.INBOUND || model.getBlockState() == BlockState.OUTBOUND)); } model.setLocomotive(locomotive); } public AccessoryBean getAccessoryBean() { return accessoryBean; } public void setAccessoryBean(AccessoryBean accessoryBean) { this.accessoryBean = accessoryBean; if (accessoryBean != null) { accessoryId = accessoryBean.getId(); signalValue = accessoryBean.getSignalValue(); signalType = SignalType.getSignalType(accessoryBean.getType()); } else { accessoryId = null; signalType = SignalType.NONE; signalValue = AccessoryBean.SignalValue.OFF; } } public AccessoryValue getAccessoryValue() { if (this.accessoryValue == null) { return AccessoryValue.OFF; } else { return accessoryValue; } } public void setAccessoryValue(AccessoryValue value) { this.accessoryValue = value; repaint(); } public AccessoryValue getRouteValue() { if (routeValue == null) { return AccessoryValue.OFF; } else { return routeValue; } } public void setRouteValue(AccessoryValue value) { this.routeValue = value; repaint(); } public AccessoryBean.SignalValue getSignalValue() { return signalValue; } public void setSignalValue(AccessoryBean.SignalValue signalValue) { this.signalValue = signalValue; repaint(); } public SensorBean getSensorBean() { return sensorBean; } public void setSensorBean(SensorBean sensorBean) { this.sensorBean = sensorBean; } public BlockBean getBlockBean() { return blockBean; } public void setBlockBean(BlockBean blockBean) { this.blockBean = blockBean; } public void setRenderWidth(int renderWidth) { this.renderWidth = renderWidth; } public void setRenderHeight(int renderHeight) { this.renderHeight = renderHeight; } public int getRenderOffsetX() { return renderOffsetX; } public void setRenderOffsetX(int renderOffsetX) { this.renderOffsetX = renderOffsetX; } public int getRenderOffsetY() { return renderOffsetY; } public void setRenderOffsetY(int renderOffsetY) { this.renderOffsetY = renderOffsetY; } public TileBean.TileType getTileType() { return this.tileType; } public final void setTileType(TileType tileType) { this.tileType = tileType; } public Color getTrackColor() { return trackColor; } public final void setTrackColor(Color trackColor) { this.trackColor = trackColor; } public Color getTrackRouteColor() { return trackRouteColor; } public void setTrackRouteColor(Color trackRouteColor) { this.trackRouteColor = trackRouteColor; } public Color getSelectedColor() { return selectedColor; } public void setSelectedColor(Color selectedColor) { this.selectedColor = selectedColor; } public Orientation getIncomingSide() { return incomingSide; } public void setIncomingSide(Orientation incomingSide) { this.incomingSide = incomingSide; } public Color getBackgroundColor() { return backgroundColor; } public void setBackgroundColor(Color backgroundColor) { this.backgroundColor = backgroundColor; } public boolean isDrawRoute() { return model.isShowRoute(); } public void setDrawRoute(boolean drawRoute) { this.model.setShowRoute(drawRoute); } public int getRenderWidth() { return renderWidth; } public int getRenderHeight() { return renderHeight; } abstract void renderTile(Graphics2D g2d); abstract void renderTileRoute(Graphics2D g2d); public abstract Map getNeighborPoints(); public abstract Map getEdgePoints(); public abstract Set getAllPoints(); /** * Draw the Tile * * @param g2d The graphics handle */ public void drawTile(Graphics2D g2d) { // by default and image is rendered in the EAST orientation Orientation tileOrientation = model.getTileOrienation(); // if (tileOrientation == null) { // tileOrientation = Orientation.EAST; // } BufferedImage bf = createImage(); Graphics2D g2di = bf.createGraphics(); //Avoid errors if (model.isShowRoute() && incomingSide == null) { incomingSide = getOrientation(); } if (model.isSelected()) { g2di.setBackground(selectedColor); } else { g2di.setBackground(backgroundColor); } g2di.clearRect(0, 0, renderWidth, renderHeight); int ox = 0, oy = 0; AffineTransform trans = new AffineTransform(); switch (tileOrientation) { case SOUTH -> { trans.rotate(Math.PI / 2, renderWidth / 2, renderHeight / 2); ox = (renderHeight - renderWidth) / 2; oy = (renderWidth - renderHeight) / 2; trans.translate(-ox, -oy); } case WEST -> { trans.rotate(Math.PI, renderWidth / 2, renderHeight / 2); trans.translate(ox, oy); } case NORTH -> { trans.rotate(-Math.PI / 2, renderWidth / 2, renderHeight / 2); ox = (renderHeight - renderWidth) / 2; oy = (renderWidth - renderHeight) / 2; trans.translate(-ox, -oy); } default -> { trans.rotate(0.0, this.renderWidth / 2, this.renderHeight / 2); trans.translate(ox, oy); } } //Logger.trace(tileOrientation.getOrientation() + " renderWidth: " + renderWidth + " renderHeight: " + renderHeight + " CP: (" + renderWidth / 2 + "," + renderHeight / 2 + ")"); //Logger.trace(tileOrientation.getOrientation() + " ox: " + ox + " oy: " + oy); g2di.setTransform(trans); renderTile(g2di); if (model.isShowRoute()) { renderTileRoute(g2di); } if (model.isShowCenter()) { drawCenterPoint(g2di); } // Scale the image back... if (model.isScaleImage()) { tileImage = Scalr.resize(bf, Method.AUTOMATIC, Mode.FIT_EXACT, getWidth(), getHeight(), Scalr.OP_ANTIALIAS); } else { tileImage = bf; } g2di.dispose(); Logger.trace(id + " Cp: " + xyToString()); } public BufferedImage getTileImage() { return tileImage; } /** * Render a tile image Always starts at (0,0) used the default width and height * * @param g2 the Graphic context */ public void drawName(Graphics2D g2) { } protected void drawCenterPoint(Graphics2D g2d) { drawCenterPoint(g2d, Color.magenta); } protected void drawCenterPoint(Graphics2D g2, Color color) { drawCenterPoint(g2, color, 60); } protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { double dX = (renderWidth / 2 - size / 2); double dY = (renderHeight / 2 - size / 2); g2d.setColor(color); g2d.fill(new Ellipse2D.Double(dX, dY, size, size)); } /** * Rotate the tile clockwise 90 deg * * @return the new Orientation */ public Orientation rotate() { Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case EAST -> setOrientation(Orientation.SOUTH); case SOUTH -> setOrientation(Orientation.WEST); case WEST -> setOrientation(Orientation.NORTH); default -> setOrientation(Orientation.EAST); } return model.getTileOrienation(); } public void flipHorizontal() { Orientation tileOrientation = model.getTileOrienation(); if (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) { rotate(); rotate(); } } public void flipVertical() { Orientation tileOrientation = model.getTileOrienation(); if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { rotate(); rotate(); } } @Override public void move(int newX, int newY) { Point cs = LayoutUtil.snapToGrid(newX, newY); setCenter(cs); } protected static void drawRotate(Graphics2D g2d, double x, double y, int angle, String text) { g2d.translate((float) x, (float) y); g2d.rotate(Math.toRadians(angle)); g2d.drawString(text, 0, 0); g2d.rotate(-Math.toRadians(angle)); g2d.translate(-x, -y); } public static BufferedImage flipHorizontally(BufferedImage source) { BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); AffineTransform flip = AffineTransform.getScaleInstance(1, -1); flip.translate(0, -source.getHeight()); AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); op.filter(source, output); return output; } public static BufferedImage flipVertically(BufferedImage source) { BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); AffineTransform flip = AffineTransform.getScaleInstance(-1, 1); flip.translate(-source.getWidth(), 0); AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); op.filter(source, output); return output; } public Set getAltPoints() { return Collections.EMPTY_SET; } public final int getOffsetX() { return offsetX; } public void setOffsetX(int offsetX) { this.offsetX = offsetX; } public final int getOffsetY() { return offsetY; } public void setOffsetY(int offsetY) { this.offsetY = offsetY; } protected BufferedImage createImage() { return new BufferedImage(renderWidth, renderHeight, BufferedImage.TYPE_INT_RGB); } public int getCenterX() { if (tileX > 0) { return this.tileX; } else { return GRID; } } public int getCenterY() { if (tileY > 0) { return this.tileY; } else { return GRID; } } public boolean isDrawName() { return drawName; } public void setDrawName(boolean drawName) { this.drawName = drawName; } public boolean isScaleImage() { return model.isScaleImage(); } public void setScaleImage(boolean scaleImage) { Dimension d; if (scaleImage) { d = new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); } else { d = new Dimension(renderWidth, renderHeight); } setSize(d); setPreferredSize(d); model.setScaleImage(scaleImage); } public boolean isDrawCenterPoint() { return model.isShowCenter(); } public void setDrawCenterPoint(boolean drawCenterPoint) { model.setShowCenter(drawCenterPoint); } @Override public String toString() { return this.getClass().getSimpleName() + " {id: " + this.id + ", orientation: " + getOrientation() + ", direction: " + getDirection() + ", center: " + xyToString() + "}"; } public String xyToString() { return "(" + this.tileX + "," + this.tileY + ")"; } /** * The main route of the tile is horizontal * * @return true when main route goes from East to West or vv */ public boolean isHorizontal() { Orientation tileOrientation = model.getTileOrienation(); return (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) && TileType.CURVED != tileType; } /** * The main route of the tile is vertical * * @return true when main route goes from North to South or vv */ public boolean isVertical() { Orientation tileOrientation = model.getTileOrienation(); return (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) && TileType.CURVED != tileType; } public boolean isJunction() { return TileType.SWITCH == tileType || TileType.CROSS == tileType; } public boolean isBlock() { return TileType.BLOCK == tileType; } public boolean isDirectional() { return TileType.STRAIGHT_DIR == tileType; } /** * The main route of the tile is diagonal * * @return true when main route goes from North to East or West to South and vv */ public boolean isDiagonal() { return TileType.CURVED == tileType; } public boolean isCrossing() { return TileType.CROSSING == tileType; } public List getNeighbours() { return neighbours; } public void setNeighbours(List neighbours) { this.neighbours = neighbours; } public String getIdSuffix(Tile other) { return ""; } public Map getNeighborOrientations() { Map edgeOrientations = new HashMap<>(); Map neighborPoints = getNeighborPoints(); for (Orientation o : Orientation.values()) { edgeOrientations.put(neighborPoints.get(o), o); } return edgeOrientations; } public Map getEdgeOrientations() { Map edgeOrientations = new HashMap<>(); Map edgeConnections = getEdgePoints(); for (Orientation o : Orientation.values()) { edgeOrientations.put(edgeConnections.get(o), o); } return edgeOrientations; } public boolean isAdjacent(Tile other) { boolean adjacent = false; if (other != null) { Collection thisEdgePoints = getEdgePoints().values(); Collection otherEdgePoints = other.getEdgePoints().values(); for (Point p : thisEdgePoints) { adjacent = otherEdgePoints.contains(p); if (adjacent) { break; } } } return adjacent; } /** * When the tile has a specific direction a train may travel,
* then this method will indicate whether the other tile is in on the side where the arrow is pointing to. * * @param other A Tile * @return true where other is on the side of this tile where the arrow points to */ public boolean isArrowDirection(Tile other) { return true; } public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { return AccessoryValue.OFF; } public TileModel getModel() { return model; } public void setModel(TileModel newModel) { TileModel oldModel = getModel(); if (oldModel != null) { oldModel.removeChangeListener(changeListener); oldModel.removeActionListener(actionListener); changeListener = null; actionListener = null; } model = newModel; if (newModel != null) { changeListener = createChangeListener(); actionListener = createActionListener(); newModel.addChangeListener(changeListener); newModel.addActionListener(actionListener); } firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel); if (newModel != oldModel) { revalidate(); repaint(); } } // public TileUI getUI() { // return (TileUI) ui; // } // public void setUI(TileUI ui) { // super.setUI(ui); // } @Override public void updateUI() { } protected ChangeListener createChangeListener() { return getHandler(); } protected ActionListener createActionListener() { return getHandler(); } private Handler getHandler() { if (handler == null) { handler = new Handler(); } return handler; } class Handler implements ActionListener, ChangeListener, Serializable { @Override public void stateChanged(ChangeEvent e) { //Object source = e.getSource(); fireStateChanged(); repaint(); } @Override public void actionPerformed(ActionEvent event) { fireActionPerformed(event); } } protected void fireStateChanged() { Object[] listeners = listenerList.getListenerList(); //reverse order for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == ChangeListener.class) { // Lazily create the event: if (changeEvent == null) { changeEvent = new ChangeEvent(this); } ((ChangeListener) listeners[i + 1]).stateChanged(changeEvent); } } } protected void fireActionPerformed(ActionEvent event) { Object[] listeners = listenerList.getListenerList(); ActionEvent e = null; // reverse for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == ActionListener.class) { // Lazily create the event: if (e == null) { String actionCommand = event.getActionCommand(); //if(actionCommand == null) { // actionCommand = getActionCommand(); //} e = new ActionEvent(Tile.this, ActionEvent.ACTION_PERFORMED, actionCommand, event.getWhen(), event.getModifiers()); } ((ActionListener) listeners[i + 1]).actionPerformed(e); } } } public Rectangle getTileBounds() { if (model.isScaleImage()) { return new Rectangle(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); } else { return new Rectangle(tileX - renderWidth / 2, tileY - renderHeight / 2, renderWidth, renderHeight); } } @Override protected void paintComponent(Graphics g) { long started = System.currentTimeMillis(); Graphics2D g2 = (Graphics2D) g.create(); //Graphics2D g2 = (Graphics2D) g.create(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); drawTile(g2); g2.dispose(); g.drawImage(tileImage, 0, 0, null); long now = System.currentTimeMillis(); Logger.trace(id + " Duration: " + (now - started) + " ms. Cp: " + xyToString() + " O: " + model.getTileOrienation()); } } \ No newline at end of file +/* + * Copyright 2024 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.geom.AffineTransform; +import java.awt.geom.Ellipse2D; +import java.awt.image.AffineTransformOp; +import java.awt.image.BufferedImage; +import java.beans.PropertyChangeListener; +import java.io.Serializable; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.swing.JComponent; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import jcs.entities.AccessoryBean; +import jcs.entities.AccessoryBean.AccessoryValue; +import jcs.entities.AccessoryBean.SignalType; +import jcs.entities.BlockBean; +import jcs.entities.BlockBean.BlockState; +import jcs.entities.LocomotiveBean; +import jcs.entities.SensorBean; +import jcs.entities.TileBean; +import jcs.entities.TileBean.Direction; +import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean.TileType; +import jcs.ui.layout.LayoutUtil; +import static jcs.ui.layout.tiles.Block.BLOCK_HEIGHT; +import static jcs.ui.layout.tiles.Block.BLOCK_WIDTH; +import org.imgscalr.Scalr; +import org.imgscalr.Scalr.Method; +import org.imgscalr.Scalr.Mode; +import org.tinylog.Logger; + +/** + * Basic graphic element to display a track, turnout, etc on the screen.
+ * By default the drawing of a Tile is Horizontal from L to R or West to East.
+ * The default orientation is East. + * + *

+ * The default size of a Tile is 40 tileX 40 pixels.
+ * The center point of a Tile is stored and always snapped to the nearest grid point.
+ * The basic grid is 20x 20 pixels.
+ * + *

+ * A Tile can be rotated (always clockwise).
+ * Rotation will change the orientation from East -> South -> West -> North -> East.
+ * + *

+ * A Tile is rendered to a Buffered Image to speed up the display + */ +public abstract class Tile extends JComponent { //implements TileEventListener { //, ItemSelectable { + + public static final int GRID = 20; + public static final int DEFAULT_WIDTH = GRID * 2; + public static final int DEFAULT_HEIGHT = GRID * 2; + + static final int RENDER_GRID = GRID * 10; + static final int RENDER_WIDTH = RENDER_GRID * 2; + static final int RENDER_HEIGHT = RENDER_GRID * 2; + + public static final Color DEFAULT_BACKGROUND_COLOR = Color.white; + public static final Color DEFAULT_TRACK_COLOR = Color.lightGray; + public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.blue; + public static final Color DEFAULT_SELECTED_COLOR = Color.orange; + public static final Color DEFAULT_WARN_COLOR = Color.red; + + public static final String MODEL_CHANGED_PROPERTY = "model"; + public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled"; + + /** + * The data model that determines the button's state. + */ + protected TileModel model = null; + + protected String id; + protected Integer tileX; + protected Integer tileY; + + protected int renderWidth; + protected int renderHeight; + + //protected Orientation tileOrientation; + protected Direction tileDirection; + + protected TileType tileType; + protected String accessoryId; + protected String sensorId; + + protected AccessoryValue accessoryValue; + protected AccessoryValue routeValue; + + protected SignalType signalType; + protected AccessoryBean.SignalValue signalValue; + + protected TileBean tileBean; + protected AccessoryBean accessoryBean; + protected SensorBean sensorBean; + protected BlockBean blockBean; + + protected List neighbours; + + protected int offsetX = 0; + protected int offsetY = 0; + + protected int renderOffsetX = 0; + protected int renderOffsetY = 0; + + //protected Color selectedColor; + protected Color trackColor; + protected Color trackRouteColor; + protected Orientation incomingSide; + + protected Color backgroundColor; + protected boolean drawName = true; + + protected BufferedImage tileImage; + + protected PropertyChangeListener propertyChangeListener; + + protected ChangeListener changeListener = null; + protected ActionListener actionListener = null; + + protected transient ChangeEvent changeEvent; + + private Handler handler; + + protected Tile(TileType tileType, Orientation orientation, Point center, int width, int height) { + this(tileType, orientation, Direction.CENTER, center.x, center.y, width, height); + } + + protected Tile(TileType tileType, Orientation orientation, int x, int y, int width, int height) { + this(tileType, orientation, Direction.CENTER, x, y, width, height); + } + + protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { + this(tileType, orientation, direction, x, y, width, height, null, null); + } + + protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height, Color backgroundColor, Color selectedColor) { + this.tileType = tileType; + //this.tileOrientation = orientation; + //model.setTileOrienation(orientation); + this.tileDirection = direction; + this.tileX = x; + this.tileY = y; + + setLayout(null); + Dimension d = new Dimension(width, height); + setSize(d); + setPreferredSize(d); + + this.renderWidth = RENDER_WIDTH; + this.renderHeight = RENDER_HEIGHT; + + this.trackColor = DEFAULT_TRACK_COLOR; + this.backgroundColor = backgroundColor; + //this.selectedColor = selectedColor; + + if (this.backgroundColor == null) { + this.backgroundColor = DEFAULT_BACKGROUND_COLOR; + } +// if (this.selectedColor == null) { +// this.selectedColor = DEFAULT_SELECTED_COLOR; +// } + } + + protected Tile(TileBean tileBean) { + this(tileBean, tileWidth(tileBean.getOrientation(), tileBean.getTileType()), tileHeight(tileBean.getOrientation(), tileBean.getTileType())); + } + + protected Tile(TileBean tileBean, int width, int height) { + this.tileBean = tileBean; + //Quick properties + this.id = tileBean.getId(); + this.tileType = tileBean.getTileType(); + //this.tileOrientation = tileBean.getOrientation(); + //this.model.setTileOrienation(tileBean.getOrientation()); + this.tileDirection = tileBean.getDirection(); + this.tileX = tileBean.getX(); + this.tileY = tileBean.getY(); + + this.accessoryId = tileBean.getAccessoryId(); + this.accessoryBean = tileBean.getAccessoryBean(); + this.signalType = tileBean.getSignalType(); + + this.sensorId = tileBean.getSensorId(); + this.sensorBean = tileBean.getSensorBean(); + this.blockBean = tileBean.getBlockBean(); + + setLayout(null); + Dimension d = new Dimension(width, height); + setSize(d); + setPreferredSize(d); + + this.trackColor = DEFAULT_TRACK_COLOR; + this.backgroundColor = DEFAULT_BACKGROUND_COLOR; +// this.selectedColor = DEFAULT_SELECTED_COLOR; + this.renderWidth = RENDER_WIDTH; + this.renderHeight = RENDER_HEIGHT; + } + + protected static int tileWidth(Orientation orientation, TileType tileType) { + if (Orientation.EAST == orientation || Orientation.WEST == orientation) { + if (null == tileType) { + return DEFAULT_WIDTH; + } else { + return switch (tileType) { + case BLOCK -> + BLOCK_WIDTH; + case CROSS -> + DEFAULT_WIDTH * 2; + default -> + DEFAULT_WIDTH; + }; + } + } else { + return DEFAULT_WIDTH; + } + } + + protected static int tileHeight(Orientation orientation, TileType tileType) { + if (Orientation.EAST == orientation || Orientation.WEST == orientation) { + return DEFAULT_HEIGHT; + } else { + if (null == tileType) { + return DEFAULT_HEIGHT; + } else { + return switch (tileType) { + case BLOCK -> + BLOCK_HEIGHT; + case CROSS -> + DEFAULT_HEIGHT * 2; + default -> + DEFAULT_HEIGHT; + }; + } + } + } + + protected void populateModel() { + if (this.blockBean != null) { + this.model.setBlockState(this.blockBean.getBlockState()); + this.model.setLocomotive(this.blockBean.getLocomotive()); + this.model.setArrivalSuffix(this.blockBean.getArrivalSuffix()); + this.model.setLogicalDirection(LocomotiveBean.Direction.get(this.blockBean.getLogicalDirection())); + } + } + + public TileBean getTileBean() { + if (tileBean == null) { + tileBean = new TileBean(); + tileBean.setId(this.id); + tileBean.setX(this.tileX); + tileBean.setY(this.tileY); + tileBean.setTileType(this.tileType); + //tileBean.setTileOrientation(this.tileOrientation.getOrientation()); + tileBean.setTileOrientation(this.model.getTileOrienation().getOrientation()); + + tileBean.setTileDirection(this.tileDirection.getDirection()); + tileBean.setSignalType(this.signalType); + tileBean.setAccessoryId(this.accessoryId); + tileBean.setSensorId(this.sensorId); + tileBean.setAccessoryBean(this.accessoryBean); + tileBean.setSensorBean(this.sensorBean); + tileBean.setBlockBean(this.blockBean); + } + return tileBean; + } + + public boolean isSelected() { + return model.isSelected(); + } + + public void setSelected(boolean b) { + //boolean oldValue = isSelected(); + model.setSelected(b); + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public SignalType getSignalType() { + return signalType; + } + + public void setSignalType(SignalType signalType) { + this.signalType = signalType; + } + + public Integer getTileX() { + return tileX; + } + + public Integer getTileY() { + return tileY; + } + + public Point getCenter() { + return new Point(this.tileX, this.tileY); + } + + public void setCenter(Point center) { + tileX = center.x; + tileY = center.y; + if (tileBean != null) { + tileBean.setCenter(center); + } + Logger.trace(id + " Cp: " + xyToString()); + } + + public Orientation getOrientation() { + //return tileOrientation; + return model.getTileOrienation(); + } + + public void setOrientation(Orientation orientation) { + //this.tileOrientation = orientation; + model.setTileOrienation(orientation); + if (tileBean != null) { + tileBean.setOrientation(orientation); + } + } + + public Direction getDirection() { + return tileDirection; + } + + public void setDirection(Direction direction) { + this.tileDirection = direction; + if (tileBean != null) { + tileBean.setDirection(direction); + } + } + + public String getAccessoryId() { + return accessoryId; + } + + public void setAccessoryId(String accessoryId) { + this.accessoryId = accessoryId; + if (tileBean != null) { + tileBean.setAccessoryId(accessoryId); + } + } + + public String getSensorId() { + return sensorId; + } + + public void setSensorId(String sensorId) { + this.sensorId = sensorId; + } + + public boolean isActive() { + return model.isSensorActive(); + } + + public void setActive(boolean active) { + model.setSensorActive(active); + } + + public BlockState getBlockState() { + return model.getBlockState(); + } + + public void setBlockState(BlockState blockState) { + if (blockBean != null) { + blockBean.setBlockState(blockState); + LocomotiveBean locomotive = model.getLocomotive(); + model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (blockState == BlockState.OCCUPIED || blockState == BlockState.INBOUND || blockState == BlockState.OUTBOUND)); + } + model.setBlockState(blockState); + } + + public String getDepartureSuffix() { + return model.getDepartureSuffix(); + } + + public void setDepartureSuffix(String suffix) { + if (blockBean != null) { + blockBean.setDepartureSuffix(suffix); + } + model.setDepartureSuffix(suffix); + } + + public boolean isReverseArrival() { + return model.isReverseArrival(); + } + + public void setReverseArrival(boolean reverseArrival) { + if (blockBean != null) { + blockBean.setReverseArrival(reverseArrival); + } + model.setReverseArrival(reverseArrival); + } + + public LocomotiveBean.Direction getLogicalDirection() { + return model.getLogicalDirection(); + } + + public void setLogicalDirection(LocomotiveBean.Direction logicalDirection) { + if (blockBean != null) { + blockBean.setLogicalDirection(logicalDirection.getDirection()); + } + model.setLogicalDirection(logicalDirection); + } + + public LocomotiveBean getLocomotive() { + return model.getLocomotive(); + } + + public void setLocomotive(LocomotiveBean locomotive) { + if (blockBean != null) { + blockBean.setLocomotive(locomotive); + model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (model.getBlockState() == BlockState.OCCUPIED || model.getBlockState() == BlockState.INBOUND || model.getBlockState() == BlockState.OUTBOUND)); + } + + model.setLocomotive(locomotive); + } + + public AccessoryBean getAccessoryBean() { + return accessoryBean; + } + + public void setAccessoryBean(AccessoryBean accessoryBean) { + this.accessoryBean = accessoryBean; + + if (accessoryBean != null) { + accessoryId = accessoryBean.getId(); + signalValue = accessoryBean.getSignalValue(); + signalType = SignalType.getSignalType(accessoryBean.getType()); + } else { + accessoryId = null; + signalType = SignalType.NONE; + signalValue = AccessoryBean.SignalValue.OFF; + } + } + + public AccessoryValue getAccessoryValue() { + if (this.accessoryValue == null) { + return AccessoryValue.OFF; + } else { + return accessoryValue; + } + } + + public void setAccessoryValue(AccessoryValue value) { + this.accessoryValue = value; + repaint(); + } + + public AccessoryValue getRouteValue() { + if (routeValue == null) { + return AccessoryValue.OFF; + } else { + return routeValue; + } + } + + public void setRouteValue(AccessoryValue value) { + this.routeValue = value; + repaint(); + } + + public AccessoryBean.SignalValue getSignalValue() { + return signalValue; + } + + public void setSignalValue(AccessoryBean.SignalValue signalValue) { + this.signalValue = signalValue; + repaint(); + } + + public SensorBean getSensorBean() { + return sensorBean; + } + + public void setSensorBean(SensorBean sensorBean) { + this.sensorBean = sensorBean; + } + + public BlockBean getBlockBean() { + return blockBean; + } + + public void setBlockBean(BlockBean blockBean) { + this.blockBean = blockBean; + } + + public void setRenderWidth(int renderWidth) { + this.renderWidth = renderWidth; + } + + public void setRenderHeight(int renderHeight) { + this.renderHeight = renderHeight; + } + + public int getRenderOffsetX() { + return renderOffsetX; + } + + public void setRenderOffsetX(int renderOffsetX) { + this.renderOffsetX = renderOffsetX; + } + + public int getRenderOffsetY() { + return renderOffsetY; + } + + public void setRenderOffsetY(int renderOffsetY) { + this.renderOffsetY = renderOffsetY; + } + + public TileBean.TileType getTileType() { + return this.tileType; + } + + public final void setTileType(TileType tileType) { + this.tileType = tileType; + } + + public Color getTrackColor() { + return trackColor; + } + + public final void setTrackColor(Color trackColor) { + this.trackColor = trackColor; + } + + public Color getTrackRouteColor() { + return trackRouteColor; + } + + public void setTrackRouteColor(Color trackRouteColor) { + this.trackRouteColor = trackRouteColor; + } + + public Color getSelectedColor() { + return model.getSelectedColor(); + } + + public void setSelectedColor(Color selectedColor) { + this.model.setSelectedColor(selectedColor); + } + + public Orientation getIncomingSide() { + return incomingSide; + } + + public void setIncomingSide(Orientation incomingSide) { + this.incomingSide = incomingSide; + } + + public Color getBackgroundColor() { + return backgroundColor; + } + + public void setBackgroundColor(Color backgroundColor) { + this.backgroundColor = backgroundColor; + } + + public boolean isDrawRoute() { + return model.isShowRoute(); + } + + public void setDrawRoute(boolean drawRoute) { + this.model.setShowRoute(drawRoute); + } + + public int getRenderWidth() { + return renderWidth; + } + + public int getRenderHeight() { + return renderHeight; + } + + abstract void renderTile(Graphics2D g2d); + + abstract void renderTileRoute(Graphics2D g2d); + + public abstract Map getNeighborPoints(); + + public abstract Map getEdgePoints(); + + public abstract Set getAllPoints(); + + /** + * Draw the Tile + * + * @param g2d The graphics handle + */ + public void drawTile(Graphics2D g2d) { + // by default and image is rendered in the EAST orientation + Orientation tileOrientation = model.getTileOrienation(); +// if (tileOrientation == null) { +// tileOrientation = Orientation.EAST; +// } + + BufferedImage bf = createImage(); + Graphics2D g2di = bf.createGraphics(); + + //Avoid errors + if (model.isShowRoute() && incomingSide == null) { + incomingSide = getOrientation(); + } + + if (model.isSelected()) { + g2di.setBackground(model.getSelectedColor()); + } else { + g2di.setBackground(backgroundColor); + } + + g2di.clearRect(0, 0, renderWidth, renderHeight); + int ox = 0, oy = 0; + + AffineTransform trans = new AffineTransform(); + switch (tileOrientation) { + case SOUTH -> { + trans.rotate(Math.PI / 2, renderWidth / 2, renderHeight / 2); + ox = (renderHeight - renderWidth) / 2; + oy = (renderWidth - renderHeight) / 2; + trans.translate(-ox, -oy); + } + case WEST -> { + trans.rotate(Math.PI, renderWidth / 2, renderHeight / 2); + trans.translate(ox, oy); + } + case NORTH -> { + trans.rotate(-Math.PI / 2, renderWidth / 2, renderHeight / 2); + ox = (renderHeight - renderWidth) / 2; + oy = (renderWidth - renderHeight) / 2; + trans.translate(-ox, -oy); + } + default -> { + trans.rotate(0.0, this.renderWidth / 2, this.renderHeight / 2); + trans.translate(ox, oy); + } + } + + //Logger.trace(tileOrientation.getOrientation() + " renderWidth: " + renderWidth + " renderHeight: " + renderHeight + " CP: (" + renderWidth / 2 + "," + renderHeight / 2 + ")"); + //Logger.trace(tileOrientation.getOrientation() + " ox: " + ox + " oy: " + oy); + g2di.setTransform(trans); + + renderTile(g2di); + + if (model.isShowRoute()) { + renderTileRoute(g2di); + } + + if (model.isShowCenter()) { + drawCenterPoint(g2di); + } + + // Scale the image back... + if (model.isScaleImage()) { + tileImage = Scalr.resize(bf, Method.AUTOMATIC, Mode.FIT_EXACT, getWidth(), getHeight(), Scalr.OP_ANTIALIAS); + } else { + tileImage = bf; + } + + g2di.dispose(); + + Logger.trace(id + " Cp: " + xyToString()); + + } + + public BufferedImage getTileImage() { + return tileImage; + } + + /** + * Render a tile image Always starts at (0,0) used the default width and height + * + * @param g2 the Graphic context + */ + public void drawName(Graphics2D g2) { + } + + protected void drawCenterPoint(Graphics2D g2d) { + drawCenterPoint(g2d, Color.magenta); + } + + protected void drawCenterPoint(Graphics2D g2, Color color) { + drawCenterPoint(g2, color, 60); + } + + protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { + double dX = (renderWidth / 2 - size / 2); + double dY = (renderHeight / 2 - size / 2); + + g2d.setColor(color); + g2d.fill(new Ellipse2D.Double(dX, dY, size, size)); + } + + /** + * Rotate the tile clockwise 90 deg + * + * @return the new Orientation + */ + public Orientation rotate() { + Orientation tileOrientation = model.getTileOrienation(); + switch (tileOrientation) { + case EAST -> + setOrientation(Orientation.SOUTH); + case SOUTH -> + setOrientation(Orientation.WEST); + case WEST -> + setOrientation(Orientation.NORTH); + default -> + setOrientation(Orientation.EAST); + } + return model.getTileOrienation(); + } + + public void flipHorizontal() { + Orientation tileOrientation = model.getTileOrienation(); + if (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) { + rotate(); + rotate(); + } + } + + public void flipVertical() { + Orientation tileOrientation = model.getTileOrienation(); + if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { + rotate(); + rotate(); + } + } + + @Override + public void move(int newX, int newY) { + Point cs = LayoutUtil.snapToGrid(newX, newY); + setCenter(cs); + } + + protected static void drawRotate(Graphics2D g2d, double x, double y, int angle, String text) { + g2d.translate((float) x, (float) y); + g2d.rotate(Math.toRadians(angle)); + g2d.drawString(text, 0, 0); + g2d.rotate(-Math.toRadians(angle)); + g2d.translate(-x, -y); + } + + public static BufferedImage flipHorizontally(BufferedImage source) { + BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); + + AffineTransform flip = AffineTransform.getScaleInstance(1, -1); + flip.translate(0, -source.getHeight()); + AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); + + op.filter(source, output); + + return output; + } + + public static BufferedImage flipVertically(BufferedImage source) { + BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); + + AffineTransform flip = AffineTransform.getScaleInstance(-1, 1); + flip.translate(-source.getWidth(), 0); + AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); + + op.filter(source, output); + + return output; + } + + public Set getAltPoints() { + return Collections.EMPTY_SET; + } + + public final int getOffsetX() { + return offsetX; + } + + public void setOffsetX(int offsetX) { + this.offsetX = offsetX; + } + + public final int getOffsetY() { + return offsetY; + } + + public void setOffsetY(int offsetY) { + this.offsetY = offsetY; + } + + protected BufferedImage createImage() { + return new BufferedImage(renderWidth, renderHeight, BufferedImage.TYPE_INT_RGB); + } + + public int getCenterX() { + if (tileX > 0) { + return this.tileX; + } else { + return GRID; + } + } + + public int getCenterY() { + if (tileY > 0) { + return this.tileY; + } else { + return GRID; + } + } + + public boolean isDrawName() { + return drawName; + } + + public void setDrawName(boolean drawName) { + this.drawName = drawName; + } + + public boolean isScaleImage() { + return model.isScaleImage(); + } + + public void setScaleImage(boolean scaleImage) { + Dimension d; + if (scaleImage) { + d = new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); + } else { + d = new Dimension(renderWidth, renderHeight); + } + + setSize(d); + setPreferredSize(d); + + model.setScaleImage(scaleImage); + } + + public boolean isDrawCenterPoint() { + return model.isShowCenter(); + } + + public void setDrawCenterPoint(boolean drawCenterPoint) { + model.setShowCenter(drawCenterPoint); + } + + @Override + public String toString() { + return this.getClass().getSimpleName() + + " {id: " + + this.id + + ", orientation: " + + getOrientation() + + ", direction: " + + getDirection() + + ", center: " + + xyToString() + + "}"; + } + + public String xyToString() { + return "(" + this.tileX + "," + this.tileY + ")"; + } + + /** + * The main route of the tile is horizontal + * + * @return true when main route goes from East to West or vv + */ + public boolean isHorizontal() { + Orientation tileOrientation = model.getTileOrienation(); + return (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) && TileType.CURVED != tileType; + } + + /** + * The main route of the tile is vertical + * + * @return true when main route goes from North to South or vv + */ + public boolean isVertical() { + Orientation tileOrientation = model.getTileOrienation(); + return (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) && TileType.CURVED != tileType; + } + + public boolean isJunction() { + return TileType.SWITCH == tileType || TileType.CROSS == tileType; + } + + public boolean isBlock() { + return TileType.BLOCK == tileType; + } + + public boolean isDirectional() { + return TileType.STRAIGHT_DIR == tileType; + } + + /** + * The main route of the tile is diagonal + * + * @return true when main route goes from North to East or West to South and vv + */ + public boolean isDiagonal() { + return TileType.CURVED == tileType; + } + + public boolean isCrossing() { + return TileType.CROSSING == tileType; + } + + public List getNeighbours() { + return neighbours; + } + + public void setNeighbours(List neighbours) { + this.neighbours = neighbours; + } + + public String getIdSuffix(Tile other) { + return ""; + } + + public Map getNeighborOrientations() { + Map edgeOrientations = new HashMap<>(); + + Map neighborPoints = getNeighborPoints(); + + for (Orientation o : Orientation.values()) { + edgeOrientations.put(neighborPoints.get(o), o); + } + return edgeOrientations; + } + + public Map getEdgeOrientations() { + Map edgeOrientations = new HashMap<>(); + + Map edgeConnections = getEdgePoints(); + + for (Orientation o : Orientation.values()) { + edgeOrientations.put(edgeConnections.get(o), o); + } + return edgeOrientations; + } + + public boolean isAdjacent(Tile other) { + boolean adjacent = false; + + if (other != null) { + Collection thisEdgePoints = getEdgePoints().values(); + Collection otherEdgePoints = other.getEdgePoints().values(); + + for (Point p : thisEdgePoints) { + adjacent = otherEdgePoints.contains(p); + if (adjacent) { + break; + } + } + } + + return adjacent; + } + + /** + * When the tile has a specific direction a train may travel,
+ * then this method will indicate whether the other tile is in on the side where the arrow is pointing to. + * + * @param other A Tile + * @return true where other is on the side of this tile where the arrow points to + */ + public boolean isArrowDirection(Tile other) { + return true; + } + + public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { + return AccessoryValue.OFF; + } + + public TileModel getModel() { + return model; + } + + public void setModel(TileModel newModel) { + TileModel oldModel = getModel(); + + if (oldModel != null) { + oldModel.removeChangeListener(changeListener); + oldModel.removeActionListener(actionListener); + changeListener = null; + actionListener = null; + } + + model = newModel; + + if (newModel != null) { + changeListener = createChangeListener(); + actionListener = createActionListener(); + + newModel.addChangeListener(changeListener); + newModel.addActionListener(actionListener); + } + + firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel); + if (newModel != oldModel) { + revalidate(); + repaint(); + } + } + +// public TileUI getUI() { +// return (TileUI) ui; +// } +// public void setUI(TileUI ui) { +// super.setUI(ui); +// } + @Override + public void updateUI() { + } + + protected ChangeListener createChangeListener() { + return getHandler(); + } + + protected ActionListener createActionListener() { + return getHandler(); + } + + private Handler getHandler() { + if (handler == null) { + handler = new Handler(); + } + return handler; + } + + class Handler implements ActionListener, ChangeListener, Serializable { + + @Override + public void stateChanged(ChangeEvent e) { + //Object source = e.getSource(); + + fireStateChanged(); + repaint(); + } + + @Override + public void actionPerformed(ActionEvent event) { + fireActionPerformed(event); + } + } + + protected void fireStateChanged() { + Object[] listeners = listenerList.getListenerList(); + //reverse order + for (int i = listeners.length - 2; i >= 0; i -= 2) { + if (listeners[i] == ChangeListener.class) { + // Lazily create the event: + if (changeEvent == null) { + changeEvent = new ChangeEvent(this); + } + ((ChangeListener) listeners[i + 1]).stateChanged(changeEvent); + } + } + } + + protected void fireActionPerformed(ActionEvent event) { + Object[] listeners = listenerList.getListenerList(); + ActionEvent e = null; + // reverse + for (int i = listeners.length - 2; i >= 0; i -= 2) { + if (listeners[i] == ActionListener.class) { + // Lazily create the event: + if (e == null) { + String actionCommand = event.getActionCommand(); + //if(actionCommand == null) { + // actionCommand = getActionCommand(); + //} + e = new ActionEvent(Tile.this, ActionEvent.ACTION_PERFORMED, actionCommand, event.getWhen(), event.getModifiers()); + } + ((ActionListener) listeners[i + 1]).actionPerformed(e); + } + } + } + + public Rectangle getTileBounds() { + if (model.isScaleImage()) { + return new Rectangle(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); + } else { + return new Rectangle(tileX - renderWidth / 2, tileY - renderHeight / 2, renderWidth, renderHeight); + } + } + + @Override + protected void paintComponent(Graphics g) { + long started = System.currentTimeMillis(); + + Graphics2D g2 = (Graphics2D) g.create(); + //Graphics2D g2 = (Graphics2D) g.create(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); + drawTile(g2); + g2.dispose(); + + g.drawImage(tileImage, 0, 0, null); + + long now = System.currentTimeMillis(); + Logger.trace(id + " Duration: " + (now - started) + " ms. Cp: " + xyToString() + " O: " + model.getTileOrienation()); + } + +} diff --git a/src/main/java/jcs/ui/layout/tiles/TileFactory.java b/src/main/java/jcs/ui/layout/tiles/TileFactory.java index f1522721..40d6db61 100755 --- a/src/main/java/jcs/ui/layout/tiles/TileFactory.java +++ b/src/main/java/jcs/ui/layout/tiles/TileFactory.java @@ -225,7 +225,6 @@ public static Tile createTile(TileBean tileBean, boolean showValues) { * @param orientation whether the orientation of the Tile is EAST, WEST, NORTH or SOUTH * @param x the tile center X * @param y the tile center Y - * @param drawOutline whether the outline of the tile must be rendered * @return a Tile object */ public static Tile createTile(TileBean.TileType tileType, Orientation orientation, int x, int y) { diff --git a/src/main/java/jcs/ui/layout/tiles/TileModel.java b/src/main/java/jcs/ui/layout/tiles/TileModel.java index 84b78bf0..4280d06e 100644 --- a/src/main/java/jcs/ui/layout/tiles/TileModel.java +++ b/src/main/java/jcs/ui/layout/tiles/TileModel.java @@ -15,6 +15,7 @@ */ package jcs.ui.layout.tiles; +import java.awt.Color; import java.awt.event.ActionListener; import java.io.Serializable; import javax.swing.event.ChangeListener; @@ -32,6 +33,10 @@ public interface TileModel extends Serializable { public void setSelected(boolean selected); + Color getSelectedColor(); + + public void setSelectedColor(Color selectedColor); + boolean isScaleImage(); public void setScaleImage(boolean scaleImage); From 1cbd14c92ec7b0bdafe5373c537a9b301dc4b325 Mon Sep 17 00:00:00 2001 From: fja-itank Date: Wed, 29 Jan 2025 20:14:50 +0100 Subject: [PATCH 11/70] Adding tests for checking Tile occupancy in the edit screen --- .../commandStation/autopilot/AutoPilot.java | 2 +- .../autopilot/state/Dispatcher.java | 2 +- src/main/java/jcs/ui/layout/LayoutCanvas.form | 234 +--- src/main/java/jcs/ui/layout/LayoutCanvas.java | 114 +- src/main/java/jcs/ui/layout/RoutesDialog.java | 1 + src/main/java/jcs/ui/layout/TileCache.java | 406 ------ .../ui/layout/dialogs/BlockControlDialog.java | 2 +- .../jcs/ui/layout/dialogs/BlockDialog.java | 2 +- src/main/java/jcs/ui/layout/tiles/Block.java | 2 +- src/main/java/jcs/ui/layout/tiles/Cross.java | 669 +--------- .../java/jcs/ui/layout/tiles/Crossing.java | 150 +-- src/main/java/jcs/ui/layout/tiles/Curved.java | 162 +-- src/main/java/jcs/ui/layout/tiles/End.java | 148 +-- .../java/jcs/ui/layout/tiles/Straight.java | 148 +-- src/main/java/jcs/ui/layout/tiles/Switch.java | 362 +----- src/main/java/jcs/ui/layout/tiles/Tile.java | 1134 +---------------- .../java/jcs/ui/layout/tiles/TileCache.java | 1 + .../java/jcs/ui/layout/tiles/TileFactory.java | 293 +---- 18 files changed, 40 insertions(+), 3792 deletions(-) delete mode 100644 src/main/java/jcs/ui/layout/TileCache.java create mode 100644 src/main/java/jcs/ui/layout/tiles/TileCache.java diff --git a/src/main/java/jcs/commandStation/autopilot/AutoPilot.java b/src/main/java/jcs/commandStation/autopilot/AutoPilot.java index f3bfb91c..23ce3b8b 100644 --- a/src/main/java/jcs/commandStation/autopilot/AutoPilot.java +++ b/src/main/java/jcs/commandStation/autopilot/AutoPilot.java @@ -37,7 +37,7 @@ import jcs.entities.RouteBean; import jcs.entities.SensorBean; import jcs.persistence.PersistenceFactory; -import jcs.ui.layout.TileCache; +import jcs.ui.layout.tiles.TileCache; import jcs.ui.layout.events.TileEvent; import org.tinylog.Logger; diff --git a/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java b/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java index d474b4da..70801fc9 100644 --- a/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java +++ b/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java @@ -32,7 +32,7 @@ import jcs.entities.RouteElementBean; import jcs.entities.TileBean; import jcs.persistence.PersistenceFactory; -import jcs.ui.layout.TileCache; +import jcs.ui.layout.tiles.TileCache; import jcs.ui.layout.events.TileEvent; import org.tinylog.Logger; diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.form b/src/main/java/jcs/ui/layout/LayoutCanvas.form index 884eba14..3a7b262c 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.form +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.form @@ -1,233 +1 @@ - - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
\ No newline at end of file diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.java b/src/main/java/jcs/ui/layout/LayoutCanvas.java index fb3813da..edc748ef 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.java +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.java @@ -73,6 +73,8 @@ import jcs.ui.layout.tiles.Switch; import jcs.ui.layout.tiles.Tile; import jcs.ui.layout.tiles.TileFactory; +import jcs.ui.layout.tiles.TileCache; +import static jcs.ui.layout.tiles.TileCache.findTile; import org.tinylog.Logger; /** @@ -244,12 +246,12 @@ void loadLayoutInBackground() { } private void loadTiles() { - TileCache.loadTiles(); - removeAll(); + List tiles = TileCache.loadTiles(); + removeAll(); selectedTile = null; - for (Tile tile : TileCache.tiles.values()) { + for (Tile tile : tiles) { add(tile); tile.setDrawCenterPoint(!readonly); } @@ -324,7 +326,7 @@ private void mousePressedAction(MouseEvent evt) { } } default -> { - Logger.trace((selectedTile != null ? "Selected tile: " + selectedTile.getId() + ", " + selectedTile.xyToString() : "No tile selected")); + Logger.trace((selectedTile != null ? "Selected tile: " + selectedTile.getId() + ", " + selectedTile.xyToString() : "No tile @ (" + snapPoint.x + "," + snapPoint.y + ")")); if (MouseEvent.BUTTON3 == evt.getButton()) { showOperationsPopupMenu(selectedTile, snapPoint); } @@ -334,20 +336,18 @@ private void mousePressedAction(MouseEvent evt) { private Tile addTile(Point p, TileType tileType, Orientation orientation, Direction direction, boolean selected, boolean showCenter) { Logger.trace("Adding: " + tileType + " @ " + p + " O: " + orientation + " D: " + direction); - Point chkp = TileCache.checkAvailable(p, orientation); - - Tile tile = TileFactory.createTile(tileType, orientation, direction, chkp); - tile.setSelected(selected); - tile.setDrawCenterPoint(showCenter); + Tile tile = TileFactory.createTile(tileType, orientation, direction, p); - //Can the tile be placed, keeping in mind the extra points - boolean canBeAdded = !TileCache.checkTileOccupation(tile); - - if (canBeAdded) { + if (TileCache.canMoveTo(tile, p)) { + tile.setSelected(selected); + tile.setDrawCenterPoint(showCenter); add(tile); TileCache.addAndSaveTile(tile); return tile; } else { + Tile occ = TileCache.findTile(p); + Logger.trace("Can't add tile " + tile.getId() + " on " + tile.xyToString() + " Is occupied by " + occ.getId()); + TileFactory.rollback(tile); return null; } } @@ -372,15 +372,11 @@ private void mouseDragAction(MouseEvent evt) { setComponentZOrder(selectedTile, 0); int curX = snapPoint.x - Tile.GRID; int curY = snapPoint.y - Tile.GRID; - - //check overlap in the cache - //This wil only chek the snappint, whic incas of a moving Block or Cross in not enough! - //TODO ! Needed are the alt point of the moved block or Cross. - //How to do this? - if (TileCache.containsPoint(snapPoint)) { - selectedTile.setSelectedColor(Tile.DEFAULT_WARN_COLOR); - } else { + + if (TileCache.canMoveTo(selectedTile, snapPoint)) { selectedTile.setSelectedColor(Tile.DEFAULT_SELECTED_COLOR); + } else { + selectedTile.setSelectedColor(Tile.DEFAULT_WARN_COLOR); } selectedTile.setBounds(curX, curY, selectedTile.getWidth(), selectedTile.getHeight()); @@ -390,79 +386,17 @@ private void mouseDragAction(MouseEvent evt) { private void mouseReleasedAction(MouseEvent evt) { Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); - boolean snapPointOccupied = TileCache.containsPoint(snapPoint); - if (!Mode.CONTROL.equals(mode) && MouseEvent.BUTTON1 == evt.getButton() && selectedTile != null) { - - boolean destinationOccupied = TileCache.containsPoints(selectedTile.getAllPoints()); + if (!Mode.CONTROL.equals(mode) && MouseEvent.BUTTON1 == evt.getButton() && selectedTile != null && !selectedTile.getCenter().equals(snapPoint)) { - - Logger.trace("Selected tile: " + selectedTile.getId() + ", " + selectedTile.xyToString()+" Dest Occ "+destinationOccupied); - - if (destinationOccupied || snapPointOccupied) { - Logger.debug("Can't move tile " + selectedTile.getId() + " from " + selectedTile.xyToString() + " to (" + snapPoint.x + "," + snapPoint.y + ")!"); + if (TileCache.canMoveTo(selectedTile, snapPoint)) { + TileCache.moveTo(selectedTile, snapPoint); + } else { + Tile occ = TileCache.findTile(snapPoint); + Logger.trace("Can't Move tile " + selectedTile.getId() + " from " + selectedTile.xyToString() + " to (" + snapPoint.x + "," + snapPoint.y + ") Is occupied by " + occ.getId()); - //selectedTile.setBounds(selectedTile.getTileX(), selectedTile.getTileY(), selectedTile.getWidth(), selectedTile.getHeight()); - selectedTile.setBounds(selectedTile.getTileBounds()); selectedTile.setSelectedColor(Tile.DEFAULT_SELECTED_COLOR); - - } else { - TileCache.moveTile(snapPoint, selectedTile); + selectedTile.setBounds(selectedTile.getTileBounds()); } - -// Point tp = selectedTile.getCenter(); -// if (!tp.equals(snapPoint)) { -// -// Logger.tag("Moving Tile from " + tp + " to " + snapPoint + " Tile to move: " + selectedTile); -// //Check if new position is free -// boolean canMove = true; -// if (TileCache.containsPoint(snapPoint)) { -// Tile tile = TileCache.findTile(snapPoint); -// if (selectedTile.getId().equals(tile.getId())) { -// //same tile so we can move -// canMove = true; -// } else { -// Logger.debug("Position " + snapPoint + " is occupied with tile: " + tile + ", can't move tile " + selectedTile.getId()); -// canMove = false; -// } -// } -// -// if (canMove) { -// //Remove the original tile center from the tiles -// Tile movingTile = TileCache.tiles.remove(tp); -// if (movingTile != null) { -// //Also remove from the alt points -// Point oldCenter = movingTile.getCenter(); -// Set oldAltPoints = movingTile.getAltPoints(); -// //Logger.trace("Removing " + oldAltPoints.size() + " alt tile points"); -// for (Point ep : oldAltPoints) { -// TileCache.altTiles.remove(ep); -// TileCache.tiles.remove(ep); -// } -// -// //Set the new center position -// movingTile.setCenter(snapPoint); -// //Check again, needed for tiles which are longer then 1 square, like a block -// if (!TileCache.checkTileOccupation(movingTile)) { -// Logger.trace("Moved Tile " + movingTile.getId() + " from " + tp + " to " + snapPoint + "..."); -// TileCache.tiles.put(snapPoint, movingTile); -// for (Point ep : movingTile.getAltPoints()) { -// TileCache.altTiles.put(ep, movingTile); -// } -// } else { -// //Do not move Tile, put back where it was -// movingTile.setCenter(oldCenter); -// TileCache.tiles.put(oldCenter, movingTile); -// for (Point ep : movingTile.getAltPoints()) { -// TileCache.altTiles.put(ep, movingTile); -// } -// } -// -// TileCache.saveTile(movingTile); -// } -// //TODO is this needed? - // repaint(); - // } - // } } } diff --git a/src/main/java/jcs/ui/layout/RoutesDialog.java b/src/main/java/jcs/ui/layout/RoutesDialog.java index 742a03e0..6f564d26 100644 --- a/src/main/java/jcs/ui/layout/RoutesDialog.java +++ b/src/main/java/jcs/ui/layout/RoutesDialog.java @@ -15,6 +15,7 @@ */ package jcs.ui.layout; +import jcs.ui.layout.tiles.TileCache; import java.awt.Color; import java.awt.Component; import java.awt.Point; diff --git a/src/main/java/jcs/ui/layout/TileCache.java b/src/main/java/jcs/ui/layout/TileCache.java deleted file mode 100644 index c44f5909..00000000 --- a/src/main/java/jcs/ui/layout/TileCache.java +++ /dev/null @@ -1,406 +0,0 @@ -/* - * Copyright 2025 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout; - -import jcs.ui.layout.tiles.*; -import java.awt.Point; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; -import jcs.entities.AccessoryBean.AccessoryValue; -import jcs.entities.AccessoryBean.SignalValue; -import jcs.entities.TileBean; -import jcs.entities.TileBean.Orientation; -import static jcs.entities.TileBean.Orientation.EAST; -import static jcs.entities.TileBean.Orientation.SOUTH; -import static jcs.entities.TileBean.Orientation.WEST; -import static jcs.entities.TileBean.TileType.CROSS; -import jcs.persistence.PersistenceFactory; -import jcs.ui.layout.events.TileEvent; -import jcs.ui.layout.events.TileEventListener; -import org.tinylog.Logger; - -/** - * Factory object to create Tiles and cache tiles - * - * @author frans - */ -public class TileCache { - - private static final Map tileEventListeners = new HashMap<>(); - - private static boolean drawCenterPoint; - private static boolean showValues; - - static final Map tiles = new HashMap<>(); - static final Map points = new HashMap<>(); - static final Map altTiles = new HashMap<>(); - - private TileCache() { - } - -// static void setDrawCenterPoint(boolean drawCenterPoint) { -// TileCache.drawCenterPoint = drawCenterPoint; -// -// for (Tile tile : tiles.values()) { -// //if (tile instanceof AbstractTile abstractTile) { -// tile.setDrawCenterPoint(drawCenterPoint); -// //} -// } -// } - public static void setShowValues(boolean showValues) { - TileCache.showValues = showValues; - - for (Tile tile : tiles.values()) { - TileBean.TileType tileType = tile.getTileType(); - //AbstractTile tile = null; - switch (tileType) { - case SWITCH -> { - if (showValues && ((Switch) tile).getTileBean().getAccessoryBean() != null) { - tile.setAccessoryValue(tile.getTileBean().getAccessoryBean().getAccessoryValue()); - } else { - tile.setAccessoryValue(AccessoryValue.OFF); - } - } - case CROSS -> { - if (showValues && ((Cross) tile).getTileBean().getAccessoryBean() != null) { - tile.setAccessoryValue(tile.getTileBean().getAccessoryBean().getAccessoryValue()); - } else { - tile.setAccessoryValue(AccessoryValue.OFF); - } - } - case SIGNAL -> { - if (showValues && ((Signal) tile).getTileBean().getAccessoryBean() != null) { - tile.setSignalValue(tile.getTileBean().getAccessoryBean().getSignalValue()); - } else { - tile.setSignalValue(SignalValue.OFF); - } - } - case SENSOR -> { - if (showValues && ((Sensor) tile).getTileBean().getSensorBean() != null) { - tile.setActive(tile.getTileBean().getSensorBean().isActive()); - } else { - tile.setActive(false); - } - } - case BLOCK -> { - } - } - } - } - - static void loadTiles() { - List tileBeans = PersistenceFactory.getService().getTileBeans(); - - tileEventListeners.clear(); - altTiles.clear(); - tiles.clear(); - - for (TileBean tb : tileBeans) { - Tile tile = TileFactory.createTile(tb, showValues); - //tile.setPropertyChangeListener(listener); - tiles.put(tile.getCenter(), tile); - points.put(tile.getId(), tile.getCenter()); - - //addTileEventListener((TileEventListener) tile); - //Alternative point(s) to be able to find all points - if (!tile.getAltPoints().isEmpty()) { - Set alt = tile.getAltPoints(); - for (Point ap : alt) { - altTiles.put(ap, tile); - } - } - } - - Logger.trace("Loaded " + tiles.size() + " Tiles..."); - } - - static List getTiles() { - return tiles.values().stream().collect(Collectors.toList()); - } - - static void addAndSaveTile(Tile tile) { - tiles.put(tile.getCenter(), tile); - points.put(tile.getId(), tile.getCenter()); - - //addTileEventListener((TileEventListener) tile); - //Alternative point(s) to be able to find all points - if (!tile.getAltPoints().isEmpty()) { - Set alt = tile.getAltPoints(); - for (Point ap : alt) { - altTiles.put(ap, tile); - } - } - - saveTile(tile); - Logger.trace("Added " + tile + " There are now " + TileCache.tiles.size() + " tiles..."); - } - - static void deleteTile(final Tile tile) { - if (tile != null) { - if (tiles.containsKey(tile.getCenter())) { - tiles.remove(tile.getCenter()); - points.remove(tile.getId()); - Set rps = tile.getAltPoints(); - //Also remove alt points - for (Point ap : rps) { - altTiles.remove(ap); - } - - TileBean tb = tile.getTileBean(); - PersistenceFactory.getService().remove(tb); - Logger.trace("Deleted " + tile.getId()); - } else { - Logger.warn("Tile " + tile.getId() + " not found in cache"); - } - } else { - Logger.warn("Tile is null?"); - } - } - - static void saveTile(final Tile tile) { - if (tile != null) { - TileBean tb = tile.getTileBean(); - PersistenceFactory.getService().persist(tb); - } else { - Logger.warn("Tile is null?"); - } - } - - static void saveTiles() { - for (Tile tile : tiles.values()) { - saveTile(tile); - } - } - - public static Tile findTile(Point cp) { - Tile result = tiles.get(cp); - if (result == null) { - result = altTiles.get(cp); - if (result != null) { - } - } - return result; - } - - public static Tile findTile(String id) { - Point p = points.get(id); - if (p != null) { - return findTile(p); - } else { - return null; - } - } - - static boolean checkTileOccupation(Tile tile) { - Set tilePoints = tile.getAllPoints(); - for (Point p : tilePoints) { - if (tiles.containsKey(p) || altTiles.containsKey(p)) { - //The is a match, check if it is an other tile - Tile mt = findTile(p); - if (tile.getId().equals(mt.getId())) { - //same tile continue - } else { - //Other tile so really occupied - return true; - } - } - } - return false; - } - - static boolean containsPoints(Set points) { - for (Point p : points) { - return tiles.containsKey(p) || altTiles.containsKey(p); - } - return false; - - } - - static boolean containsPoint(Point point) { - return tiles.containsKey(point) || altTiles.containsKey(point); - } - - static Point checkAvailable(Point newPoint, Orientation orientation) { - if (tiles.containsKey(newPoint)) { - Tile et = tiles.get(newPoint); - Logger.trace("@ " + newPoint + " is allready occcupied by: " + et + "..."); - //Search for the nearest avalaible free point - //first get the Center point of the tile which is occuping this slot - // show warning! - Point ecp = et.getCenter(); - - int w = et.getWidth(); - int h = et.getHeight(); - - Point np; - np = switch (orientation) { - case EAST -> - new Point(ecp.x + w, ecp.y); - case WEST -> - new Point(newPoint.x - w, ecp.y); - case SOUTH -> - new Point(ecp.x, newPoint.y + h); - default -> - new Point(ecp.x, newPoint.y - h); - }; - - Logger.trace("Alternative CP: " + np); - // recursive check - return checkAvailable(np, orientation); - } else { - Logger.trace("@ " + newPoint + " is not yet used..."); - - return newPoint; - } - } - - static Tile rotateTile(Tile tile) { - if (!tiles.containsKey(tile.getCenter())) { - Logger.warn("Tile " + tile.getId() + " NOT in cache!"); - } - - //Remove the alternative or extra points... - for (Point ep : tile.getAltPoints()) { - altTiles.remove(ep); - } - - tile.rotate(); - - //update - tiles.put(tile.getCenter(), tile); - for (Point ep : tile.getAltPoints()) { - altTiles.put(ep, tile); - } - - saveTile(tile); - return tile; - } - - static Tile flipHorizontal(Tile tile) { - return flipTile(tile, true); - } - - public static Tile flipVertical(Tile tile) { - return flipTile(tile, false); - } - - private static Tile flipTile(Tile tile, boolean horizontal) { - if (!tiles.containsKey(tile.getCenter())) { - Logger.warn("Tile " + tile.getId() + " NOT in cache!"); - } - - //Remove the alternative or extra points... - for (Point ep : tile.getAltPoints()) { - altTiles.remove(ep); - } - - if (horizontal) { - tile.flipHorizontal(); - } else { - tile.flipVertical(); - } - //update - tiles.put(tile.getCenter(), tile); - for (Point ep : tile.getAltPoints()) { - altTiles.put(ep, tile); - } - - saveTile(tile); - return tile; - } - - static void moveTile(Point snapPoint, Tile tile) { - Point tp = tile.getCenter(); - if (!tp.equals(snapPoint)) { - //Check if new position is free - boolean canMove = !TileCache.containsPoint(snapPoint); - - if (canMove) { - Logger.trace("Moving from tile " + tile.getId() + " from " + tile.xyToString() + " to (" + snapPoint.x + "," + snapPoint.y + ")"); - //Remove the original tile center from the tiles - Tile movingTile = tiles.remove(tp); - if (movingTile != null) { - //Also remove from the alt points - Point oldCenter = movingTile.getCenter(); - Set oldAltPoints = movingTile.getAltPoints(); - //Logger.trace("Removing " + oldAltPoints.size() + " alt tile points"); - for (Point ep : oldAltPoints) { - altTiles.remove(ep); - tiles.remove(ep); - } - - //Set the new center position - movingTile.setCenter(snapPoint); - //Check again, needed for tiles which are longer then 1 square, like a block - if (!checkTileOccupation(movingTile)) { - Logger.trace("Moved Tile " + movingTile.getId() + " from " + tp + " to " + snapPoint + "..."); - tiles.put(snapPoint, movingTile); - for (Point ep : movingTile.getAltPoints()) { - altTiles.put(ep, movingTile); - } - } else { - //Do not move Tile, put back where it was - movingTile.setCenter(oldCenter); - tiles.put(oldCenter, movingTile); - for (Point ep : movingTile.getAltPoints()) { - altTiles.put(ep, movingTile); - } - } - - saveTile(movingTile); - } - } - //} - } - } - - static void addTileEventListener(TileEventListener listener) { - String key = listener.getId(); - tileEventListeners.put(key, listener); - } - - static void removeTileEventListener(Tile tile) { - if (tile instanceof TileEventListener tileEventListener) { - removeTileEventListener(tileEventListener); - } - } - - static void removeTileEventListener(TileEventListener listener) { - String key = listener.getId(); - tileEventListeners.remove(key, listener); - } - - public static void fireTileEventListener(TileEvent tileEvent) { - String key = tileEvent.getTileId(); - TileEventListener listener = tileEventListeners.get(key); - if (listener != null) { - listener.onTileChange(tileEvent); - Logger.trace("Fire listener on tile " + key); - } else { - //Logger.trace("Tile " + key + " not available"); - } - } - - static void fireAllTileEventListeners(TileEvent tileEvent) { - for (TileEventListener listener : tileEventListeners.values()) { - listener.onTileChange(tileEvent); - } - } - -} diff --git a/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java b/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java index 88057929..b5881650 100644 --- a/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java +++ b/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java @@ -24,7 +24,7 @@ import jcs.entities.BlockBean; import jcs.entities.LocomotiveBean; import jcs.persistence.PersistenceFactory; -import jcs.ui.layout.TileCache; +import jcs.ui.layout.tiles.TileCache; import jcs.ui.layout.events.TileEvent; import jcs.ui.layout.tiles.Block; import org.tinylog.Logger; diff --git a/src/main/java/jcs/ui/layout/dialogs/BlockDialog.java b/src/main/java/jcs/ui/layout/dialogs/BlockDialog.java index aa1974ba..9b06c95f 100644 --- a/src/main/java/jcs/ui/layout/dialogs/BlockDialog.java +++ b/src/main/java/jcs/ui/layout/dialogs/BlockDialog.java @@ -27,7 +27,7 @@ import jcs.entities.SensorBean; import jcs.persistence.PersistenceFactory; import jcs.ui.layout.LayoutCanvas; -import jcs.ui.layout.TileCache; +import jcs.ui.layout.tiles.TileCache; import jcs.ui.layout.tiles.Block; import jcs.ui.layout.tiles.Sensor; import jcs.ui.layout.tiles.Tile; diff --git a/src/main/java/jcs/ui/layout/tiles/Block.java b/src/main/java/jcs/ui/layout/tiles/Block.java index e98fa594..c9f36962 100755 --- a/src/main/java/jcs/ui/layout/tiles/Block.java +++ b/src/main/java/jcs/ui/layout/tiles/Block.java @@ -1 +1 @@ -/* * Copyright 2024 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; 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.Image; import java.awt.Point; import java.awt.Rectangle; import java.awt.geom.Ellipse2D; import java.awt.image.BufferedImage; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import jcs.entities.BlockBean; import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.EAST; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; import static jcs.ui.layout.tiles.Tile.GRID; import static jcs.ui.layout.tiles.Tile.RENDER_HEIGHT; import static jcs.ui.layout.tiles.Tile.RENDER_WIDTH; import jcs.ui.util.ImageUtil; import org.tinylog.Logger; public class Block extends Tile { public static final int BLOCK_WIDTH = DEFAULT_WIDTH * 3; public static final int BLOCK_HEIGHT = DEFAULT_HEIGHT * 3; public Block(TileBean tileBean) { super(tileBean); setModel(new DefaultTileModel(tileBean.getOrientation())); changeRenderSize(); populateModel(); } public Block(Orientation orientation, Point center) { this(orientation, center.x, center.y); } public Block(Orientation orientation, int x, int y) { this(orientation, x, y, tileWidth(orientation, TileType.BLOCK), tileHeight(orientation, TileType.BLOCK)); } public Block(Orientation orientation, int x, int y, int width, int height) { super(TileType.BLOCK, orientation, x, y, width, height); setModel(new DefaultTileModel(orientation)); changeRenderSize(); } private void changeRenderSize() { Orientation tileOrientation = model.getTileOrienation(); if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { this.renderWidth = RENDER_WIDTH * 3; this.renderHeight = RENDER_HEIGHT; } else { this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT * 3; } } @Override public Set getAltPoints() { int xx = this.tileX; int yy = this.tileY; Set alternatives = new HashSet<>(); if (Orientation.EAST.equals(getOrientation()) || Orientation.WEST.equals(getOrientation())) { // West Point wp = new Point((xx - DEFAULT_WIDTH), yy); Point ep = new Point((xx + DEFAULT_WIDTH), yy); alternatives.add(wp); alternatives.add(ep); } else { Point np = new Point(xx, (yy - DEFAULT_HEIGHT)); Point sp = new Point(xx, (yy + DEFAULT_HEIGHT)); alternatives.add(np); alternatives.add(sp); } return alternatives; } @Override public Set getAllPoints() { Set aps = new HashSet<>(); aps.add(getCenter()); aps.addAll(getAltPoints()); return aps; } public Point getAltPoint(String suffix) { int cx = this.getCenterX(); int cy = this.getCenterY(); if ("+".equals(suffix)) { return switch (this.getOrientation()) { case WEST -> new Point(cx - Tile.GRID * 2, cy); case NORTH -> new Point(cx, cy - Tile.GRID * 2); case SOUTH -> new Point(cx, cy + Tile.GRID * 2); default -> new Point(cx + Tile.GRID * 2, cy); }; } else { return switch (this.getOrientation()) { case EAST -> new Point(cx - Tile.GRID * 2, cy); case SOUTH -> new Point(cx, cy - Tile.GRID * 2); case NORTH -> new Point(cx, cy + Tile.GRID * 2); default -> new Point(cx + Tile.GRID * 2, cy); }; } } @Override public boolean isBlock() { return true; } @Override public Map getNeighborPoints() { Map neighbors = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); // Horizontal if (Orientation.EAST == orientation || Orientation.WEST == orientation) { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 4, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 4, cy)); } else { // Vertical neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 4)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 4)); } return neighbors; } @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); // Horizontal if (Orientation.EAST == orientation || Orientation.WEST == orientation) { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID * 3, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID * 3, cy)); } else { // Vertical edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 3)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 3)); } return edgeConnections; } public Point getNeighborPoint(String suffix) { int cx = getCenterX(); int cy = getCenterY(); if ("+".equals(suffix)) { return switch (getOrientation()) { case WEST -> new Point(cx - Tile.GRID * 4, cy); case NORTH -> new Point(cx, cy - Tile.GRID * 4); case SOUTH -> new Point(cx, cy + Tile.GRID * 4); default -> new Point(cx + Tile.GRID * 4, cy); }; } else { return switch (getOrientation()) { case EAST -> new Point(cx - Tile.GRID * 4, cy); case SOUTH -> new Point(cx, cy - Tile.GRID * 4); case NORTH -> new Point(cx, cy + Tile.GRID * 4); default -> new Point(cx + Tile.GRID * 4, cy); }; } } public Orientation getTravelDirection(String suffix) { if ("+".equals(suffix)) { return getOrientation(); } else { return switch (getOrientation()) { case EAST -> Orientation.WEST; case SOUTH -> Orientation.NORTH; case NORTH -> Orientation.SOUTH; default -> Orientation.EAST; }; } } @Override public String getIdSuffix(Tile other) { String suffix = null; Orientation match = null; if (isAdjacent(other)) { Map blockSides = this.getEdgePoints(); Map otherSides = other.getEdgePoints(); for (Orientation bo : Orientation.values()) { Point bp = blockSides.get(bo); if (bp != null) { for (Orientation oo : Orientation.values()) { Point op = otherSides.get(oo); if (op != null) { if (op.equals(bp)) { match = bo; break; } } } } } } Orientation tileOrientation = model.getTileOrienation(); if (match != null) { if (Orientation.EAST == tileOrientation && Orientation.EAST == match) { suffix = "+"; } if (Orientation.WEST == tileOrientation && Orientation.WEST == match) { suffix = "+"; } if (Orientation.EAST == tileOrientation && Orientation.WEST == match) { suffix = "-"; } if (Orientation.WEST == tileOrientation && Orientation.EAST == match) { suffix = "-"; } if (Orientation.NORTH == tileOrientation && Orientation.NORTH == match) { suffix = "+"; } if (Orientation.NORTH == tileOrientation && Orientation.SOUTH == match) { suffix = "-"; } if (Orientation.SOUTH == tileOrientation && Orientation.SOUTH == match) { suffix = "+"; } if (Orientation.SOUTH == tileOrientation && Orientation.NORTH == match) { suffix = "-"; } } return suffix; } @Override public Orientation rotate() { super.rotate(); Orientation tileOrientation = model.getTileOrienation(); int w = tileWidth(tileOrientation, TileType.BLOCK); int h = tileHeight(tileOrientation, TileType.BLOCK); Dimension d = new Dimension(w, h); setPreferredSize(d); setSize(d); changeRenderSize(); setBounds(getTileBounds()); return model.getTileOrienation(); } /** * Depending on the block status change the background color
* - Red: Occupied
* - Green: Departure
* - Magenta: Arrival / entering
* - Yellow: reserved
* - White: all clear / default
* * @return the Color which belong with the current Block State */ Color getBlockStateColor() { return getBlockStateColor(this.model.getBlockState()); } protected Color getBlockStateColor(BlockState blockState) { return switch (blockState) { case GHOST -> new Color(250, 0, 0); case LOCKED -> new Color(250, 250, 210); case OCCUPIED -> new Color(250, 210, 210); case OUT_OF_ORDER -> new Color(190, 190, 190); case OUTBOUND -> new Color(210, 250, 210); case INBOUND -> new Color(250, 210, 250); default -> new Color(255, 255, 255); }; } public static String getDepartureSuffix(Orientation tileOrientation, boolean reverseArrival, LocomotiveBean.Direction direction) { if (LocomotiveBean.Direction.FORWARDS == direction) { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { if (reverseArrival) { return "-"; } else { return "+"; } } else { if (reverseArrival) { return "+"; } else { return "-"; } } } else { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { if (reverseArrival) { return "+"; } else { return "-"; } } else { if (reverseArrival) { return "-"; } else { return "+"; } } } } @Override public void renderTile(Graphics2D g2) { int xx = 20; int yy = 50; int rw = RENDER_WIDTH * 3 - 40; int rh = 300; g2.setStroke(new BasicStroke(3, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); g2.setPaint(Color.darkGray); g2.drawRoundRect(xx, yy, rw, rh, 15, 15); Color blockStateColor = getBlockStateColor(); //Logger.trace("Block " + this.id + " State: " + this.getBlockBean().getBlockState().getState() + " Color: " + blockStateColor.toString()); g2.setPaint(blockStateColor); g2.fillRoundRect(xx, yy, rw, rh, 15, 15); g2.setStroke(new BasicStroke(20, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); g2.setPaint(Color.darkGray); g2.drawLine(rw + GRID, yy - 0, rw + GRID, yy + 300); //When there is a locomotive in the block mark the direction of travel. //The default, forwards is in the direction of the block orientation, i.e. the + if (model.getLocomotive() != null && model.getLocomotive().getName() != null) { renderDirectionArrow(g2); } drawName(g2); } private void renderDirectionArrow(Graphics2D g2) { //The default, forwards is in the direction of the block orientation, i.e. the + Orientation tileOrientation = model.getTileOrienation(); BlockBean bb = this.getBlockBean(); boolean reverseArrival = model.isReverseArrival(); LocomotiveBean.Direction logicalDirection; if (bb.getLogicalDirection() != null) { logicalDirection = model.getLogicalDirection(); } else { logicalDirection = model.getLocomotive().getDirection(); } String departureSuffix = model.getDepartureSuffix(); if (departureSuffix == null) { departureSuffix = Block.getDepartureSuffix(tileOrientation, reverseArrival, logicalDirection); } //Logger.trace(this.getId()+" LogicalDirection is " + (bb.getLogicalDirection() != null ? "Set" : "Not Set") + " Dir: " + logicalDirection.getDirection() + " Orientation: " + orientation.getOrientation() + " departureSuffix: " + departureSuffix); if ("+".equals(departureSuffix)) { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { switch (logicalDirection) { case LocomotiveBean.Direction.FORWARDS -> { if (reverseArrival) { renderLeftArrow(g2); } else { renderRightArrow(g2); } } case LocomotiveBean.Direction.BACKWARDS -> { if (reverseArrival) { renderRightArrow(g2); } else { renderLeftArrow(g2); } } } } else { switch (logicalDirection) { case LocomotiveBean.Direction.BACKWARDS -> { if (reverseArrival) { renderLeftArrow(g2); } else { renderRightArrow(g2); } } case LocomotiveBean.Direction.FORWARDS -> { if (reverseArrival) { renderRightArrow(g2); } else { renderLeftArrow(g2); } } } } } else { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { switch (logicalDirection) { case LocomotiveBean.Direction.FORWARDS -> { if (reverseArrival) { renderLeftArrow(g2); } else { renderRightArrow(g2); } } case LocomotiveBean.Direction.BACKWARDS -> { if (reverseArrival) { renderRightArrow(g2); } else { renderLeftArrow(g2); } } } } else { switch (logicalDirection) { case LocomotiveBean.Direction.BACKWARDS -> { if (reverseArrival) { renderLeftArrow(g2); } else { renderRightArrow(g2); } } case LocomotiveBean.Direction.FORWARDS -> { if (reverseArrival) { renderRightArrow(g2); } else { renderLeftArrow(g2); } } } } } } private void renderLeftArrow(Graphics2D g2) { //Logger.trace(this.getId()+" LogicalDirection is " + this.getBlockBean().getLogicalDirection() + " Orientation: " + this.getOrientation() + " departureSuffix: " + this.getBlockBean().getDepartureSuffix()); g2.fillPolygon(new int[]{0, 50, 50,}, new int[]{200, 150, 250}, 3); } private void renderRightArrow(Graphics2D g2) { //Logger.trace(this.getId()+" LogicalDirection is " + this.getBlockBean().getLogicalDirection() + " Orientation: " + this.getOrientation() + " departureSuffix: " + this.getBlockBean().getDepartureSuffix()); g2.fillPolygon(new int[]{1180, 1130, 1130,}, new int[]{200, 150, 250}, 3); } @Override public void renderTileRoute(Graphics2D g2d) { if (model.isShowBlockState()) { backgroundColor = getBlockStateColor(model.getBlockState()); } } protected void overlayLocImage() { int ww = tileImage.getWidth(); int hh = tileImage.getHeight(); Orientation tileOrientation = model.getTileOrienation(); BufferedImage overlay = new BufferedImage(ww, hh, BufferedImage.TYPE_INT_ARGB); Graphics2D g2i = overlay.createGraphics(); Image locImage = getLocImage(); if (locImage != null) { String departureSuffix = model.getDepartureSuffix(); boolean reverseImage = model.isReverseArrival(); Logger.trace("LocImage w: " + locImage.getWidth(null) + " h: " + locImage.getHeight(null)); // scale it to max h of 45 int size = 45; float aspect = (float) locImage.getHeight(null) / (float) locImage.getWidth(null); //TODO: Use Scalr? locImage = locImage.getScaledInstance(size, (int) (size * aspect), Image.SCALE_SMOOTH); //Depending on the block orientation the image needs to be rotated and flipped //Incase the departure suffix is NOT set center the locomotive image int w, h, xx, yy; switch (tileOrientation) { case WEST -> { w = locImage.getWidth(null); h = locImage.getHeight(null); if (null == departureSuffix) { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w; } else { switch (departureSuffix) { case "+" -> { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w - 25; } default -> { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w + 10; } } } yy = DEFAULT_HEIGHT / 2 - h / 2; if (reverseImage) { locImage = ImageUtil.flipVertically(locImage); } } case SOUTH -> { locImage = ImageUtil.flipHorizontally(locImage); locImage = ImageUtil.rotate(locImage, 90); w = locImage.getWidth(null); h = locImage.getHeight(null); xx = DEFAULT_WIDTH / 2 - w / 2; if (null == departureSuffix) { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h; } else { switch (departureSuffix) { case "-" -> { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h - 25; } default -> { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h + 10; } } } if (reverseImage) { locImage = ImageUtil.flipHorizontally(locImage); } } case NORTH -> { locImage = ImageUtil.flipHorizontally(locImage); locImage = ImageUtil.rotate(locImage, 90); w = locImage.getWidth(null); h = locImage.getHeight(null); xx = DEFAULT_WIDTH / 2 - w / 2; if (null == departureSuffix) { int minY = BLOCK_HEIGHT / 2 - getHeight() / 2 + h; yy = minY; } else { switch (departureSuffix) { case "+" -> { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h - 25; } default -> { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h + 10; } } } if (reverseImage) { locImage = ImageUtil.flipHorizontally(locImage); } } default -> { w = locImage.getWidth(null); h = locImage.getHeight(null); if (null == departureSuffix) { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w; } else { switch (departureSuffix) { case "-" -> { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w - 25; } default -> { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w + 10; } } } yy = DEFAULT_HEIGHT / 2 - h / 2; if (reverseImage) { locImage = ImageUtil.flipVertically(locImage); } } } g2i.drawImage(tileImage, 0, 0, null); g2i.drawImage(locImage, xx, yy, null); g2i.dispose(); tileImage = overlay; } } private Image getLocImage() { if (model.getLocomotive() != null && model.getLocomotive().getLocIcon() != null) { return model.getLocomotive().getLocIcon(); } else { return null; } } public String getBlockText() { String blockText; if (blockBean != null && blockBean.getDescription() != null) { if (blockBean.getLocomotive() != null && blockBean.getLocomotive().getName() != null && BlockState.GHOST != blockBean.getBlockState()) { blockText = blockBean.getLocomotive().getName(); } else { if (blockBean.getDescription().length() > 0) { blockText = blockBean.getDescription(); } else { blockText = getId(); } } } else { // Design mode show description when available if (blockBean != null && blockBean.getDescription() != null && blockBean.getDescription().length() > 0) { blockText = blockBean.getDescription(); } else { blockText = getId(); } } return blockText; } @Override public void drawName(Graphics2D g2d) { if (!model.isOverlayImage()) { g2d.setPaint(Color.black); Font currentFont = g2d.getFont(); Font newFont = currentFont.deriveFont(currentFont.getSize() * 10.0F); g2d.setFont(newFont); String blockText = getBlockText(); // Scale the text if necessary int textWidth = g2d.getFontMetrics().stringWidth(blockText); double fontscale = 10.0; if (textWidth > 845) { fontscale = fontscale * 847.0 / textWidth; newFont = currentFont.deriveFont(currentFont.getSize() * (float) fontscale); g2d.setFont(newFont); textWidth = g2d.getFontMetrics().stringWidth(blockText); } int textHeight = g2d.getFontMetrics().getHeight(); Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case EAST -> { drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) - textWidth / 2, RENDER_GRID + textHeight / 3, 0, blockText); } case WEST -> { drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) + textWidth / 2, RENDER_GRID - textHeight / 3, 180, blockText); } case NORTH -> { drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) - textWidth / 2, RENDER_GRID + textHeight / 3, 0, blockText); } case SOUTH -> { drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) + textWidth / 2, RENDER_GRID - textHeight / 3, 180, blockText); } } // reset to the original font newFont = currentFont.deriveFont(currentFont.getSize() * 1.0F); g2d.setFont(newFont); } } @Override public Rectangle getTileBounds() { int multiplier = (model.isScaleImage() ? 1 : 10); Orientation tileOrientation = model.getTileOrienation(); int xx, yy; if (tileOrientation == Orientation.EAST || tileOrientation == Orientation.WEST) { xx = tileX - GRID * multiplier - GRID * multiplier * 2; yy = tileY - GRID * multiplier; } else { xx = tileX - GRID * multiplier; yy = tileY - GRID * multiplier - GRID * multiplier * 2; } if (model.isScaleImage()) { return new Rectangle(xx, yy, tileWidth(tileOrientation, TileType.BLOCK), tileHeight(tileOrientation, TileType.BLOCK)); } else { return new Rectangle(xx, yy, renderWidth, renderHeight); } } @Override protected void paintComponent(Graphics g) { long started = System.currentTimeMillis(); Graphics2D g2 = (Graphics2D) g.create(); drawTile(g2); g2.dispose(); if (model.isOverlayImage()) { overlayLocImage(); } g.drawImage(tileImage, 0, 0, null); long now = System.currentTimeMillis(); Logger.trace(id + " Duration: " + (now - started) + " ms."); } @Override protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { //A block has 2 alternate points //1st square //2nd square holds the centerpoint //3rd square Orientation tileOrientation = model.getTileOrienation(); double dX1, dX2, dX3, dY1, dY2, dY3; if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { dX1 = renderWidth / 3 / 2 - size / 2 / 2; dY1 = renderHeight / 2 - size / 2 / 2; dX2 = renderWidth / 2 - size / 2; dY2 = renderHeight / 2 - size / 2; dX3 = renderWidth - renderWidth / 3 / 2 - size / 2 / 2; dY3 = renderHeight / 2 - size / 2 / 2; } else { dX1 = renderWidth / 2 - size / 2 / 2; dY1 = renderHeight / 3 / 2 - size / 2 / 2; dX2 = renderHeight / 2 - size / 2; dY2 = renderWidth / 2 - size / 2; dY3 = renderWidth / 2 - size / 2 / 2; dX3 = renderHeight - renderHeight / 3 / 2 - size / 2 / 2; } g2d.setColor(color); g2d.fill(new Ellipse2D.Double(dX1, dY1, size / 2, size / 2)); g2d.fill(new Ellipse2D.Double(dX2, dY2, size, size)); g2d.fill(new Ellipse2D.Double(dX3, dY3, size / 2, size / 2)); } } \ No newline at end of file +/* * Copyright 2024 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; 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.Image; import java.awt.Point; import java.awt.Rectangle; import java.awt.geom.Ellipse2D; import java.awt.image.BufferedImage; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import jcs.entities.BlockBean; import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.EAST; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; import static jcs.ui.layout.tiles.Tile.GRID; import static jcs.ui.layout.tiles.Tile.RENDER_HEIGHT; import static jcs.ui.layout.tiles.Tile.RENDER_WIDTH; import jcs.ui.util.ImageUtil; import org.tinylog.Logger; public class Block extends Tile { public static final int BLOCK_WIDTH = DEFAULT_WIDTH * 3; public static final int BLOCK_HEIGHT = DEFAULT_HEIGHT * 3; public Block(TileBean tileBean) { super(tileBean); setModel(new DefaultTileModel(tileBean.getOrientation())); changeRenderSize(); populateModel(); } public Block(Orientation orientation, Point center) { this(orientation, center.x, center.y); } public Block(Orientation orientation, int x, int y) { this(orientation, x, y, tileWidth(orientation, TileType.BLOCK), tileHeight(orientation, TileType.BLOCK)); } public Block(Orientation orientation, int x, int y, int width, int height) { super(TileType.BLOCK, orientation, x, y, width, height); setModel(new DefaultTileModel(orientation)); changeRenderSize(); } private void changeRenderSize() { Orientation tileOrientation = model.getTileOrienation(); if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { this.renderWidth = RENDER_WIDTH * 3; this.renderHeight = RENDER_HEIGHT; } else { this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT * 3; } } @Override public Set getAltPoints() { int xx = this.tileX; int yy = this.tileY; Set alternatives = new HashSet<>(); if (Orientation.EAST.equals(getOrientation()) || Orientation.WEST.equals(getOrientation())) { // West Point wp = new Point((xx - DEFAULT_WIDTH), yy); Point ep = new Point((xx + DEFAULT_WIDTH), yy); alternatives.add(wp); alternatives.add(ep); } else { Point np = new Point(xx, (yy - DEFAULT_HEIGHT)); Point sp = new Point(xx, (yy + DEFAULT_HEIGHT)); alternatives.add(np); alternatives.add(sp); } return alternatives; } @Override public Set getAllPoints() { Set aps = new HashSet<>(); aps.add(getCenter()); aps.addAll(getAltPoints()); return aps; } @Override Set getAllPoints(Point center) { Set points = getAltPoints(center); points.add(center); return points; } @Override Set getAltPoints(Point center) { Set alts = new HashSet<>(); if (Orientation.EAST == model.getTileOrienation() || Orientation.WEST == model.getTileOrienation()) { // West Point wp = new Point((center.x - DEFAULT_WIDTH), center.y); Point ep = new Point((center.x + DEFAULT_WIDTH), center.y); alts.add(wp); alts.add(ep); } else { Point np = new Point(center.x, (center.y - DEFAULT_HEIGHT)); Point sp = new Point(center.x, (center.y + DEFAULT_HEIGHT)); alts.add(np); alts.add(sp); } return alts; } public Point getAltPoint(String suffix) { int cx = this.getCenterX(); int cy = this.getCenterY(); if ("+".equals(suffix)) { return switch (this.getOrientation()) { case WEST -> new Point(cx - Tile.GRID * 2, cy); case NORTH -> new Point(cx, cy - Tile.GRID * 2); case SOUTH -> new Point(cx, cy + Tile.GRID * 2); default -> new Point(cx + Tile.GRID * 2, cy); }; } else { return switch (this.getOrientation()) { case EAST -> new Point(cx - Tile.GRID * 2, cy); case SOUTH -> new Point(cx, cy - Tile.GRID * 2); case NORTH -> new Point(cx, cy + Tile.GRID * 2); default -> new Point(cx + Tile.GRID * 2, cy); }; } } @Override public boolean isBlock() { return true; } @Override public Map getNeighborPoints() { Map neighbors = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); // Horizontal if (Orientation.EAST == orientation || Orientation.WEST == orientation) { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 4, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 4, cy)); } else { // Vertical neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 4)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 4)); } return neighbors; } @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); // Horizontal if (Orientation.EAST == orientation || Orientation.WEST == orientation) { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID * 3, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID * 3, cy)); } else { // Vertical edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 3)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 3)); } return edgeConnections; } public Point getNeighborPoint(String suffix) { int cx = getCenterX(); int cy = getCenterY(); if ("+".equals(suffix)) { return switch (getOrientation()) { case WEST -> new Point(cx - Tile.GRID * 4, cy); case NORTH -> new Point(cx, cy - Tile.GRID * 4); case SOUTH -> new Point(cx, cy + Tile.GRID * 4); default -> new Point(cx + Tile.GRID * 4, cy); }; } else { return switch (getOrientation()) { case EAST -> new Point(cx - Tile.GRID * 4, cy); case SOUTH -> new Point(cx, cy - Tile.GRID * 4); case NORTH -> new Point(cx, cy + Tile.GRID * 4); default -> new Point(cx + Tile.GRID * 4, cy); }; } } public Orientation getTravelDirection(String suffix) { if ("+".equals(suffix)) { return getOrientation(); } else { return switch (getOrientation()) { case EAST -> Orientation.WEST; case SOUTH -> Orientation.NORTH; case NORTH -> Orientation.SOUTH; default -> Orientation.EAST; }; } } @Override public String getIdSuffix(Tile other) { String suffix = null; Orientation match = null; if (isAdjacent(other)) { Map blockSides = this.getEdgePoints(); Map otherSides = other.getEdgePoints(); for (Orientation bo : Orientation.values()) { Point bp = blockSides.get(bo); if (bp != null) { for (Orientation oo : Orientation.values()) { Point op = otherSides.get(oo); if (op != null) { if (op.equals(bp)) { match = bo; break; } } } } } } Orientation tileOrientation = model.getTileOrienation(); if (match != null) { if (Orientation.EAST == tileOrientation && Orientation.EAST == match) { suffix = "+"; } if (Orientation.WEST == tileOrientation && Orientation.WEST == match) { suffix = "+"; } if (Orientation.EAST == tileOrientation && Orientation.WEST == match) { suffix = "-"; } if (Orientation.WEST == tileOrientation && Orientation.EAST == match) { suffix = "-"; } if (Orientation.NORTH == tileOrientation && Orientation.NORTH == match) { suffix = "+"; } if (Orientation.NORTH == tileOrientation && Orientation.SOUTH == match) { suffix = "-"; } if (Orientation.SOUTH == tileOrientation && Orientation.SOUTH == match) { suffix = "+"; } if (Orientation.SOUTH == tileOrientation && Orientation.NORTH == match) { suffix = "-"; } } return suffix; } @Override public Orientation rotate() { super.rotate(); Orientation tileOrientation = model.getTileOrienation(); int w = tileWidth(tileOrientation, TileType.BLOCK); int h = tileHeight(tileOrientation, TileType.BLOCK); Dimension d = new Dimension(w, h); setPreferredSize(d); setSize(d); changeRenderSize(); setBounds(getTileBounds()); return model.getTileOrienation(); } /** * Depending on the block status change the background color
* - Red: Occupied
* - Green: Departure
* - Magenta: Arrival / entering
* - Yellow: reserved
* - White: all clear / default
* * @return the Color which belong with the current Block State */ Color getBlockStateColor() { return getBlockStateColor(this.model.getBlockState()); } protected Color getBlockStateColor(BlockState blockState) { return switch (blockState) { case GHOST -> new Color(250, 0, 0); case LOCKED -> new Color(250, 250, 210); case OCCUPIED -> new Color(250, 210, 210); case OUT_OF_ORDER -> new Color(190, 190, 190); case OUTBOUND -> new Color(210, 250, 210); case INBOUND -> new Color(250, 210, 250); default -> new Color(255, 255, 255); }; } public static String getDepartureSuffix(Orientation tileOrientation, boolean reverseArrival, LocomotiveBean.Direction direction) { if (LocomotiveBean.Direction.FORWARDS == direction) { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { if (reverseArrival) { return "-"; } else { return "+"; } } else { if (reverseArrival) { return "+"; } else { return "-"; } } } else { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { if (reverseArrival) { return "+"; } else { return "-"; } } else { if (reverseArrival) { return "-"; } else { return "+"; } } } } @Override public void renderTile(Graphics2D g2) { int xx = 20; int yy = 50; int rw = RENDER_WIDTH * 3 - 40; int rh = 300; g2.setStroke(new BasicStroke(3, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); g2.setPaint(Color.darkGray); g2.drawRoundRect(xx, yy, rw, rh, 15, 15); Color blockStateColor = getBlockStateColor(); //Logger.trace("Block " + this.id + " State: " + this.getBlockBean().getBlockState().getState() + " Color: " + blockStateColor.toString()); g2.setPaint(blockStateColor); g2.fillRoundRect(xx, yy, rw, rh, 15, 15); g2.setStroke(new BasicStroke(20, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); g2.setPaint(Color.darkGray); g2.drawLine(rw + GRID, yy - 0, rw + GRID, yy + 300); //When there is a locomotive in the block mark the direction of travel. //The default, forwards is in the direction of the block orientation, i.e. the + if (model.getLocomotive() != null && model.getLocomotive().getName() != null) { renderDirectionArrow(g2); } drawName(g2); } private void renderDirectionArrow(Graphics2D g2) { //The default, forwards is in the direction of the block orientation, i.e. the + Orientation tileOrientation = model.getTileOrienation(); BlockBean bb = this.getBlockBean(); boolean reverseArrival = model.isReverseArrival(); LocomotiveBean.Direction logicalDirection; if (bb.getLogicalDirection() != null) { logicalDirection = model.getLogicalDirection(); } else { logicalDirection = model.getLocomotive().getDirection(); } String departureSuffix = model.getDepartureSuffix(); if (departureSuffix == null) { departureSuffix = Block.getDepartureSuffix(tileOrientation, reverseArrival, logicalDirection); } //Logger.trace(this.getId()+" LogicalDirection is " + (bb.getLogicalDirection() != null ? "Set" : "Not Set") + " Dir: " + logicalDirection.getDirection() + " Orientation: " + orientation.getOrientation() + " departureSuffix: " + departureSuffix); if ("+".equals(departureSuffix)) { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { switch (logicalDirection) { case LocomotiveBean.Direction.FORWARDS -> { if (reverseArrival) { renderLeftArrow(g2); } else { renderRightArrow(g2); } } case LocomotiveBean.Direction.BACKWARDS -> { if (reverseArrival) { renderRightArrow(g2); } else { renderLeftArrow(g2); } } } } else { switch (logicalDirection) { case LocomotiveBean.Direction.BACKWARDS -> { if (reverseArrival) { renderLeftArrow(g2); } else { renderRightArrow(g2); } } case LocomotiveBean.Direction.FORWARDS -> { if (reverseArrival) { renderRightArrow(g2); } else { renderLeftArrow(g2); } } } } } else { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { switch (logicalDirection) { case LocomotiveBean.Direction.FORWARDS -> { if (reverseArrival) { renderLeftArrow(g2); } else { renderRightArrow(g2); } } case LocomotiveBean.Direction.BACKWARDS -> { if (reverseArrival) { renderRightArrow(g2); } else { renderLeftArrow(g2); } } } } else { switch (logicalDirection) { case LocomotiveBean.Direction.BACKWARDS -> { if (reverseArrival) { renderLeftArrow(g2); } else { renderRightArrow(g2); } } case LocomotiveBean.Direction.FORWARDS -> { if (reverseArrival) { renderRightArrow(g2); } else { renderLeftArrow(g2); } } } } } } private void renderLeftArrow(Graphics2D g2) { //Logger.trace(this.getId()+" LogicalDirection is " + this.getBlockBean().getLogicalDirection() + " Orientation: " + this.getOrientation() + " departureSuffix: " + this.getBlockBean().getDepartureSuffix()); g2.fillPolygon(new int[]{0, 50, 50,}, new int[]{200, 150, 250}, 3); } private void renderRightArrow(Graphics2D g2) { //Logger.trace(this.getId()+" LogicalDirection is " + this.getBlockBean().getLogicalDirection() + " Orientation: " + this.getOrientation() + " departureSuffix: " + this.getBlockBean().getDepartureSuffix()); g2.fillPolygon(new int[]{1180, 1130, 1130,}, new int[]{200, 150, 250}, 3); } @Override public void renderTileRoute(Graphics2D g2d) { if (model.isShowBlockState()) { backgroundColor = getBlockStateColor(model.getBlockState()); } } protected void overlayLocImage() { int ww = tileImage.getWidth(); int hh = tileImage.getHeight(); Orientation tileOrientation = model.getTileOrienation(); BufferedImage overlay = new BufferedImage(ww, hh, BufferedImage.TYPE_INT_ARGB); Graphics2D g2i = overlay.createGraphics(); Image locImage = getLocImage(); if (locImage != null) { String departureSuffix = model.getDepartureSuffix(); boolean reverseImage = model.isReverseArrival(); Logger.trace("LocImage w: " + locImage.getWidth(null) + " h: " + locImage.getHeight(null)); // scale it to max h of 45 int size = 45; float aspect = (float) locImage.getHeight(null) / (float) locImage.getWidth(null); //TODO: Use Scalr? locImage = locImage.getScaledInstance(size, (int) (size * aspect), Image.SCALE_SMOOTH); //Depending on the block orientation the image needs to be rotated and flipped //Incase the departure suffix is NOT set center the locomotive image int w, h, xx, yy; switch (tileOrientation) { case WEST -> { w = locImage.getWidth(null); h = locImage.getHeight(null); if (null == departureSuffix) { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w; } else { switch (departureSuffix) { case "+" -> { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w - 25; } default -> { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w + 10; } } } yy = DEFAULT_HEIGHT / 2 - h / 2; if (reverseImage) { locImage = ImageUtil.flipVertically(locImage); } } case SOUTH -> { locImage = ImageUtil.flipHorizontally(locImage); locImage = ImageUtil.rotate(locImage, 90); w = locImage.getWidth(null); h = locImage.getHeight(null); xx = DEFAULT_WIDTH / 2 - w / 2; if (null == departureSuffix) { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h; } else { switch (departureSuffix) { case "-" -> { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h - 25; } default -> { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h + 10; } } } if (reverseImage) { locImage = ImageUtil.flipHorizontally(locImage); } } case NORTH -> { locImage = ImageUtil.flipHorizontally(locImage); locImage = ImageUtil.rotate(locImage, 90); w = locImage.getWidth(null); h = locImage.getHeight(null); xx = DEFAULT_WIDTH / 2 - w / 2; if (null == departureSuffix) { int minY = BLOCK_HEIGHT / 2 - getHeight() / 2 + h; yy = minY; } else { switch (departureSuffix) { case "+" -> { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h - 25; } default -> { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h + 10; } } } if (reverseImage) { locImage = ImageUtil.flipHorizontally(locImage); } } default -> { w = locImage.getWidth(null); h = locImage.getHeight(null); if (null == departureSuffix) { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w; } else { switch (departureSuffix) { case "-" -> { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w - 25; } default -> { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w + 10; } } } yy = DEFAULT_HEIGHT / 2 - h / 2; if (reverseImage) { locImage = ImageUtil.flipVertically(locImage); } } } g2i.drawImage(tileImage, 0, 0, null); g2i.drawImage(locImage, xx, yy, null); g2i.dispose(); tileImage = overlay; } } private Image getLocImage() { if (model.getLocomotive() != null && model.getLocomotive().getLocIcon() != null) { return model.getLocomotive().getLocIcon(); } else { return null; } } public String getBlockText() { String blockText; if (blockBean != null && blockBean.getDescription() != null) { if (blockBean.getLocomotive() != null && blockBean.getLocomotive().getName() != null && BlockState.GHOST != blockBean.getBlockState()) { blockText = blockBean.getLocomotive().getName(); } else { if (blockBean.getDescription().length() > 0) { blockText = blockBean.getDescription(); } else { blockText = getId(); } } } else { // Design mode show description when available if (blockBean != null && blockBean.getDescription() != null && blockBean.getDescription().length() > 0) { blockText = blockBean.getDescription(); } else { blockText = getId(); } } return blockText; } @Override public void drawName(Graphics2D g2d) { if (!model.isOverlayImage()) { g2d.setPaint(Color.black); Font currentFont = g2d.getFont(); Font newFont = currentFont.deriveFont(currentFont.getSize() * 10.0F); g2d.setFont(newFont); String blockText = getBlockText(); // Scale the text if necessary int textWidth = g2d.getFontMetrics().stringWidth(blockText); double fontscale = 10.0; if (textWidth > 845) { fontscale = fontscale * 847.0 / textWidth; newFont = currentFont.deriveFont(currentFont.getSize() * (float) fontscale); g2d.setFont(newFont); textWidth = g2d.getFontMetrics().stringWidth(blockText); } int textHeight = g2d.getFontMetrics().getHeight(); Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case EAST -> { drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) - textWidth / 2, RENDER_GRID + textHeight / 3, 0, blockText); } case WEST -> { drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) + textWidth / 2, RENDER_GRID - textHeight / 3, 180, blockText); } case NORTH -> { drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) - textWidth / 2, RENDER_GRID + textHeight / 3, 0, blockText); } case SOUTH -> { drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) + textWidth / 2, RENDER_GRID - textHeight / 3, 180, blockText); } } // reset to the original font newFont = currentFont.deriveFont(currentFont.getSize() * 1.0F); g2d.setFont(newFont); } } @Override public Rectangle getTileBounds() { int multiplier = (model.isScaleImage() ? 1 : 10); Orientation tileOrientation = model.getTileOrienation(); int xx, yy; if (tileOrientation == Orientation.EAST || tileOrientation == Orientation.WEST) { xx = tileX - GRID * multiplier - GRID * multiplier * 2; yy = tileY - GRID * multiplier; } else { xx = tileX - GRID * multiplier; yy = tileY - GRID * multiplier - GRID * multiplier * 2; } if (model.isScaleImage()) { return new Rectangle(xx, yy, tileWidth(tileOrientation, TileType.BLOCK), tileHeight(tileOrientation, TileType.BLOCK)); } else { return new Rectangle(xx, yy, renderWidth, renderHeight); } } @Override protected void paintComponent(Graphics g) { long started = System.currentTimeMillis(); Graphics2D g2 = (Graphics2D) g.create(); drawTile(g2); g2.dispose(); if (model.isOverlayImage()) { overlayLocImage(); } g.drawImage(tileImage, 0, 0, null); long now = System.currentTimeMillis(); Logger.trace(id + " Duration: " + (now - started) + " ms."); } @Override protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { //A block has 2 alternate points //1st square //2nd square holds the centerpoint //3rd square Orientation tileOrientation = model.getTileOrienation(); double dX1, dX2, dX3, dY1, dY2, dY3; if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { dX1 = renderWidth / 3 / 2 - size / 2 / 2; dY1 = renderHeight / 2 - size / 2 / 2; dX2 = renderWidth / 2 - size / 2; dY2 = renderHeight / 2 - size / 2; dX3 = renderWidth - renderWidth / 3 / 2 - size / 2 / 2; dY3 = renderHeight / 2 - size / 2 / 2; } else { dX1 = renderWidth / 2 - size / 2 / 2; dY1 = renderHeight / 3 / 2 - size / 2 / 2; dX2 = renderHeight / 2 - size / 2; dY2 = renderWidth / 2 - size / 2; dY3 = renderWidth / 2 - size / 2 / 2; dX3 = renderHeight - renderHeight / 3 / 2 - size / 2 / 2; } g2d.setColor(color); g2d.fill(new Ellipse2D.Double(dX1, dY1, size / 2, size / 2)); g2d.fill(new Ellipse2D.Double(dX2, dY2, size, size)); g2d.fill(new Ellipse2D.Double(dX3, dY3, size / 2, size / 2)); } } \ No newline at end of file diff --git a/src/main/java/jcs/ui/layout/tiles/Cross.java b/src/main/java/jcs/ui/layout/tiles/Cross.java index 4777b114..419a693f 100644 --- a/src/main/java/jcs/ui/layout/tiles/Cross.java +++ b/src/main/java/jcs/ui/layout/tiles/Cross.java @@ -1,668 +1 @@ -/* - * Copyright 2023 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout.tiles; - -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.geom.Ellipse2D; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import jcs.entities.AccessoryBean.AccessoryValue; -import static jcs.entities.AccessoryBean.AccessoryValue.GREEN; -import static jcs.entities.AccessoryBean.AccessoryValue.RED; -import jcs.entities.TileBean; -import jcs.entities.TileBean.Direction; -import jcs.entities.TileBean.Orientation; -import static jcs.entities.TileBean.Orientation.NORTH; -import static jcs.entities.TileBean.Orientation.SOUTH; -import static jcs.entities.TileBean.Orientation.WEST; -import jcs.entities.TileBean.TileType; -import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; -import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; -import static jcs.ui.layout.tiles.Tile.GRID; -import static jcs.ui.layout.tiles.Tile.tileHeight; -import static jcs.ui.layout.tiles.Tile.tileWidth; - -public class Cross extends Switch { - - public static final int CROSS_WIDTH = DEFAULT_WIDTH * 2; - public static final int CROSS_HEIGHT = DEFAULT_HEIGHT * 2; - - public static final Color VERY_LIGHT_RED = new Color(255, 102, 102); - public static final Color LIGHT_RED = new Color(255, 51, 51); - public static final Color DARK_RED = new Color(204, 0, 0); - - public static final Color VERY_LIGHT_GREEN = new Color(102, 255, 102); - public static final Color LIGHT_GREEN = new Color(0, 255, 51); - public static final Color DARK_GREEN = new Color(0, 153, 0); - - public Cross(Orientation orientation, Direction direction, Point center) { - this(orientation, direction, center.x, center.y); - } - - public Cross(Orientation orientation, Direction direction, int x, int y) { - this(orientation, direction, x, y, tileWidth(orientation, TileType.CROSS), tileHeight(orientation, TileType.CROSS)); - } - - public Cross(Orientation orientation, Direction direction, int x, int y, int width, int height) { - super(TileType.CROSS, orientation, direction, x, y, width, height); - changeRenderSizeAndOffsets(); - } - - public Cross(TileBean tileBean) { - super(tileBean, tileWidth(tileBean.getOrientation(), TileType.CROSS), tileHeight(tileBean.getOrientation(), TileType.CROSS)); - changeRenderSizeAndOffsets(); - } - - /** - * A Cross has a width in horizontal position of 2 tiles and a height of 1 tile in Vertical position.
- * - * @return the set of center point which mark the position of the Cross - */ - @Override - public Set getAltPoints() { - Set alternatives = new HashSet<>(); - - switch (getOrientation()) { - case SOUTH -> { - Point sp = new Point(tileX, (tileY + DEFAULT_HEIGHT)); - alternatives.add(sp); - } - case WEST -> { - Point wp = new Point((tileX - DEFAULT_WIDTH), tileY); - alternatives.add(wp); - } - case NORTH -> { - Point np = new Point(tileX, (tileY - DEFAULT_HEIGHT)); - alternatives.add(np); - } - default -> { - //East so default - Point ep = new Point((tileX + DEFAULT_WIDTH), tileY); - alternatives.add(ep); - } - } - return alternatives; - } - - @Override - public Map getNeighborPoints() { - Map neighbors = new HashMap<>(); - Orientation orientation = this.getOrientation(); - Direction direction = this.getDirection(); - int cx = this.getCenterX(); - int cy = this.getCenterY(); - - switch (orientation) { - case SOUTH -> { - neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); - neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 4)); - - if (Direction.LEFT == direction) { - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy + Tile.GRID * 2)); - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); - } else { - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy + Tile.GRID * 2)); - } - } - case WEST -> { - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 4, cy)); - - if (Direction.LEFT == direction) { - neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); - neighbors.put(Orientation.SOUTH, new Point(cx - Tile.GRID * 2, cy + Tile.GRID * 2)); - } else { - neighbors.put(Orientation.NORTH, new Point(cx - Tile.GRID * 2, cy - Tile.GRID * 2)); - neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); - } - } - case NORTH -> { - neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 4)); - neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); - - if (Direction.LEFT == direction) { - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy - Tile.GRID * 2)); - } else { - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy - Tile.GRID * 2)); - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); - } - } - default -> { - //EAST - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 4, cy)); - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); - - if (Direction.LEFT == direction) { - neighbors.put(Orientation.NORTH, new Point(cx + Tile.GRID * 2, cy - Tile.GRID * 2)); - neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); - } else { - neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); - neighbors.put(Orientation.SOUTH, new Point(cx + Tile.GRID * 2, cy + Tile.GRID * 2)); - } - } - } - return neighbors; - } - - @Override - public Map getEdgePoints() { - Map edgeConnections = new HashMap<>(); - Orientation orientation = this.getOrientation(); - Direction direction = this.getDirection(); - int cx = this.getCenterX(); - int cy = this.getCenterY(); - - switch (orientation) { - case SOUTH -> { - edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); - edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 3)); - - if (Direction.LEFT == direction) { - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy + Tile.GRID * 2)); - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); - } else { - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy + Tile.GRID * 2)); - } - } - case WEST -> { - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID * 3, cy)); - - if (Direction.LEFT == direction) { - edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); - edgeConnections.put(Orientation.SOUTH, new Point(cx - Tile.GRID * 2, cy + Tile.GRID)); - } else { - edgeConnections.put(Orientation.NORTH, new Point(cx - Tile.GRID * 2, cy - Tile.GRID)); - edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); - } - } - case NORTH -> { - edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 3)); - edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); - - if (Direction.LEFT == direction) { - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy - Tile.GRID * 2)); - } else { - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy - Tile.GRID * 2)); - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); - } - } - default -> { - //EAST - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID * 3, cy)); - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); - - if (Direction.LEFT == direction) { - edgeConnections.put(Orientation.NORTH, new Point(cx + Tile.GRID * 2, cy - Tile.GRID)); - edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); - } else { - edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); - edgeConnections.put(Orientation.SOUTH, new Point(cx + Tile.GRID * 2, cy + Tile.GRID)); - } - } - } - return edgeConnections; - } - - @Override - protected void renderStraight(Graphics2D g2, Color color) { - int xx, yy, w, h; - xx = 0; - yy = 170; - w = RENDER_WIDTH; - h = 60; - - g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - g2.fillRect(xx, yy, w, h); - } - - @Override - protected void renderRouteStraight(Graphics2D g2, Color color) { - int xx, yy, w, h; - xx = 0; - yy = 190; - w = RENDER_WIDTH; - h = 20; - - g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - g2.fillRect(xx, yy, w, h); - } - - protected void renderStraight2(Graphics2D g2, Color color) { - int xx, yy, w, h; - xx = RENDER_WIDTH; - yy = 170; - w = RENDER_WIDTH; - h = 60; - - g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - g2.fillRect(xx, yy, w, h); - } - - protected void renderRouteStraight2(Graphics2D g2, Color color) { - int xx, yy, w, h; - xx = RENDER_WIDTH; - yy = 190; - w = RENDER_WIDTH; - h = 20; - - g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - g2.fillRect(xx, yy, w, h); - } - - @Override - protected void renderDiagonal(Graphics2D g2, Color color) { - int[] xPoints, yPoints; - if (Direction.RIGHT.equals(getDirection())) { - xPoints = new int[]{400, 400, 167, 230}; - yPoints = new int[]{170, 230, 0, 0}; - } else { - xPoints = new int[]{400, 400, 170, 230}; - yPoints = new int[]{230, 170, 400, 400}; - } - - g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - g2.fillPolygon(xPoints, yPoints, xPoints.length); - } - - @Override - protected void renderRouteDiagonal(Graphics2D g2, Color color) { - int[] xPoints, yPoints; - if (Direction.RIGHT.equals(getDirection())) { - xPoints = new int[]{420, 400, 190, 210}; - yPoints = new int[]{210, 210, 0, 0}; - } else { - xPoints = new int[]{400, 400, 190, 210}; - yPoints = new int[]{210, 190, 400, 400}; - } - - g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - g2.fillPolygon(xPoints, yPoints, xPoints.length); - } - - protected void renderDiagonal2(Graphics2D g2, Color color) { - int[] xPoints, yPoints; - if (Direction.RIGHT.equals(getDirection())) { - xPoints = new int[]{400, 400, 570, 630}; - yPoints = new int[]{170, 230, 400, 400}; - } else { - xPoints = new int[]{400, 400, 570, 630}; - yPoints = new int[]{230, 170, 0, 0}; - } - - g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - g2.fillPolygon(xPoints, yPoints, xPoints.length); - } - - protected void renderRouteDiagonal2(Graphics2D g2, Color color) { - int[] xPoints, yPoints; - if (Direction.RIGHT.equals(getDirection())) { - xPoints = new int[]{400, 380, 590, 610}; - yPoints = new int[]{190, 190, 400, 400}; - } else { - xPoints = new int[]{400, 380, 590, 610}; - yPoints = new int[]{210, 210, 0, 0}; - } - - g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - g2.setPaint(Color.cyan); - g2.fillPolygon(xPoints, yPoints, xPoints.length); - } - - @Override - public void renderTile(Graphics2D g2) { - if (accessoryValue == null) { - this.accessoryValue = AccessoryValue.OFF; - } - - switch (accessoryValue) { - case RED -> { - renderStraight2(g2, Cross.LIGHT_RED); - renderDiagonal(g2, Cross.LIGHT_RED); - renderStraight(g2, Cross.DARK_RED); - renderDiagonal2(g2, Cross.DARK_RED); - } - case GREEN -> { - renderDiagonal(g2, Cross.VERY_LIGHT_GREEN); - renderDiagonal2(g2, Cross.VERY_LIGHT_GREEN); - renderStraight(g2, Cross.DARK_GREEN); - renderStraight2(g2, Cross.DARK_GREEN); - } - default -> { - renderStraight(g2, trackColor); - renderStraight2(g2, trackColor); - renderDiagonal(g2, trackColor); - renderDiagonal2(g2, trackColor); - } - } - } - - @Override - public void renderTileRoute(Graphics2D g2) { - if (routeValue == null) { - routeValue = AccessoryValue.OFF; - } - if (incomingSide == null) { - incomingSide = getOrientation(); - } - - if (isHorizontal()) { - if (AccessoryValue.GREEN == routeValue && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteDiagonal(g2, trackRouteColor); - renderRouteDiagonal2(g2, trackRouteColor); - } else if (AccessoryValue.GREEN == routeValue && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { - renderRouteStraight(g2, trackRouteColor); - renderRouteStraight2(g2, trackRouteColor); - } else if (AccessoryValue.RED == routeValue && Orientation.EAST == getOrientation()) { - if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { - renderRouteStraight2(g2, trackRouteColor); - renderRouteDiagonal(g2, trackRouteColor); - } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteDiagonal2(g2, trackRouteColor); - renderRouteStraight(g2, trackRouteColor); - } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteStraight2(g2, trackRouteColor); - renderRouteDiagonal(g2, trackRouteColor); - } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { - renderRouteStraight(g2, trackColor); - renderRouteDiagonal2(g2, trackColor); - } - } else if (AccessoryValue.RED == routeValue && Orientation.WEST == getOrientation()) { - if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { - renderRouteStraight(g2, trackRouteColor); - renderRouteDiagonal2(g2, trackRouteColor); - } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteDiagonal(g2, trackRouteColor); - renderRouteStraight2(g2, trackRouteColor); - } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteStraight(g2, trackRouteColor); - renderRouteDiagonal2(g2, trackRouteColor); - } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { - renderRouteStraight2(g2, trackColor); - renderRouteDiagonal(g2, trackColor); - } - } - } else { - if (AccessoryValue.GREEN == routeValue && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteStraight(g2, trackRouteColor); - renderRouteStraight2(g2, trackRouteColor); - } else if (AccessoryValue.GREEN == routeValue && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { - renderRouteDiagonal(g2, trackRouteColor); - renderRouteDiagonal2(g2, trackRouteColor); - } else if (AccessoryValue.RED == routeValue && Orientation.SOUTH == getOrientation()) { - if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteStraight2(g2, trackRouteColor); - renderRouteDiagonal(g2, trackRouteColor); - } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { - renderRouteDiagonal2(g2, trackRouteColor); - renderRouteStraight(g2, trackRouteColor); - } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { - renderRouteStraight(g2, trackRouteColor); - renderRouteDiagonal2(g2, trackRouteColor); - } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteStraight2(g2, trackColor); - renderRouteDiagonal(g2, trackColor); - } - } else if (AccessoryValue.RED == routeValue && Orientation.NORTH == getOrientation()) { - if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteStraight(g2, trackRouteColor); - renderRouteDiagonal2(g2, trackRouteColor); - } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { - renderRouteDiagonal(g2, trackRouteColor); - renderRouteStraight2(g2, trackRouteColor); - } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { - renderRouteStraight2(g2, trackRouteColor); - renderRouteDiagonal(g2, trackRouteColor); - } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteStraight(g2, trackColor); - renderRouteDiagonal2(g2, trackColor); - } - } - } - } - - @Override - public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { - if (from != null && to != null && this.getDirection() != null) { - switch (this.getDirection()) { - case LEFT -> { - if (this.isHorizontal()) { - if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { - return AccessoryValue.GREEN; - } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { - return AccessoryValue.GREEN; - } else if ((from == Orientation.NORTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.NORTH)) { - return AccessoryValue.RED; - } else if ((from == Orientation.EAST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.EAST)) { - return AccessoryValue.RED; - } else { - return AccessoryValue.OFF; - } - } else { - //Vertical - if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { - return AccessoryValue.GREEN; - } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { - return AccessoryValue.GREEN; - } else if ((from == Orientation.SOUTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.SOUTH)) { - return AccessoryValue.RED; - } else if ((from == Orientation.EAST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.EAST)) { - return AccessoryValue.RED; - } else { - return AccessoryValue.OFF; - } - } - } - case RIGHT -> { - if (this.isHorizontal()) { - if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { - return AccessoryValue.GREEN; - } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { - return AccessoryValue.GREEN; - } else if ((from == Orientation.NORTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.NORTH)) { - return AccessoryValue.RED; - } else if ((from == Orientation.WEST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.WEST)) { - return AccessoryValue.RED; - } else { - return AccessoryValue.OFF; - } - } else { - //Vertical - if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { - return AccessoryValue.GREEN; - } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { - return AccessoryValue.GREEN; - } else if ((from == Orientation.SOUTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.SOUTH)) { - return AccessoryValue.RED; - } else if ((from == Orientation.WEST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.WEST)) { - return AccessoryValue.RED; - } else { - return AccessoryValue.OFF; - } - } - } - default -> { - return AccessoryValue.OFF; - } - } - } else { - return AccessoryValue.OFF; - } - } - - @Override - protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { - //A Cross has 1 alternate point - //1st square holds the centerpoint - //2nd square - double dX1, dX2, dY1, dY2; - Orientation tileOrientation = model.getTileOrienation(); - switch (tileOrientation) { - case SOUTH -> { - dX1 = renderWidth / 2 - size / 2; - dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; - dX2 = renderWidth / 2 + renderWidth - size / 4; - dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; - } - case WEST -> { - dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; - dY1 = renderHeight / 2 - size / 2; - dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; - dY2 = renderHeight / 2 - size / 4; - } - case NORTH -> { - dX1 = renderWidth / 2 - size / 2; - dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; - dX2 = renderWidth / 2 + renderWidth - size / 4; - dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; - } - default -> { - //East - dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; - dY1 = renderHeight / 2 - size / 2; - dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; - dY2 = renderHeight / 2 - size / 4; - } - } - - g2d.setColor(color); - g2d.fill(new Ellipse2D.Double(dX1, dY1, size, size)); - g2d.fill(new Ellipse2D.Double(dX2, dY2, size / 2, size / 2)); - } - - @Override - public Rectangle getTileBounds() { - Orientation tileOrientation = model.getTileOrienation(); - int xx, yy, w, h, multiplier; - if (model.isScaleImage()) { - w = tileWidth(tileOrientation, TileType.CROSS); - h = tileHeight(tileOrientation, TileType.CROSS); - multiplier = 1; - } else { - w = renderWidth; - h = renderHeight; - multiplier = 10; - } - - switch (tileOrientation) { - case SOUTH -> { - xx = tileX - GRID * multiplier; - yy = tileY - GRID * multiplier; - } - case WEST -> { - xx = tileX - GRID * multiplier - GRID * 2 * multiplier; - yy = tileY - GRID * multiplier; - } - case NORTH -> { - xx = tileX - GRID * multiplier; - yy = tileY - GRID * multiplier - GRID * 2 * multiplier; - } - default -> { - //East - xx = tileX - GRID * multiplier; - yy = tileY - GRID * multiplier; - } - } - - if (model.isScaleImage()) { - return new Rectangle(xx, yy, tileWidth(tileOrientation, TileType.CROSS), tileHeight(tileOrientation, TileType.CROSS)); - } else { - return new Rectangle(xx, yy, renderWidth, renderHeight); - } - } - - private void changeRenderSizeAndOffsets() { - //Reset offsets - this.offsetY = 0; - this.renderOffsetY = 0; - this.offsetX = 0; - this.renderOffsetX = 0; - - if (isHorizontal()) { - this.renderWidth = RENDER_GRID * 4; - this.renderHeight = RENDER_GRID * 2; - - this.offsetY = 0; - this.renderOffsetY = 0; - } else { - this.renderWidth = RENDER_GRID * 2; - this.renderHeight = RENDER_GRID * 4; - - this.offsetX = 0; - this.renderOffsetX = 0; - } - - //Due to the asymetical shape (center is on the left) - //the offset has to be changed with the rotation - Orientation tileOrientation = model.getTileOrienation(); - switch (tileOrientation) { - case SOUTH -> { - this.offsetY = +GRID; - this.renderOffsetY = RENDER_GRID; - } - case WEST -> { - this.offsetX = -GRID; - this.renderOffsetX = -RENDER_GRID; - } - case NORTH -> { - this.offsetY = -GRID; - this.renderOffsetY = -RENDER_GRID; - } - default -> { - //East so default - this.offsetX = +GRID; - this.renderOffsetX = +RENDER_GRID; - } - } - } - - @Override - public Orientation rotate() { - super.rotate(); - - Orientation tileOrientation = model.getTileOrienation(); - int w = tileWidth(tileOrientation, TileType.CROSS); - int h = tileHeight(tileOrientation, TileType.CROSS); - - Dimension d = new Dimension(w, h); - setPreferredSize(d); - setSize(d); - changeRenderSizeAndOffsets(); - - setBounds(getTileBounds()); - return tileOrientation; - } - -} +/* * Copyright 2023 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.geom.Ellipse2D; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import jcs.entities.AccessoryBean.AccessoryValue; import static jcs.entities.AccessoryBean.AccessoryValue.GREEN; import static jcs.entities.AccessoryBean.AccessoryValue.RED; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; import static jcs.ui.layout.tiles.Tile.GRID; import static jcs.ui.layout.tiles.Tile.tileHeight; import static jcs.ui.layout.tiles.Tile.tileWidth; public class Cross extends Switch { public static final int CROSS_WIDTH = DEFAULT_WIDTH * 2; public static final int CROSS_HEIGHT = DEFAULT_HEIGHT * 2; public static final Color VERY_LIGHT_RED = new Color(255, 102, 102); public static final Color LIGHT_RED = new Color(255, 51, 51); public static final Color DARK_RED = new Color(204, 0, 0); public static final Color VERY_LIGHT_GREEN = new Color(102, 255, 102); public static final Color LIGHT_GREEN = new Color(0, 255, 51); public static final Color DARK_GREEN = new Color(0, 153, 0); public Cross(Orientation orientation, Direction direction, Point center) { this(orientation, direction, center.x, center.y); } public Cross(Orientation orientation, Direction direction, int x, int y) { this(orientation, direction, x, y, tileWidth(orientation, TileType.CROSS), tileHeight(orientation, TileType.CROSS)); } public Cross(Orientation orientation, Direction direction, int x, int y, int width, int height) { super(TileType.CROSS, orientation, direction, x, y, width, height); changeRenderSizeAndOffsets(); } public Cross(TileBean tileBean) { super(tileBean, tileWidth(tileBean.getOrientation(), TileType.CROSS), tileHeight(tileBean.getOrientation(), TileType.CROSS)); changeRenderSizeAndOffsets(); } /** * A Cross has a width in horizontal position of 2 tiles and a height of 1 tile in Vertical position.
* * @return the Set of points which mark the position of the Cross */ @Override public Set getAltPoints() { return getAltPoints(getCenter()); } @Override public Set getAllPoints() { return getAllPoints(getCenter()); } @Override public Set getAllPoints(Point center) { Set aps = getAltPoints(center); aps.add(center); return aps; } @Override Set getAltPoints(Point center) { Set alts = new HashSet<>(); switch (getOrientation()) { case SOUTH -> { Point sp = new Point(center.x, (center.y + DEFAULT_HEIGHT)); alts.add(sp); } case WEST -> { Point wp = new Point((center.x - DEFAULT_WIDTH), center.y); alts.add(wp); } case NORTH -> { Point np = new Point(center.x, (center.y - DEFAULT_HEIGHT)); alts.add(np); } default -> { //East so default Point ep = new Point((center.x + DEFAULT_WIDTH), center.y); alts.add(ep); } } return alts; } @Override public Map getNeighborPoints() { Map neighbors = new HashMap<>(); Orientation orientation = this.getOrientation(); Direction direction = this.getDirection(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 4)); if (Direction.LEFT == direction) { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy + Tile.GRID * 2)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); } else { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy + Tile.GRID * 2)); } } case WEST -> { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 4, cy)); if (Direction.LEFT == direction) { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx - Tile.GRID * 2, cy + Tile.GRID * 2)); } else { neighbors.put(Orientation.NORTH, new Point(cx - Tile.GRID * 2, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); } } case NORTH -> { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 4)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); if (Direction.LEFT == direction) { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy - Tile.GRID * 2)); } else { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy - Tile.GRID * 2)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); } } default -> { //EAST neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 4, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); if (Direction.LEFT == direction) { neighbors.put(Orientation.NORTH, new Point(cx + Tile.GRID * 2, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); } else { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx + Tile.GRID * 2, cy + Tile.GRID * 2)); } } } return neighbors; } @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); Orientation orientation = this.getOrientation(); Direction direction = this.getDirection(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 3)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy + Tile.GRID * 2)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); } else { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy + Tile.GRID * 2)); } } case WEST -> { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID * 3, cy)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx - Tile.GRID * 2, cy + Tile.GRID)); } else { edgeConnections.put(Orientation.NORTH, new Point(cx - Tile.GRID * 2, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); } } case NORTH -> { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 3)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy - Tile.GRID * 2)); } else { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy - Tile.GRID * 2)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); } } default -> { //EAST edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID * 3, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.NORTH, new Point(cx + Tile.GRID * 2, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); } else { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx + Tile.GRID * 2, cy + Tile.GRID)); } } } return edgeConnections; } @Override protected void renderStraight(Graphics2D g2, Color color) { int xx, yy, w, h; xx = 0; yy = 170; w = RENDER_WIDTH; h = 60; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } @Override protected void renderRouteStraight(Graphics2D g2, Color color) { int xx, yy, w, h; xx = 0; yy = 190; w = RENDER_WIDTH; h = 20; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } protected void renderStraight2(Graphics2D g2, Color color) { int xx, yy, w, h; xx = RENDER_WIDTH; yy = 170; w = RENDER_WIDTH; h = 60; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } protected void renderRouteStraight2(Graphics2D g2, Color color) { int xx, yy, w, h; xx = RENDER_WIDTH; yy = 190; w = RENDER_WIDTH; h = 20; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } @Override protected void renderDiagonal(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{400, 400, 167, 230}; yPoints = new int[]{170, 230, 0, 0}; } else { xPoints = new int[]{400, 400, 170, 230}; yPoints = new int[]{230, 170, 400, 400}; } g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillPolygon(xPoints, yPoints, xPoints.length); } @Override protected void renderRouteDiagonal(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{420, 400, 190, 210}; yPoints = new int[]{210, 210, 0, 0}; } else { xPoints = new int[]{400, 400, 190, 210}; yPoints = new int[]{210, 190, 400, 400}; } g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillPolygon(xPoints, yPoints, xPoints.length); } protected void renderDiagonal2(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{400, 400, 570, 630}; yPoints = new int[]{170, 230, 400, 400}; } else { xPoints = new int[]{400, 400, 570, 630}; yPoints = new int[]{230, 170, 0, 0}; } g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillPolygon(xPoints, yPoints, xPoints.length); } protected void renderRouteDiagonal2(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{400, 380, 590, 610}; yPoints = new int[]{190, 190, 400, 400}; } else { xPoints = new int[]{400, 380, 590, 610}; yPoints = new int[]{210, 210, 0, 0}; } g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.setPaint(Color.cyan); g2.fillPolygon(xPoints, yPoints, xPoints.length); } @Override public void renderTile(Graphics2D g2) { if (accessoryValue == null) { this.accessoryValue = AccessoryValue.OFF; } switch (accessoryValue) { case RED -> { renderStraight2(g2, Cross.LIGHT_RED); renderDiagonal(g2, Cross.LIGHT_RED); renderStraight(g2, Cross.DARK_RED); renderDiagonal2(g2, Cross.DARK_RED); } case GREEN -> { renderDiagonal(g2, Cross.VERY_LIGHT_GREEN); renderDiagonal2(g2, Cross.VERY_LIGHT_GREEN); renderStraight(g2, Cross.DARK_GREEN); renderStraight2(g2, Cross.DARK_GREEN); } default -> { renderStraight(g2, trackColor); renderStraight2(g2, trackColor); renderDiagonal(g2, trackColor); renderDiagonal2(g2, trackColor); } } } @Override public void renderTileRoute(Graphics2D g2) { if (routeValue == null) { routeValue = AccessoryValue.OFF; } if (incomingSide == null) { incomingSide = getOrientation(); } if (isHorizontal()) { if (AccessoryValue.GREEN == routeValue && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteDiagonal(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (AccessoryValue.GREEN == routeValue && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteStraight2(g2, trackRouteColor); } else if (AccessoryValue.RED == routeValue && Orientation.EAST == getOrientation()) { if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight2(g2, trackRouteColor); renderRouteDiagonal(g2, trackRouteColor); } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteDiagonal2(g2, trackRouteColor); renderRouteStraight(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight2(g2, trackRouteColor); renderRouteDiagonal(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight(g2, trackColor); renderRouteDiagonal2(g2, trackColor); } } else if (AccessoryValue.RED == routeValue && Orientation.WEST == getOrientation()) { if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteDiagonal(g2, trackRouteColor); renderRouteStraight2(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight2(g2, trackColor); renderRouteDiagonal(g2, trackColor); } } } else { if (AccessoryValue.GREEN == routeValue && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteStraight2(g2, trackRouteColor); } else if (AccessoryValue.GREEN == routeValue && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { renderRouteDiagonal(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (AccessoryValue.RED == routeValue && Orientation.SOUTH == getOrientation()) { if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight2(g2, trackRouteColor); renderRouteDiagonal(g2, trackRouteColor); } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteDiagonal2(g2, trackRouteColor); renderRouteStraight(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight2(g2, trackColor); renderRouteDiagonal(g2, trackColor); } } else if (AccessoryValue.RED == routeValue && Orientation.NORTH == getOrientation()) { if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteDiagonal(g2, trackRouteColor); renderRouteStraight2(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight2(g2, trackRouteColor); renderRouteDiagonal(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight(g2, trackColor); renderRouteDiagonal2(g2, trackColor); } } } } @Override public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { if (from != null && to != null && this.getDirection() != null) { switch (this.getDirection()) { case LEFT -> { if (this.isHorizontal()) { if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.NORTH)) { return AccessoryValue.RED; } else if ((from == Orientation.EAST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.EAST)) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } else { //Vertical if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if ((from == Orientation.SOUTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.SOUTH)) { return AccessoryValue.RED; } else if ((from == Orientation.EAST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.EAST)) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } } case RIGHT -> { if (this.isHorizontal()) { if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.NORTH)) { return AccessoryValue.RED; } else if ((from == Orientation.WEST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.WEST)) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } else { //Vertical if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if ((from == Orientation.SOUTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.SOUTH)) { return AccessoryValue.RED; } else if ((from == Orientation.WEST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.WEST)) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } } default -> { return AccessoryValue.OFF; } } } else { return AccessoryValue.OFF; } } @Override protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { //A Cross has 1 alternate point //1st square holds the centerpoint //2nd square double dX1, dX2, dY1, dY2; Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case SOUTH -> { dX1 = renderWidth / 2 - size / 2; dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; dX2 = renderWidth / 2 + renderWidth - size / 4; dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; } case WEST -> { dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; dY1 = renderHeight / 2 - size / 2; dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; dY2 = renderHeight / 2 - size / 4; } case NORTH -> { dX1 = renderWidth / 2 - size / 2; dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; dX2 = renderWidth / 2 + renderWidth - size / 4; dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; } default -> { //East dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; dY1 = renderHeight / 2 - size / 2; dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; dY2 = renderHeight / 2 - size / 4; } } g2d.setColor(color); g2d.fill(new Ellipse2D.Double(dX1, dY1, size, size)); g2d.fill(new Ellipse2D.Double(dX2, dY2, size / 2, size / 2)); } @Override public Rectangle getTileBounds() { Orientation tileOrientation = model.getTileOrienation(); int xx, yy, w, h, multiplier; if (model.isScaleImage()) { w = tileWidth(tileOrientation, TileType.CROSS); h = tileHeight(tileOrientation, TileType.CROSS); multiplier = 1; } else { w = renderWidth; h = renderHeight; multiplier = 10; } switch (tileOrientation) { case SOUTH -> { xx = tileX - GRID * multiplier; yy = tileY - GRID * multiplier; } case WEST -> { xx = tileX - GRID * multiplier - GRID * 2 * multiplier; yy = tileY - GRID * multiplier; } case NORTH -> { xx = tileX - GRID * multiplier; yy = tileY - GRID * multiplier - GRID * 2 * multiplier; } default -> { //East xx = tileX - GRID * multiplier; yy = tileY - GRID * multiplier; } } if (model.isScaleImage()) { return new Rectangle(xx, yy, w, h); } else { return new Rectangle(xx, yy, renderWidth, renderHeight); } } private void changeRenderSizeAndOffsets() { //Reset offsets this.offsetY = 0; this.renderOffsetY = 0; this.offsetX = 0; this.renderOffsetX = 0; if (isHorizontal()) { this.renderWidth = RENDER_GRID * 4; this.renderHeight = RENDER_GRID * 2; this.offsetY = 0; this.renderOffsetY = 0; } else { this.renderWidth = RENDER_GRID * 2; this.renderHeight = RENDER_GRID * 4; this.offsetX = 0; this.renderOffsetX = 0; } //Due to the asymetical shape (center is on the left) //the offset has to be changed with the rotation Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case SOUTH -> { this.offsetY = +GRID; this.renderOffsetY = RENDER_GRID; } case WEST -> { this.offsetX = -GRID; this.renderOffsetX = -RENDER_GRID; } case NORTH -> { this.offsetY = -GRID; this.renderOffsetY = -RENDER_GRID; } default -> { //East so default this.offsetX = +GRID; this.renderOffsetX = +RENDER_GRID; } } } @Override public Orientation rotate() { super.rotate(); Orientation tileOrientation = model.getTileOrienation(); int w = tileWidth(tileOrientation, TileType.CROSS); int h = tileHeight(tileOrientation, TileType.CROSS); Dimension d = new Dimension(w, h); setPreferredSize(d); setSize(d); changeRenderSizeAndOffsets(); setBounds(getTileBounds()); return tileOrientation; } } \ No newline at end of file diff --git a/src/main/java/jcs/ui/layout/tiles/Crossing.java b/src/main/java/jcs/ui/layout/tiles/Crossing.java index c9813112..59e62085 100644 --- a/src/main/java/jcs/ui/layout/tiles/Crossing.java +++ b/src/main/java/jcs/ui/layout/tiles/Crossing.java @@ -1,149 +1 @@ -/* - * Copyright 2023 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout.tiles; - -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.Point; -import java.util.HashMap; -import java.util.Map; -import jcs.entities.TileBean; -import jcs.entities.TileBean.Orientation; -import jcs.entities.TileBean.TileType; - -public class Crossing extends Straight { - - public Crossing(TileBean tileBean) { - super(tileBean); - } - - public Crossing(Orientation orientation, Point center) { - this(orientation, center.x, center.y); - } - - public Crossing(Orientation orientation, int x, int y) { - this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); - } - - public Crossing(Orientation orientation, int x, int y, int width, int height) { - super(orientation, x, y, width, height); - this.tileType = TileType.CROSSING; - } - - @Override - public Map getNeighborPoints() { - Map neighbors = new HashMap<>(); - int cx = this.getCenterX(); - int cy = this.getCenterY(); - - // Horizontal - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); - // Vertical - neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); - neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); - return neighbors; - } - - @Override - public Map getEdgePoints() { - Map edgeConnections = new HashMap<>(); - int cx = this.getCenterX(); - int cy = this.getCenterY(); - - // Horizontal - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); - // Vertical - edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); - edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); - return edgeConnections; - } - - protected void renderVerticalAndDividers(Graphics2D g2) { - int xxn, yyn, xxs, yys, w, h; - xxn = 175; - yyn = 0; - xxs = 175; - yys = 325; - w = 50; - h = 75; - - g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); - g2.setPaint(trackColor); - - //North - g2.fillRect(xxn, yyn, w, h); - //South - g2.fillRect(xxs, yys, w, h); - - //Dividers - int[] xNorthPoly = new int[]{85, 115, 285, 315}; - int[] yNorthPoly = new int[]{85, 125, 125, 85}; - - int[] xSouthPoly = new int[]{85, 115, 285, 315}; - int[] ySouthPoly = new int[]{315, 275, 275, 315}; - - g2.setPaint(Color.darkGray); - g2.setStroke(new BasicStroke(8, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - - g2.drawPolyline(xNorthPoly, yNorthPoly, xNorthPoly.length); - g2.drawPolyline(xSouthPoly, ySouthPoly, xSouthPoly.length); - } - - @Override - public void renderTile(Graphics2D g2) { - renderStraight(g2); - renderVerticalAndDividers(g2); - } - - protected void renderRouteVertical(Graphics2D g2) { - int xxn, yyn, xxs, yys, w, h; - xxn = 190; - yyn = 0; - xxs = 190; - yys = 325; - w = 20; - h = 75; - - g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); - g2.setPaint(this.trackRouteColor); - - //North - g2.fillRect(xxn, yyn, w, h); - //South - g2.fillRect(xxs, yys, w, h); - } - -// @Override -// public void renderTileRoute(Graphics2D g2) { -// if (isHorizontal()) { -// if (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide) { -// renderRouteStraight(g2); -// } else { -// renderRouteVertical(g2); -// } -// } else { -// if (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide) { -// renderRouteStraight(g2); -// } else { -// renderRouteVertical(g2); -// } -// } -// } - -} +/* * Copyright 2023 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Point; import java.util.HashMap; import java.util.Map; import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; import jcs.entities.TileBean.TileType; public class Crossing extends Straight { public Crossing(TileBean tileBean) { super(tileBean); } public Crossing(Orientation orientation, Point center) { this(orientation, center.x, center.y); } public Crossing(Orientation orientation, int x, int y) { this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); } public Crossing(Orientation orientation, int x, int y, int width, int height) { super(orientation, x, y, width, height); this.tileType = TileType.CROSSING; } @Override public Map getNeighborPoints() { Map neighbors = new HashMap<>(); int cx = this.getCenterX(); int cy = this.getCenterY(); // Horizontal neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); // Vertical neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); return neighbors; } @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); int cx = this.getCenterX(); int cy = this.getCenterY(); // Horizontal edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); // Vertical edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); return edgeConnections; } protected void renderVerticalAndDividers(Graphics2D g2) { int xxn, yyn, xxs, yys, w, h; xxn = 175; yyn = 0; xxs = 175; yys = 325; w = 50; h = 75; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(trackColor); //North g2.fillRect(xxn, yyn, w, h); //South g2.fillRect(xxs, yys, w, h); //Dividers int[] xNorthPoly = new int[]{85, 115, 285, 315}; int[] yNorthPoly = new int[]{85, 125, 125, 85}; int[] xSouthPoly = new int[]{85, 115, 285, 315}; int[] ySouthPoly = new int[]{315, 275, 275, 315}; g2.setPaint(Color.darkGray); g2.setStroke(new BasicStroke(8, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.drawPolyline(xNorthPoly, yNorthPoly, xNorthPoly.length); g2.drawPolyline(xSouthPoly, ySouthPoly, xSouthPoly.length); } @Override public void renderTile(Graphics2D g2) { renderStraight(g2); renderVerticalAndDividers(g2); } protected void renderRouteVertical(Graphics2D g2) { int xxn, yyn, xxs, yys, w, h; xxn = 190; yyn = 0; xxs = 190; yys = 325; w = 20; h = 75; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(this.trackRouteColor); //North g2.fillRect(xxn, yyn, w, h); //South g2.fillRect(xxs, yys, w, h); } } \ No newline at end of file diff --git a/src/main/java/jcs/ui/layout/tiles/Curved.java b/src/main/java/jcs/ui/layout/tiles/Curved.java index 0de19ed3..c16fa01b 100755 --- a/src/main/java/jcs/ui/layout/tiles/Curved.java +++ b/src/main/java/jcs/ui/layout/tiles/Curved.java @@ -1,161 +1 @@ -/* - * Copyright 2023 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout.tiles; - -import java.awt.BasicStroke; -import java.awt.Graphics2D; -import java.awt.Point; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import jcs.entities.TileBean; -import jcs.entities.TileBean.Orientation; -import static jcs.entities.TileBean.Orientation.NORTH; -import static jcs.entities.TileBean.Orientation.SOUTH; -import static jcs.entities.TileBean.Orientation.WEST; -import jcs.entities.TileBean.TileType; - -public class Curved extends Tile { - - public Curved(TileBean tileBean) { - super(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); - setModel(new DefaultTileModel(tileBean.getOrientation())); - } - - public Curved(Orientation orientation, Point center) { - this(orientation, center.x, center.y); - } - - public Curved(Orientation orientation, int x, int y) { - this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); - } - - public Curved(Orientation orientation, int x, int y, int width, int height) { - super(TileType.CURVED, orientation, x, y, width, height); - setModel(new DefaultTileModel(orientation)); - } - - @Override - public Map getNeighborPoints() { - Map neighbors = new HashMap<>(); - Orientation orientation = this.getOrientation(); - int cx = this.getCenterX(); - int cy = this.getCenterY(); - - switch (orientation) { - case SOUTH -> { - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); - neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); - } - case WEST -> { - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); - neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); - } - case NORTH -> { - neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); - } - default -> { - //EAST - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); - neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); - } - } - return neighbors; - } - - @Override - public Map getEdgePoints() { - Map edgeConnections = new HashMap<>(); - - Orientation orientation = this.getOrientation(); - int cx = this.getCenterX(); - int cy = this.getCenterY(); - - switch (orientation) { - case SOUTH -> { - // | | - // b \ |\ | - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); - edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); - } - case WEST -> { - // |/ | - // t / | | - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); - edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); - } - case NORTH -> { - // t \ - edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); - } - default -> { - //EAST b / - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); - edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); - } - } - return edgeConnections; - } - - @Override - public Set getAllPoints() { - Set aps = new HashSet<>(); - aps.add(getCenter()); - return aps; - } - - @Override - public void renderTile(Graphics2D g2) { - int[] xPoints = new int[]{400, 400, 170, 230}; - int[] yPoints = new int[]{230, 170, 400, 400}; - - g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - g2.setPaint(trackColor); - - g2.fillPolygon(xPoints, yPoints, xPoints.length); - } - - @Override - public void renderTileRoute(Graphics2D g2) { - int[] xPoints = new int[]{400, 400, 190, 210}; - int[] yPoints = new int[]{210, 190, 400, 400}; - - g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - g2.setPaint(trackRouteColor); - - g2.fillPolygon(xPoints, yPoints, xPoints.length); - } - -// @Override -// protected void paintComponent(Graphics g) { -// long started = System.currentTimeMillis(); -// super.paintComponent(g); -// -// setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); -// -// Graphics2D g2 = (Graphics2D) g.create(); -// drawTile(g2); -// g2.dispose(); -// -// g.drawImage(this.tileImage, 0, 0, null); -// -// long now = System.currentTimeMillis(); -// Logger.trace(this.id + " Duration: " + (now - started) + " ms."); -// } -} +/* * Copyright 2023 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.BasicStroke; import java.awt.Graphics2D; import java.awt.Point; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; public class Curved extends Tile { public Curved(TileBean tileBean) { super(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); setModel(new DefaultTileModel(tileBean.getOrientation())); } public Curved(Orientation orientation, Point center) { this(orientation, center.x, center.y); } public Curved(Orientation orientation, int x, int y) { this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); } public Curved(Orientation orientation, int x, int y, int width, int height) { super(TileType.CURVED, orientation, x, y, width, height); setModel(new DefaultTileModel(orientation)); } @Override public Map getNeighborPoints() { Map neighbors = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> { neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); } case WEST -> { neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); } case NORTH -> { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); } default -> { //EAST neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); } } return neighbors; } @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> { // | | // b \ |\ | edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); } case WEST -> { // |/ | // t / | | edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); } case NORTH -> { // t \ edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); } default -> { //EAST b / edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); } } return edgeConnections; } @Override public void renderTile(Graphics2D g2) { int[] xPoints = new int[]{400, 400, 170, 230}; int[] yPoints = new int[]{230, 170, 400, 400}; g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(trackColor); g2.fillPolygon(xPoints, yPoints, xPoints.length); } @Override public void renderTileRoute(Graphics2D g2) { int[] xPoints = new int[]{400, 400, 190, 210}; int[] yPoints = new int[]{210, 190, 400, 400}; g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(trackRouteColor); g2.fillPolygon(xPoints, yPoints, xPoints.length); } // @Override // protected void paintComponent(Graphics g) { // long started = System.currentTimeMillis(); // super.paintComponent(g); // // setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); // // Graphics2D g2 = (Graphics2D) g.create(); // drawTile(g2); // g2.dispose(); // // g.drawImage(this.tileImage, 0, 0, null); // // long now = System.currentTimeMillis(); // Logger.trace(this.id + " Duration: " + (now - started) + " ms."); // } } \ No newline at end of file diff --git a/src/main/java/jcs/ui/layout/tiles/End.java b/src/main/java/jcs/ui/layout/tiles/End.java index e71da407..79b10135 100644 --- a/src/main/java/jcs/ui/layout/tiles/End.java +++ b/src/main/java/jcs/ui/layout/tiles/End.java @@ -1,147 +1 @@ -/* - * Copyright 2023 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout.tiles; - -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.Point; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import jcs.entities.TileBean; -import jcs.entities.TileBean.Orientation; -import static jcs.entities.TileBean.Orientation.NORTH; -import static jcs.entities.TileBean.Orientation.SOUTH; -import static jcs.entities.TileBean.Orientation.WEST; -import jcs.entities.TileBean.TileType; - -public class End extends Tile { - - public End(TileBean tileBean) { - super(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); - setModel(new DefaultTileModel(tileBean.getOrientation())); - } - - public End(Orientation orientation, Point center) { - this(orientation, center.x, center.y); - } - - public End(Orientation orientation, int x, int y) { - this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); - } - - public End(Orientation orientation, int x, int y, int width, int height) { - super(TileType.END, orientation, x, y, width, height); - setModel(new DefaultTileModel(orientation)); - } - - @Override - public Map getNeighborPoints() { - Map neighbors = new HashMap<>(); - Orientation orientation = this.getOrientation(); - int cx = this.getCenterX(); - int cy = this.getCenterY(); - - switch (orientation) { - case SOUTH -> - neighbors.put(Orientation.SOUTH, new Point(cx, cy - Tile.GRID * 2)); - case WEST -> - neighbors.put(Orientation.WEST, new Point(cx + Tile.GRID * 2, cy)); - case NORTH -> - neighbors.put(Orientation.NORTH, new Point(cx, cy + Tile.GRID * 2)); - default -> //EAST - neighbors.put(Orientation.EAST, new Point(cx - Tile.GRID * 2, cy)); - } - return neighbors; - } - - @Override - public Set getAllPoints() { - Set aps = new HashSet<>(); - aps.add(getCenter()); - return aps; - } - - @Override - public Map getEdgePoints() { - Map edgeConnections = new HashMap<>(); - Orientation orientation = this.getOrientation(); - int cx = this.getCenterX(); - int cy = this.getCenterY(); - - switch (orientation) { - case SOUTH -> - edgeConnections.put(Orientation.SOUTH, new Point(cx, cy - Tile.GRID)); - case WEST -> - edgeConnections.put(Orientation.WEST, new Point(cx + Tile.GRID, cy)); - case NORTH -> - edgeConnections.put(Orientation.NORTH, new Point(cx, cy + Tile.GRID)); - default -> //EAST - edgeConnections.put(Orientation.EAST, new Point(cx - Tile.GRID, cy)); - } - return edgeConnections; - } - - protected void renderEnd(Graphics2D g2) { - int xx, yy, w, h; - xx = 0; - yy = 175; - - w = RENDER_GRID; - h = 50; - - g2.setStroke(new BasicStroke(40, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); - g2.setPaint(trackColor); - g2.fillRect(xx, yy, w, h); - - xx = RENDER_GRID; - yy = 100; - - w = 30; - h = 200; - - g2.setPaint(Color.DARK_GRAY); - g2.fillRect(xx, yy, w, h); - } - - @Override - public void renderTile(Graphics2D g2) { - renderEnd(g2); - } - - @Override - public void renderTileRoute(Graphics2D g2d) { - } - -// @Override -// protected void paintComponent(Graphics g) { -// long started = System.currentTimeMillis(); -// super.paintComponent(g); -// -// setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); -// -// Graphics2D g2 = (Graphics2D) g.create(); -// drawTile(g2); -// g2.dispose(); -// -// g.drawImage(this.tileImage, 0, 0, null); -// -// long now = System.currentTimeMillis(); -// Logger.trace(this.id + " Duration: " + (now - started) + " ms."); -// } -} +/* * Copyright 2023 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Point; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; public class End extends Tile { public End(TileBean tileBean) { super(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); setModel(new DefaultTileModel(tileBean.getOrientation())); } public End(Orientation orientation, Point center) { this(orientation, center.x, center.y); } public End(Orientation orientation, int x, int y) { this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); } public End(Orientation orientation, int x, int y, int width, int height) { super(TileType.END, orientation, x, y, width, height); setModel(new DefaultTileModel(orientation)); } @Override public Map getNeighborPoints() { Map neighbors = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> neighbors.put(Orientation.SOUTH, new Point(cx, cy - Tile.GRID * 2)); case WEST -> neighbors.put(Orientation.WEST, new Point(cx + Tile.GRID * 2, cy)); case NORTH -> neighbors.put(Orientation.NORTH, new Point(cx, cy + Tile.GRID * 2)); default -> //EAST neighbors.put(Orientation.EAST, new Point(cx - Tile.GRID * 2, cy)); } return neighbors; } @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> edgeConnections.put(Orientation.SOUTH, new Point(cx, cy - Tile.GRID)); case WEST -> edgeConnections.put(Orientation.WEST, new Point(cx + Tile.GRID, cy)); case NORTH -> edgeConnections.put(Orientation.NORTH, new Point(cx, cy + Tile.GRID)); default -> //EAST edgeConnections.put(Orientation.EAST, new Point(cx - Tile.GRID, cy)); } return edgeConnections; } protected void renderEnd(Graphics2D g2) { int xx, yy, w, h; xx = 0; yy = 175; w = RENDER_GRID; h = 50; g2.setStroke(new BasicStroke(40, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(trackColor); g2.fillRect(xx, yy, w, h); xx = RENDER_GRID; yy = 100; w = 30; h = 200; g2.setPaint(Color.DARK_GRAY); g2.fillRect(xx, yy, w, h); } @Override public void renderTile(Graphics2D g2) { renderEnd(g2); } @Override public void renderTileRoute(Graphics2D g2d) { } // @Override // protected void paintComponent(Graphics g) { // long started = System.currentTimeMillis(); // super.paintComponent(g); // // setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); // // Graphics2D g2 = (Graphics2D) g.create(); // drawTile(g2); // g2.dispose(); // // g.drawImage(this.tileImage, 0, 0, null); // // long now = System.currentTimeMillis(); // Logger.trace(this.id + " Duration: " + (now - started) + " ms."); // } } \ No newline at end of file diff --git a/src/main/java/jcs/ui/layout/tiles/Straight.java b/src/main/java/jcs/ui/layout/tiles/Straight.java index 9cc63d74..e34552ca 100755 --- a/src/main/java/jcs/ui/layout/tiles/Straight.java +++ b/src/main/java/jcs/ui/layout/tiles/Straight.java @@ -1,147 +1 @@ -/* - * Copyright 2023 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout.tiles; - -import java.awt.BasicStroke; -import java.awt.Graphics2D; -import java.awt.Point; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import jcs.entities.TileBean; -import jcs.entities.TileBean.Orientation; -import jcs.entities.TileBean.TileType; - -public class Straight extends Tile { - - public Straight(TileBean tileBean) { - super(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); - setModel(new DefaultTileModel(tileBean.getOrientation())); - } - - public Straight(Orientation orientation, Point center) { - this(orientation, center.x, center.y); - } - - public Straight(Orientation orientation, int x, int y) { - this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); - } - - public Straight(Orientation orientation, int x, int y, int width, int height) { - super(TileType.STRAIGHT, orientation, x, y, width, height); - setModel(new DefaultTileModel(orientation)); - } - - @Override - public Map getNeighborPoints() { - Map neighbors = new HashMap<>(); - Orientation orientation = this.getOrientation(); - int cx = this.getCenterX(); - int cy = this.getCenterY(); - - if (Orientation.EAST == orientation || Orientation.WEST == orientation) { - // Horizontal - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); - } else { - // Vertical - neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); - neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); - } - return neighbors; - } - - @Override - public Map getEdgePoints() { - Map edgeConnections = new HashMap<>(); - Orientation orientation = this.getOrientation(); - int cx = this.getCenterX(); - int cy = this.getCenterY(); - - if (Orientation.EAST == orientation || Orientation.WEST == orientation) { - // Horizontal - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); - } else { - // Vertical - edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); - edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); - } - return edgeConnections; - } - - @Override - public Set getAllPoints() { - Set aps = new HashSet<>(); - aps.add(getCenter()); - return aps; - } - - protected void renderStraight(Graphics2D g2) { - int xx, yy, w, h; - xx = 0; - yy = 170; - w = RENDER_WIDTH; - h = 60; - - g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); - g2.setPaint(trackColor); - - g2.fillRect(xx, yy, w, h); - } - - protected void renderRouteStraight(Graphics2D g2) { - int xx, yy, w, h; - xx = 0; - yy = 190; - w = RENDER_WIDTH; - h = 20; - - g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); - g2.setPaint(trackRouteColor); - - g2.fillRect(xx, yy, w, h); - } - - @Override - public void renderTileRoute(Graphics2D g2) { - renderRouteStraight(g2); - } - - @Override - public void renderTile(Graphics2D g2) { - renderStraight(g2); - } - -// @Override -// protected void paintComponent(Graphics g) { -// long started = System.currentTimeMillis(); -// super.paintComponent(g); -// -// setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); -// -// Graphics2D g2 = (Graphics2D) g.create(); -// drawTile(g2); -// g2.dispose(); -// -// g.drawImage(this.tileImage, 0, 0, null); -// -// long now = System.currentTimeMillis(); -// Logger.trace(this.id + " Duration: " + (now - started) + " ms."); -// } - -} +/* * Copyright 2023 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.BasicStroke; import java.awt.Graphics2D; import java.awt.Point; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; import jcs.entities.TileBean.TileType; public class Straight extends Tile { public Straight(TileBean tileBean) { super(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); setModel(new DefaultTileModel(tileBean.getOrientation())); } public Straight(Orientation orientation, Point center) { this(orientation, center.x, center.y); } public Straight(Orientation orientation, int x, int y) { this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); } public Straight(Orientation orientation, int x, int y, int width, int height) { super(TileType.STRAIGHT, orientation, x, y, width, height); setModel(new DefaultTileModel(orientation)); } @Override public Map getNeighborPoints() { Map neighbors = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); if (Orientation.EAST == orientation || Orientation.WEST == orientation) { // Horizontal neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); } else { // Vertical neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); } return neighbors; } @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); if (Orientation.EAST == orientation || Orientation.WEST == orientation) { // Horizontal edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); } else { // Vertical edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); } return edgeConnections; } protected void renderStraight(Graphics2D g2) { int xx, yy, w, h; xx = 0; yy = 170; w = RENDER_WIDTH; h = 60; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(trackColor); g2.fillRect(xx, yy, w, h); } protected void renderRouteStraight(Graphics2D g2) { int xx, yy, w, h; xx = 0; yy = 190; w = RENDER_WIDTH; h = 20; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(trackRouteColor); g2.fillRect(xx, yy, w, h); } @Override public void renderTileRoute(Graphics2D g2) { renderRouteStraight(g2); } @Override public void renderTile(Graphics2D g2) { renderStraight(g2); } } \ No newline at end of file diff --git a/src/main/java/jcs/ui/layout/tiles/Switch.java b/src/main/java/jcs/ui/layout/tiles/Switch.java index abfd920f..9dd3a651 100644 --- a/src/main/java/jcs/ui/layout/tiles/Switch.java +++ b/src/main/java/jcs/ui/layout/tiles/Switch.java @@ -1,361 +1 @@ -/* - * Copyright 2023 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout.tiles; - -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.Point; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import jcs.commandStation.events.AccessoryEvent; -import jcs.commandStation.events.AccessoryEventListener; -import jcs.entities.AccessoryBean.AccessoryValue; -import static jcs.entities.AccessoryBean.AccessoryValue.GREEN; -import static jcs.entities.AccessoryBean.AccessoryValue.RED; -import jcs.entities.TileBean; -import jcs.entities.TileBean.Direction; -import static jcs.entities.TileBean.Direction.LEFT; -import static jcs.entities.TileBean.Direction.RIGHT; -import jcs.entities.TileBean.Orientation; -import static jcs.entities.TileBean.Orientation.NORTH; -import static jcs.entities.TileBean.Orientation.SOUTH; -import static jcs.entities.TileBean.Orientation.WEST; -import jcs.entities.TileBean.TileType; - -public class Switch extends Tile implements AccessoryEventListener { - - public Switch(Orientation orientation, Direction direction, Point center) { - this(orientation, direction, center.x, center.y); - } - - public Switch(Orientation orientation, Direction direction, int x, int y) { - this(orientation, direction, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); - } - - public Switch(Orientation orientation, Direction direction, int x, int y, int width, int height) { - this(TileType.SWITCH, orientation, direction, x, y, width, height); - } - - protected Switch(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { - super(tileType, orientation, direction, x, y, width, height); - setModel(new DefaultTileModel(orientation)); - } - - public Switch(TileBean tileBean) { - this(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); - } - - protected Switch(TileBean tileBean, int width, int height) { - super(tileBean, width, height); - setModel(new DefaultTileModel(tileBean.getOrientation())); - } - - @Override - public Map getNeighborPoints() { - Map neighbors = new HashMap<>(); - Orientation orientation = this.getOrientation(); - Direction direction = this.getDirection(); - int cx = this.getCenterX(); - int cy = this.getCenterY(); - - switch (orientation) { - case SOUTH -> { - neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); - neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); - if (Direction.LEFT == direction) { - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); - } else { - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); - } - } - case WEST -> { - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); - if (Direction.LEFT == direction) { - neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); - } else { - neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); - } - } - case NORTH -> { - neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); - neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); - if (Direction.LEFT == direction) { - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); - } else { - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); - } - } - default -> { - //EAST - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); - if (Direction.LEFT == direction) { - neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); - } else { - neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); - } - } - } - return neighbors; - } - - @Override - public Map getEdgePoints() { - Map edgeConnections = new HashMap<>(); - Orientation orientation = this.getOrientation(); - Direction direction = this.getDirection(); - int cx = this.getCenterX(); - int cy = this.getCenterY(); - - switch (orientation) { - case SOUTH -> { - edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); - edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); - if (Direction.LEFT == direction) { - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); - } else { - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); - } - } - case WEST -> { - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); - if (Direction.LEFT == direction) { - edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); - } else { - edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); - } - } - case NORTH -> { - edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); - edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); - if (Direction.LEFT == direction) { - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); - } else { - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); - } - } - default -> { - //EAST - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); - if (Direction.LEFT == direction) { - edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); - } else { - edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); - } - } - } - return edgeConnections; - } - - @Override - public Set getAllPoints() { - Set aps = new HashSet<>(); - aps.add(getCenter()); - return aps; - } - - protected void renderStraight(Graphics2D g2, Color color) { - int xx, yy, w, h; - xx = 0; - yy = 170; - w = RENDER_WIDTH; - h = 60; - - g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - - g2.fillRect(xx, yy, w, h); - } - - protected void renderDiagonal(Graphics2D g2, Color color) { - int[] xPoints, yPoints; - if (Direction.RIGHT.equals(getDirection())) { - xPoints = new int[]{400, 400, 170, 230}; - yPoints = new int[]{170, 230, 0, 0}; - } else { - xPoints = new int[]{400, 400, 170, 230}; - yPoints = new int[]{230, 170, 400, 400}; - } - - g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - g2.fillPolygon(xPoints, yPoints, xPoints.length); - } - - protected void renderRouteStraight(Graphics2D g2, Color color) { - int xx, yy, w, h; - xx = 0; - yy = 190; - w = RENDER_WIDTH; - h = 20; - - g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - - g2.fillRect(xx, yy, w, h); - } - - protected void renderRouteDiagonal(Graphics2D g2, Color color) { - int[] xPoints, yPoints; - if (Direction.RIGHT.equals(getDirection())) { - xPoints = new int[]{400, 400, 190, 210}; - yPoints = new int[]{190, 210, 0, 0}; - } else { - xPoints = new int[]{400, 400, 190, 210}; - yPoints = new int[]{210, 190, 400, 400}; - } - - g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - - g2.fillPolygon(xPoints, yPoints, xPoints.length); - } - - @Override - public void renderTile(Graphics2D g2) { - if (accessoryValue == null) { - this.accessoryValue = AccessoryValue.OFF; - } - - switch (accessoryValue) { - case RED -> { - renderStraight(g2, trackColor); - renderDiagonal(g2, Color.red); - } - case GREEN -> { - renderDiagonal(g2, trackColor); - renderStraight(g2, Color.green); - } - default -> { - renderStraight(g2, trackColor); - renderDiagonal(g2, trackColor); - } - } - } - - @Override - public void renderTileRoute(Graphics2D g2) { - if (routeValue == null) { - routeValue = AccessoryValue.OFF; - } - switch (routeValue) { - case RED -> { - renderRouteDiagonal(g2, trackRouteColor); - } - case GREEN -> { - renderRouteStraight(g2, trackRouteColor); - } - default -> { - } - } - } - - @Override - public void onAccessoryChange(AccessoryEvent event) { - if (getAccessoryBean() != null && event.isEventFor(accessoryBean)) { - setAccessoryValue(event.getAccessoryBean().getAccessoryValue()); - } - } - - @Override - public boolean isJunction() { - return true; - } - - @Override - public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { - if (from != null && to != null && this.getDirection() != null) { - switch (this.getDirection()) { - case LEFT -> { - if (this.isHorizontal()) { - if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { - return AccessoryValue.GREEN; - } else if (((from == Orientation.EAST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.EAST)) && Orientation.EAST == this.getOrientation()) { - return AccessoryValue.RED; - } else if (((from == Orientation.WEST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.WEST)) && Orientation.WEST == this.getOrientation()) { - return AccessoryValue.RED; - } else { - return AccessoryValue.OFF; - } - } else { - //Vertical - if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { - return AccessoryValue.GREEN; - } else if (((from == Orientation.SOUTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.SOUTH)) && Orientation.SOUTH == this.getOrientation()) { - return AccessoryValue.RED; - } else if (((from == Orientation.NORTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.NORTH)) && Orientation.NORTH == this.getOrientation()) { - return AccessoryValue.RED; - } else { - return AccessoryValue.OFF; - } - } - } - case RIGHT -> { - if (this.isHorizontal()) { - if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { - return AccessoryValue.GREEN; - } else if (((from == Orientation.EAST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.EAST)) && Orientation.EAST == this.getOrientation()) { - return AccessoryValue.RED; - } else if (((from == Orientation.WEST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.WEST)) && Orientation.WEST == this.getOrientation()) { - return AccessoryValue.RED; - } else { - return AccessoryValue.OFF; - } - } else { - //Vertical - if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { - return AccessoryValue.GREEN; - } else if (((from == Orientation.EAST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.EAST)) && Orientation.SOUTH == this.getOrientation()) { - return AccessoryValue.RED; - } else if (((from == Orientation.WEST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.WEST)) && Orientation.NORTH == this.getOrientation()) { - return AccessoryValue.RED; - } else { - return AccessoryValue.OFF; - } - } - } - default -> { - return AccessoryValue.OFF; - } - } - } else { - return AccessoryValue.OFF; - } - } - -// @Override -// protected void paintComponent(Graphics g) { -// long started = System.currentTimeMillis(); -// super.paintComponent(g); -// -// setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); -// -// Graphics2D g2 = (Graphics2D) g.create(); -// drawTile(g2); -// g2.dispose(); -// -// g.drawImage(this.tileImage, 0, 0, null); -// -// long now = System.currentTimeMillis(); -// Logger.trace(this.id + " Duration: " + (now - started) + " ms."); -// } -} +/* * Copyright 2023 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Point; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import jcs.commandStation.events.AccessoryEvent; import jcs.commandStation.events.AccessoryEventListener; import jcs.entities.AccessoryBean.AccessoryValue; import static jcs.entities.AccessoryBean.AccessoryValue.GREEN; import static jcs.entities.AccessoryBean.AccessoryValue.RED; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import static jcs.entities.TileBean.Direction.LEFT; import static jcs.entities.TileBean.Direction.RIGHT; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; public class Switch extends Tile implements AccessoryEventListener { public Switch(Orientation orientation, Direction direction, Point center) { this(orientation, direction, center.x, center.y); } public Switch(Orientation orientation, Direction direction, int x, int y) { this(orientation, direction, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); } public Switch(Orientation orientation, Direction direction, int x, int y, int width, int height) { this(TileType.SWITCH, orientation, direction, x, y, width, height); } protected Switch(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { super(tileType, orientation, direction, x, y, width, height); setModel(new DefaultTileModel(orientation)); } public Switch(TileBean tileBean) { this(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); } protected Switch(TileBean tileBean, int width, int height) { super(tileBean, width, height); setModel(new DefaultTileModel(tileBean.getOrientation())); } @Override public Map getNeighborPoints() { Map neighbors = new HashMap<>(); Orientation orientation = this.getOrientation(); Direction direction = this.getDirection(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); if (Direction.LEFT == direction) { neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); } else { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); } } case WEST -> { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); if (Direction.LEFT == direction) { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); } else { neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); } } case NORTH -> { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); if (Direction.LEFT == direction) { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); } else { neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); } } default -> { //EAST neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); if (Direction.LEFT == direction) { neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); } else { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); } } } return neighbors; } @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); Orientation orientation = this.getOrientation(); Direction direction = this.getDirection(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); } else { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); } } case WEST -> { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); } else { edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); } } case NORTH -> { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); } else { edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); } } default -> { //EAST edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); } else { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); } } } return edgeConnections; } protected void renderStraight(Graphics2D g2, Color color) { int xx, yy, w, h; xx = 0; yy = 170; w = RENDER_WIDTH; h = 60; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } protected void renderDiagonal(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{400, 400, 170, 230}; yPoints = new int[]{170, 230, 0, 0}; } else { xPoints = new int[]{400, 400, 170, 230}; yPoints = new int[]{230, 170, 400, 400}; } g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillPolygon(xPoints, yPoints, xPoints.length); } protected void renderRouteStraight(Graphics2D g2, Color color) { int xx, yy, w, h; xx = 0; yy = 190; w = RENDER_WIDTH; h = 20; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } protected void renderRouteDiagonal(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{400, 400, 190, 210}; yPoints = new int[]{190, 210, 0, 0}; } else { xPoints = new int[]{400, 400, 190, 210}; yPoints = new int[]{210, 190, 400, 400}; } g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillPolygon(xPoints, yPoints, xPoints.length); } @Override public void renderTile(Graphics2D g2) { if (accessoryValue == null) { this.accessoryValue = AccessoryValue.OFF; } switch (accessoryValue) { case RED -> { renderStraight(g2, trackColor); renderDiagonal(g2, Color.red); } case GREEN -> { renderDiagonal(g2, trackColor); renderStraight(g2, Color.green); } default -> { renderStraight(g2, trackColor); renderDiagonal(g2, trackColor); } } } @Override public void renderTileRoute(Graphics2D g2) { if (routeValue == null) { routeValue = AccessoryValue.OFF; } switch (routeValue) { case RED -> { renderRouteDiagonal(g2, trackRouteColor); } case GREEN -> { renderRouteStraight(g2, trackRouteColor); } default -> { } } } @Override public void onAccessoryChange(AccessoryEvent event) { if (getAccessoryBean() != null && event.isEventFor(accessoryBean)) { setAccessoryValue(event.getAccessoryBean().getAccessoryValue()); } } @Override public boolean isJunction() { return true; } @Override public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { if (from != null && to != null && this.getDirection() != null) { switch (this.getDirection()) { case LEFT -> { if (this.isHorizontal()) { if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if (((from == Orientation.EAST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.EAST)) && Orientation.EAST == this.getOrientation()) { return AccessoryValue.RED; } else if (((from == Orientation.WEST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.WEST)) && Orientation.WEST == this.getOrientation()) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } else { //Vertical if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if (((from == Orientation.SOUTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.SOUTH)) && Orientation.SOUTH == this.getOrientation()) { return AccessoryValue.RED; } else if (((from == Orientation.NORTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.NORTH)) && Orientation.NORTH == this.getOrientation()) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } } case RIGHT -> { if (this.isHorizontal()) { if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if (((from == Orientation.EAST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.EAST)) && Orientation.EAST == this.getOrientation()) { return AccessoryValue.RED; } else if (((from == Orientation.WEST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.WEST)) && Orientation.WEST == this.getOrientation()) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } else { //Vertical if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if (((from == Orientation.EAST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.EAST)) && Orientation.SOUTH == this.getOrientation()) { return AccessoryValue.RED; } else if (((from == Orientation.WEST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.WEST)) && Orientation.NORTH == this.getOrientation()) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } } default -> { return AccessoryValue.OFF; } } } else { return AccessoryValue.OFF; } } // @Override // protected void paintComponent(Graphics g) { // long started = System.currentTimeMillis(); // super.paintComponent(g); // // setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); // // Graphics2D g2 = (Graphics2D) g.create(); // drawTile(g2); // g2.dispose(); // // g.drawImage(this.tileImage, 0, 0, null); // // long now = System.currentTimeMillis(); // Logger.trace(this.id + " Duration: " + (now - started) + " ms."); // } } \ No newline at end of file diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java index f22ea4f7..48c1598a 100755 --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -1,1133 +1 @@ -/* - * Copyright 2024 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout.tiles; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.geom.AffineTransform; -import java.awt.geom.Ellipse2D; -import java.awt.image.AffineTransformOp; -import java.awt.image.BufferedImage; -import java.beans.PropertyChangeListener; -import java.io.Serializable; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import javax.swing.JComponent; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import jcs.entities.AccessoryBean; -import jcs.entities.AccessoryBean.AccessoryValue; -import jcs.entities.AccessoryBean.SignalType; -import jcs.entities.BlockBean; -import jcs.entities.BlockBean.BlockState; -import jcs.entities.LocomotiveBean; -import jcs.entities.SensorBean; -import jcs.entities.TileBean; -import jcs.entities.TileBean.Direction; -import jcs.entities.TileBean.Orientation; -import jcs.entities.TileBean.TileType; -import jcs.ui.layout.LayoutUtil; -import static jcs.ui.layout.tiles.Block.BLOCK_HEIGHT; -import static jcs.ui.layout.tiles.Block.BLOCK_WIDTH; -import org.imgscalr.Scalr; -import org.imgscalr.Scalr.Method; -import org.imgscalr.Scalr.Mode; -import org.tinylog.Logger; - -/** - * Basic graphic element to display a track, turnout, etc on the screen.
- * By default the drawing of a Tile is Horizontal from L to R or West to East.
- * The default orientation is East. - * - *

- * The default size of a Tile is 40 tileX 40 pixels.
- * The center point of a Tile is stored and always snapped to the nearest grid point.
- * The basic grid is 20x 20 pixels.
- * - *

- * A Tile can be rotated (always clockwise).
- * Rotation will change the orientation from East -> South -> West -> North -> East.
- * - *

- * A Tile is rendered to a Buffered Image to speed up the display - */ -public abstract class Tile extends JComponent { //implements TileEventListener { //, ItemSelectable { - - public static final int GRID = 20; - public static final int DEFAULT_WIDTH = GRID * 2; - public static final int DEFAULT_HEIGHT = GRID * 2; - - static final int RENDER_GRID = GRID * 10; - static final int RENDER_WIDTH = RENDER_GRID * 2; - static final int RENDER_HEIGHT = RENDER_GRID * 2; - - public static final Color DEFAULT_BACKGROUND_COLOR = Color.white; - public static final Color DEFAULT_TRACK_COLOR = Color.lightGray; - public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.blue; - public static final Color DEFAULT_SELECTED_COLOR = Color.orange; - public static final Color DEFAULT_WARN_COLOR = Color.red; - - public static final String MODEL_CHANGED_PROPERTY = "model"; - public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled"; - - /** - * The data model that determines the button's state. - */ - protected TileModel model = null; - - protected String id; - protected Integer tileX; - protected Integer tileY; - - protected int renderWidth; - protected int renderHeight; - - //protected Orientation tileOrientation; - protected Direction tileDirection; - - protected TileType tileType; - protected String accessoryId; - protected String sensorId; - - protected AccessoryValue accessoryValue; - protected AccessoryValue routeValue; - - protected SignalType signalType; - protected AccessoryBean.SignalValue signalValue; - - protected TileBean tileBean; - protected AccessoryBean accessoryBean; - protected SensorBean sensorBean; - protected BlockBean blockBean; - - protected List neighbours; - - protected int offsetX = 0; - protected int offsetY = 0; - - protected int renderOffsetX = 0; - protected int renderOffsetY = 0; - - //protected Color selectedColor; - protected Color trackColor; - protected Color trackRouteColor; - protected Orientation incomingSide; - - protected Color backgroundColor; - protected boolean drawName = true; - - protected BufferedImage tileImage; - - protected PropertyChangeListener propertyChangeListener; - - protected ChangeListener changeListener = null; - protected ActionListener actionListener = null; - - protected transient ChangeEvent changeEvent; - - private Handler handler; - - protected Tile(TileType tileType, Orientation orientation, Point center, int width, int height) { - this(tileType, orientation, Direction.CENTER, center.x, center.y, width, height); - } - - protected Tile(TileType tileType, Orientation orientation, int x, int y, int width, int height) { - this(tileType, orientation, Direction.CENTER, x, y, width, height); - } - - protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { - this(tileType, orientation, direction, x, y, width, height, null, null); - } - - protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height, Color backgroundColor, Color selectedColor) { - this.tileType = tileType; - //this.tileOrientation = orientation; - //model.setTileOrienation(orientation); - this.tileDirection = direction; - this.tileX = x; - this.tileY = y; - - setLayout(null); - Dimension d = new Dimension(width, height); - setSize(d); - setPreferredSize(d); - - this.renderWidth = RENDER_WIDTH; - this.renderHeight = RENDER_HEIGHT; - - this.trackColor = DEFAULT_TRACK_COLOR; - this.backgroundColor = backgroundColor; - //this.selectedColor = selectedColor; - - if (this.backgroundColor == null) { - this.backgroundColor = DEFAULT_BACKGROUND_COLOR; - } -// if (this.selectedColor == null) { -// this.selectedColor = DEFAULT_SELECTED_COLOR; -// } - } - - protected Tile(TileBean tileBean) { - this(tileBean, tileWidth(tileBean.getOrientation(), tileBean.getTileType()), tileHeight(tileBean.getOrientation(), tileBean.getTileType())); - } - - protected Tile(TileBean tileBean, int width, int height) { - this.tileBean = tileBean; - //Quick properties - this.id = tileBean.getId(); - this.tileType = tileBean.getTileType(); - //this.tileOrientation = tileBean.getOrientation(); - //this.model.setTileOrienation(tileBean.getOrientation()); - this.tileDirection = tileBean.getDirection(); - this.tileX = tileBean.getX(); - this.tileY = tileBean.getY(); - - this.accessoryId = tileBean.getAccessoryId(); - this.accessoryBean = tileBean.getAccessoryBean(); - this.signalType = tileBean.getSignalType(); - - this.sensorId = tileBean.getSensorId(); - this.sensorBean = tileBean.getSensorBean(); - this.blockBean = tileBean.getBlockBean(); - - setLayout(null); - Dimension d = new Dimension(width, height); - setSize(d); - setPreferredSize(d); - - this.trackColor = DEFAULT_TRACK_COLOR; - this.backgroundColor = DEFAULT_BACKGROUND_COLOR; -// this.selectedColor = DEFAULT_SELECTED_COLOR; - this.renderWidth = RENDER_WIDTH; - this.renderHeight = RENDER_HEIGHT; - } - - protected static int tileWidth(Orientation orientation, TileType tileType) { - if (Orientation.EAST == orientation || Orientation.WEST == orientation) { - if (null == tileType) { - return DEFAULT_WIDTH; - } else { - return switch (tileType) { - case BLOCK -> - BLOCK_WIDTH; - case CROSS -> - DEFAULT_WIDTH * 2; - default -> - DEFAULT_WIDTH; - }; - } - } else { - return DEFAULT_WIDTH; - } - } - - protected static int tileHeight(Orientation orientation, TileType tileType) { - if (Orientation.EAST == orientation || Orientation.WEST == orientation) { - return DEFAULT_HEIGHT; - } else { - if (null == tileType) { - return DEFAULT_HEIGHT; - } else { - return switch (tileType) { - case BLOCK -> - BLOCK_HEIGHT; - case CROSS -> - DEFAULT_HEIGHT * 2; - default -> - DEFAULT_HEIGHT; - }; - } - } - } - - protected void populateModel() { - if (this.blockBean != null) { - this.model.setBlockState(this.blockBean.getBlockState()); - this.model.setLocomotive(this.blockBean.getLocomotive()); - this.model.setArrivalSuffix(this.blockBean.getArrivalSuffix()); - this.model.setLogicalDirection(LocomotiveBean.Direction.get(this.blockBean.getLogicalDirection())); - } - } - - public TileBean getTileBean() { - if (tileBean == null) { - tileBean = new TileBean(); - tileBean.setId(this.id); - tileBean.setX(this.tileX); - tileBean.setY(this.tileY); - tileBean.setTileType(this.tileType); - //tileBean.setTileOrientation(this.tileOrientation.getOrientation()); - tileBean.setTileOrientation(this.model.getTileOrienation().getOrientation()); - - tileBean.setTileDirection(this.tileDirection.getDirection()); - tileBean.setSignalType(this.signalType); - tileBean.setAccessoryId(this.accessoryId); - tileBean.setSensorId(this.sensorId); - tileBean.setAccessoryBean(this.accessoryBean); - tileBean.setSensorBean(this.sensorBean); - tileBean.setBlockBean(this.blockBean); - } - return tileBean; - } - - public boolean isSelected() { - return model.isSelected(); - } - - public void setSelected(boolean b) { - //boolean oldValue = isSelected(); - model.setSelected(b); - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public SignalType getSignalType() { - return signalType; - } - - public void setSignalType(SignalType signalType) { - this.signalType = signalType; - } - - public Integer getTileX() { - return tileX; - } - - public Integer getTileY() { - return tileY; - } - - public Point getCenter() { - return new Point(this.tileX, this.tileY); - } - - public void setCenter(Point center) { - tileX = center.x; - tileY = center.y; - if (tileBean != null) { - tileBean.setCenter(center); - } - Logger.trace(id + " Cp: " + xyToString()); - } - - public Orientation getOrientation() { - //return tileOrientation; - return model.getTileOrienation(); - } - - public void setOrientation(Orientation orientation) { - //this.tileOrientation = orientation; - model.setTileOrienation(orientation); - if (tileBean != null) { - tileBean.setOrientation(orientation); - } - } - - public Direction getDirection() { - return tileDirection; - } - - public void setDirection(Direction direction) { - this.tileDirection = direction; - if (tileBean != null) { - tileBean.setDirection(direction); - } - } - - public String getAccessoryId() { - return accessoryId; - } - - public void setAccessoryId(String accessoryId) { - this.accessoryId = accessoryId; - if (tileBean != null) { - tileBean.setAccessoryId(accessoryId); - } - } - - public String getSensorId() { - return sensorId; - } - - public void setSensorId(String sensorId) { - this.sensorId = sensorId; - } - - public boolean isActive() { - return model.isSensorActive(); - } - - public void setActive(boolean active) { - model.setSensorActive(active); - } - - public BlockState getBlockState() { - return model.getBlockState(); - } - - public void setBlockState(BlockState blockState) { - if (blockBean != null) { - blockBean.setBlockState(blockState); - LocomotiveBean locomotive = model.getLocomotive(); - model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (blockState == BlockState.OCCUPIED || blockState == BlockState.INBOUND || blockState == BlockState.OUTBOUND)); - } - model.setBlockState(blockState); - } - - public String getDepartureSuffix() { - return model.getDepartureSuffix(); - } - - public void setDepartureSuffix(String suffix) { - if (blockBean != null) { - blockBean.setDepartureSuffix(suffix); - } - model.setDepartureSuffix(suffix); - } - - public boolean isReverseArrival() { - return model.isReverseArrival(); - } - - public void setReverseArrival(boolean reverseArrival) { - if (blockBean != null) { - blockBean.setReverseArrival(reverseArrival); - } - model.setReverseArrival(reverseArrival); - } - - public LocomotiveBean.Direction getLogicalDirection() { - return model.getLogicalDirection(); - } - - public void setLogicalDirection(LocomotiveBean.Direction logicalDirection) { - if (blockBean != null) { - blockBean.setLogicalDirection(logicalDirection.getDirection()); - } - model.setLogicalDirection(logicalDirection); - } - - public LocomotiveBean getLocomotive() { - return model.getLocomotive(); - } - - public void setLocomotive(LocomotiveBean locomotive) { - if (blockBean != null) { - blockBean.setLocomotive(locomotive); - model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (model.getBlockState() == BlockState.OCCUPIED || model.getBlockState() == BlockState.INBOUND || model.getBlockState() == BlockState.OUTBOUND)); - } - - model.setLocomotive(locomotive); - } - - public AccessoryBean getAccessoryBean() { - return accessoryBean; - } - - public void setAccessoryBean(AccessoryBean accessoryBean) { - this.accessoryBean = accessoryBean; - - if (accessoryBean != null) { - accessoryId = accessoryBean.getId(); - signalValue = accessoryBean.getSignalValue(); - signalType = SignalType.getSignalType(accessoryBean.getType()); - } else { - accessoryId = null; - signalType = SignalType.NONE; - signalValue = AccessoryBean.SignalValue.OFF; - } - } - - public AccessoryValue getAccessoryValue() { - if (this.accessoryValue == null) { - return AccessoryValue.OFF; - } else { - return accessoryValue; - } - } - - public void setAccessoryValue(AccessoryValue value) { - this.accessoryValue = value; - repaint(); - } - - public AccessoryValue getRouteValue() { - if (routeValue == null) { - return AccessoryValue.OFF; - } else { - return routeValue; - } - } - - public void setRouteValue(AccessoryValue value) { - this.routeValue = value; - repaint(); - } - - public AccessoryBean.SignalValue getSignalValue() { - return signalValue; - } - - public void setSignalValue(AccessoryBean.SignalValue signalValue) { - this.signalValue = signalValue; - repaint(); - } - - public SensorBean getSensorBean() { - return sensorBean; - } - - public void setSensorBean(SensorBean sensorBean) { - this.sensorBean = sensorBean; - } - - public BlockBean getBlockBean() { - return blockBean; - } - - public void setBlockBean(BlockBean blockBean) { - this.blockBean = blockBean; - } - - public void setRenderWidth(int renderWidth) { - this.renderWidth = renderWidth; - } - - public void setRenderHeight(int renderHeight) { - this.renderHeight = renderHeight; - } - - public int getRenderOffsetX() { - return renderOffsetX; - } - - public void setRenderOffsetX(int renderOffsetX) { - this.renderOffsetX = renderOffsetX; - } - - public int getRenderOffsetY() { - return renderOffsetY; - } - - public void setRenderOffsetY(int renderOffsetY) { - this.renderOffsetY = renderOffsetY; - } - - public TileBean.TileType getTileType() { - return this.tileType; - } - - public final void setTileType(TileType tileType) { - this.tileType = tileType; - } - - public Color getTrackColor() { - return trackColor; - } - - public final void setTrackColor(Color trackColor) { - this.trackColor = trackColor; - } - - public Color getTrackRouteColor() { - return trackRouteColor; - } - - public void setTrackRouteColor(Color trackRouteColor) { - this.trackRouteColor = trackRouteColor; - } - - public Color getSelectedColor() { - return model.getSelectedColor(); - } - - public void setSelectedColor(Color selectedColor) { - this.model.setSelectedColor(selectedColor); - } - - public Orientation getIncomingSide() { - return incomingSide; - } - - public void setIncomingSide(Orientation incomingSide) { - this.incomingSide = incomingSide; - } - - public Color getBackgroundColor() { - return backgroundColor; - } - - public void setBackgroundColor(Color backgroundColor) { - this.backgroundColor = backgroundColor; - } - - public boolean isDrawRoute() { - return model.isShowRoute(); - } - - public void setDrawRoute(boolean drawRoute) { - this.model.setShowRoute(drawRoute); - } - - public int getRenderWidth() { - return renderWidth; - } - - public int getRenderHeight() { - return renderHeight; - } - - abstract void renderTile(Graphics2D g2d); - - abstract void renderTileRoute(Graphics2D g2d); - - public abstract Map getNeighborPoints(); - - public abstract Map getEdgePoints(); - - public abstract Set getAllPoints(); - - /** - * Draw the Tile - * - * @param g2d The graphics handle - */ - public void drawTile(Graphics2D g2d) { - // by default and image is rendered in the EAST orientation - Orientation tileOrientation = model.getTileOrienation(); -// if (tileOrientation == null) { -// tileOrientation = Orientation.EAST; -// } - - BufferedImage bf = createImage(); - Graphics2D g2di = bf.createGraphics(); - - //Avoid errors - if (model.isShowRoute() && incomingSide == null) { - incomingSide = getOrientation(); - } - - if (model.isSelected()) { - g2di.setBackground(model.getSelectedColor()); - } else { - g2di.setBackground(backgroundColor); - } - - g2di.clearRect(0, 0, renderWidth, renderHeight); - int ox = 0, oy = 0; - - AffineTransform trans = new AffineTransform(); - switch (tileOrientation) { - case SOUTH -> { - trans.rotate(Math.PI / 2, renderWidth / 2, renderHeight / 2); - ox = (renderHeight - renderWidth) / 2; - oy = (renderWidth - renderHeight) / 2; - trans.translate(-ox, -oy); - } - case WEST -> { - trans.rotate(Math.PI, renderWidth / 2, renderHeight / 2); - trans.translate(ox, oy); - } - case NORTH -> { - trans.rotate(-Math.PI / 2, renderWidth / 2, renderHeight / 2); - ox = (renderHeight - renderWidth) / 2; - oy = (renderWidth - renderHeight) / 2; - trans.translate(-ox, -oy); - } - default -> { - trans.rotate(0.0, this.renderWidth / 2, this.renderHeight / 2); - trans.translate(ox, oy); - } - } - - //Logger.trace(tileOrientation.getOrientation() + " renderWidth: " + renderWidth + " renderHeight: " + renderHeight + " CP: (" + renderWidth / 2 + "," + renderHeight / 2 + ")"); - //Logger.trace(tileOrientation.getOrientation() + " ox: " + ox + " oy: " + oy); - g2di.setTransform(trans); - - renderTile(g2di); - - if (model.isShowRoute()) { - renderTileRoute(g2di); - } - - if (model.isShowCenter()) { - drawCenterPoint(g2di); - } - - // Scale the image back... - if (model.isScaleImage()) { - tileImage = Scalr.resize(bf, Method.AUTOMATIC, Mode.FIT_EXACT, getWidth(), getHeight(), Scalr.OP_ANTIALIAS); - } else { - tileImage = bf; - } - - g2di.dispose(); - - Logger.trace(id + " Cp: " + xyToString()); - - } - - public BufferedImage getTileImage() { - return tileImage; - } - - /** - * Render a tile image Always starts at (0,0) used the default width and height - * - * @param g2 the Graphic context - */ - public void drawName(Graphics2D g2) { - } - - protected void drawCenterPoint(Graphics2D g2d) { - drawCenterPoint(g2d, Color.magenta); - } - - protected void drawCenterPoint(Graphics2D g2, Color color) { - drawCenterPoint(g2, color, 60); - } - - protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { - double dX = (renderWidth / 2 - size / 2); - double dY = (renderHeight / 2 - size / 2); - - g2d.setColor(color); - g2d.fill(new Ellipse2D.Double(dX, dY, size, size)); - } - - /** - * Rotate the tile clockwise 90 deg - * - * @return the new Orientation - */ - public Orientation rotate() { - Orientation tileOrientation = model.getTileOrienation(); - switch (tileOrientation) { - case EAST -> - setOrientation(Orientation.SOUTH); - case SOUTH -> - setOrientation(Orientation.WEST); - case WEST -> - setOrientation(Orientation.NORTH); - default -> - setOrientation(Orientation.EAST); - } - return model.getTileOrienation(); - } - - public void flipHorizontal() { - Orientation tileOrientation = model.getTileOrienation(); - if (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) { - rotate(); - rotate(); - } - } - - public void flipVertical() { - Orientation tileOrientation = model.getTileOrienation(); - if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { - rotate(); - rotate(); - } - } - - @Override - public void move(int newX, int newY) { - Point cs = LayoutUtil.snapToGrid(newX, newY); - setCenter(cs); - } - - protected static void drawRotate(Graphics2D g2d, double x, double y, int angle, String text) { - g2d.translate((float) x, (float) y); - g2d.rotate(Math.toRadians(angle)); - g2d.drawString(text, 0, 0); - g2d.rotate(-Math.toRadians(angle)); - g2d.translate(-x, -y); - } - - public static BufferedImage flipHorizontally(BufferedImage source) { - BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); - - AffineTransform flip = AffineTransform.getScaleInstance(1, -1); - flip.translate(0, -source.getHeight()); - AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); - - op.filter(source, output); - - return output; - } - - public static BufferedImage flipVertically(BufferedImage source) { - BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); - - AffineTransform flip = AffineTransform.getScaleInstance(-1, 1); - flip.translate(-source.getWidth(), 0); - AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); - - op.filter(source, output); - - return output; - } - - public Set getAltPoints() { - return Collections.EMPTY_SET; - } - - public final int getOffsetX() { - return offsetX; - } - - public void setOffsetX(int offsetX) { - this.offsetX = offsetX; - } - - public final int getOffsetY() { - return offsetY; - } - - public void setOffsetY(int offsetY) { - this.offsetY = offsetY; - } - - protected BufferedImage createImage() { - return new BufferedImage(renderWidth, renderHeight, BufferedImage.TYPE_INT_RGB); - } - - public int getCenterX() { - if (tileX > 0) { - return this.tileX; - } else { - return GRID; - } - } - - public int getCenterY() { - if (tileY > 0) { - return this.tileY; - } else { - return GRID; - } - } - - public boolean isDrawName() { - return drawName; - } - - public void setDrawName(boolean drawName) { - this.drawName = drawName; - } - - public boolean isScaleImage() { - return model.isScaleImage(); - } - - public void setScaleImage(boolean scaleImage) { - Dimension d; - if (scaleImage) { - d = new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); - } else { - d = new Dimension(renderWidth, renderHeight); - } - - setSize(d); - setPreferredSize(d); - - model.setScaleImage(scaleImage); - } - - public boolean isDrawCenterPoint() { - return model.isShowCenter(); - } - - public void setDrawCenterPoint(boolean drawCenterPoint) { - model.setShowCenter(drawCenterPoint); - } - - @Override - public String toString() { - return this.getClass().getSimpleName() - + " {id: " - + this.id - + ", orientation: " - + getOrientation() - + ", direction: " - + getDirection() - + ", center: " - + xyToString() - + "}"; - } - - public String xyToString() { - return "(" + this.tileX + "," + this.tileY + ")"; - } - - /** - * The main route of the tile is horizontal - * - * @return true when main route goes from East to West or vv - */ - public boolean isHorizontal() { - Orientation tileOrientation = model.getTileOrienation(); - return (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) && TileType.CURVED != tileType; - } - - /** - * The main route of the tile is vertical - * - * @return true when main route goes from North to South or vv - */ - public boolean isVertical() { - Orientation tileOrientation = model.getTileOrienation(); - return (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) && TileType.CURVED != tileType; - } - - public boolean isJunction() { - return TileType.SWITCH == tileType || TileType.CROSS == tileType; - } - - public boolean isBlock() { - return TileType.BLOCK == tileType; - } - - public boolean isDirectional() { - return TileType.STRAIGHT_DIR == tileType; - } - - /** - * The main route of the tile is diagonal - * - * @return true when main route goes from North to East or West to South and vv - */ - public boolean isDiagonal() { - return TileType.CURVED == tileType; - } - - public boolean isCrossing() { - return TileType.CROSSING == tileType; - } - - public List getNeighbours() { - return neighbours; - } - - public void setNeighbours(List neighbours) { - this.neighbours = neighbours; - } - - public String getIdSuffix(Tile other) { - return ""; - } - - public Map getNeighborOrientations() { - Map edgeOrientations = new HashMap<>(); - - Map neighborPoints = getNeighborPoints(); - - for (Orientation o : Orientation.values()) { - edgeOrientations.put(neighborPoints.get(o), o); - } - return edgeOrientations; - } - - public Map getEdgeOrientations() { - Map edgeOrientations = new HashMap<>(); - - Map edgeConnections = getEdgePoints(); - - for (Orientation o : Orientation.values()) { - edgeOrientations.put(edgeConnections.get(o), o); - } - return edgeOrientations; - } - - public boolean isAdjacent(Tile other) { - boolean adjacent = false; - - if (other != null) { - Collection thisEdgePoints = getEdgePoints().values(); - Collection otherEdgePoints = other.getEdgePoints().values(); - - for (Point p : thisEdgePoints) { - adjacent = otherEdgePoints.contains(p); - if (adjacent) { - break; - } - } - } - - return adjacent; - } - - /** - * When the tile has a specific direction a train may travel,
- * then this method will indicate whether the other tile is in on the side where the arrow is pointing to. - * - * @param other A Tile - * @return true where other is on the side of this tile where the arrow points to - */ - public boolean isArrowDirection(Tile other) { - return true; - } - - public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { - return AccessoryValue.OFF; - } - - public TileModel getModel() { - return model; - } - - public void setModel(TileModel newModel) { - TileModel oldModel = getModel(); - - if (oldModel != null) { - oldModel.removeChangeListener(changeListener); - oldModel.removeActionListener(actionListener); - changeListener = null; - actionListener = null; - } - - model = newModel; - - if (newModel != null) { - changeListener = createChangeListener(); - actionListener = createActionListener(); - - newModel.addChangeListener(changeListener); - newModel.addActionListener(actionListener); - } - - firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel); - if (newModel != oldModel) { - revalidate(); - repaint(); - } - } - -// public TileUI getUI() { -// return (TileUI) ui; -// } -// public void setUI(TileUI ui) { -// super.setUI(ui); -// } - @Override - public void updateUI() { - } - - protected ChangeListener createChangeListener() { - return getHandler(); - } - - protected ActionListener createActionListener() { - return getHandler(); - } - - private Handler getHandler() { - if (handler == null) { - handler = new Handler(); - } - return handler; - } - - class Handler implements ActionListener, ChangeListener, Serializable { - - @Override - public void stateChanged(ChangeEvent e) { - //Object source = e.getSource(); - - fireStateChanged(); - repaint(); - } - - @Override - public void actionPerformed(ActionEvent event) { - fireActionPerformed(event); - } - } - - protected void fireStateChanged() { - Object[] listeners = listenerList.getListenerList(); - //reverse order - for (int i = listeners.length - 2; i >= 0; i -= 2) { - if (listeners[i] == ChangeListener.class) { - // Lazily create the event: - if (changeEvent == null) { - changeEvent = new ChangeEvent(this); - } - ((ChangeListener) listeners[i + 1]).stateChanged(changeEvent); - } - } - } - - protected void fireActionPerformed(ActionEvent event) { - Object[] listeners = listenerList.getListenerList(); - ActionEvent e = null; - // reverse - for (int i = listeners.length - 2; i >= 0; i -= 2) { - if (listeners[i] == ActionListener.class) { - // Lazily create the event: - if (e == null) { - String actionCommand = event.getActionCommand(); - //if(actionCommand == null) { - // actionCommand = getActionCommand(); - //} - e = new ActionEvent(Tile.this, ActionEvent.ACTION_PERFORMED, actionCommand, event.getWhen(), event.getModifiers()); - } - ((ActionListener) listeners[i + 1]).actionPerformed(e); - } - } - } - - public Rectangle getTileBounds() { - if (model.isScaleImage()) { - return new Rectangle(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); - } else { - return new Rectangle(tileX - renderWidth / 2, tileY - renderHeight / 2, renderWidth, renderHeight); - } - } - - @Override - protected void paintComponent(Graphics g) { - long started = System.currentTimeMillis(); - - Graphics2D g2 = (Graphics2D) g.create(); - //Graphics2D g2 = (Graphics2D) g.create(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); - drawTile(g2); - g2.dispose(); - - g.drawImage(tileImage, 0, 0, null); - - long now = System.currentTimeMillis(); - Logger.trace(id + " Duration: " + (now - started) + " ms. Cp: " + xyToString() + " O: " + model.getTileOrienation()); - } - -} +/* * Copyright 2024 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.AffineTransform; import java.awt.geom.Ellipse2D; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; import java.beans.PropertyChangeListener; import java.io.Serializable; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.swing.JComponent; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.AccessoryValue; import jcs.entities.AccessoryBean.SignalType; import jcs.entities.BlockBean; import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; import jcs.entities.SensorBean; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import jcs.entities.TileBean.TileType; import jcs.ui.layout.LayoutUtil; import static jcs.ui.layout.tiles.Block.BLOCK_HEIGHT; import static jcs.ui.layout.tiles.Block.BLOCK_WIDTH; import org.imgscalr.Scalr; import org.imgscalr.Scalr.Method; import org.imgscalr.Scalr.Mode; import org.tinylog.Logger; /** * Basic graphic element to display a track, turnout, etc on the screen.
* By default the drawing of a Tile is Horizontal from L to R or West to East.
* The default orientation is East. * *

* The default size of a Tile is 40 tileX 40 pixels.
* The center point of a Tile is stored and always snapped to the nearest grid point.
* The basic grid is 20x 20 pixels.
* *

* A Tile can be rotated (always clockwise).
* Rotation will change the orientation from East -> South -> West -> North -> East.
* *

* A Tile is rendered to a Buffered Image to speed up the display */ public abstract class Tile extends JComponent { //implements TileEventListener { //, ItemSelectable { public static final int GRID = 20; public static final int DEFAULT_WIDTH = GRID * 2; public static final int DEFAULT_HEIGHT = GRID * 2; static final int RENDER_GRID = GRID * 10; static final int RENDER_WIDTH = RENDER_GRID * 2; static final int RENDER_HEIGHT = RENDER_GRID * 2; public static final Color DEFAULT_BACKGROUND_COLOR = Color.white; public static final Color DEFAULT_TRACK_COLOR = Color.lightGray; public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.blue; public static final Color DEFAULT_SELECTED_COLOR = Color.orange; public static final Color DEFAULT_WARN_COLOR = Color.red; public static final String MODEL_CHANGED_PROPERTY = "model"; public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled"; /** * The data model that determines the button's state. */ protected TileModel model = null; protected String id; protected Integer tileX; protected Integer tileY; protected int renderWidth; protected int renderHeight; //protected Orientation tileOrientation; protected Direction tileDirection; protected TileType tileType; protected String accessoryId; protected String sensorId; protected AccessoryValue accessoryValue; protected AccessoryValue routeValue; protected SignalType signalType; protected AccessoryBean.SignalValue signalValue; protected TileBean tileBean; protected AccessoryBean accessoryBean; protected SensorBean sensorBean; protected BlockBean blockBean; protected List neighbours; protected int offsetX = 0; protected int offsetY = 0; protected int renderOffsetX = 0; protected int renderOffsetY = 0; //protected Color selectedColor; protected Color trackColor; protected Color trackRouteColor; protected Orientation incomingSide; protected Color backgroundColor; protected boolean drawName = true; protected BufferedImage tileImage; protected PropertyChangeListener propertyChangeListener; protected ChangeListener changeListener = null; protected ActionListener actionListener = null; protected transient ChangeEvent changeEvent; private Handler handler; protected Tile(TileType tileType, Orientation orientation, Point center, int width, int height) { this(tileType, orientation, Direction.CENTER, center.x, center.y, width, height); } protected Tile(TileType tileType, Orientation orientation, int x, int y, int width, int height) { this(tileType, orientation, Direction.CENTER, x, y, width, height); } protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { this(tileType, orientation, direction, x, y, width, height, null, null); } protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height, Color backgroundColor, Color selectedColor) { this.tileType = tileType; //this.tileOrientation = orientation; //model.setTileOrienation(orientation); this.tileDirection = direction; this.tileX = x; this.tileY = y; setLayout(null); Dimension d = new Dimension(width, height); setSize(d); setPreferredSize(d); this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT; this.trackColor = DEFAULT_TRACK_COLOR; this.backgroundColor = backgroundColor; //this.selectedColor = selectedColor; if (this.backgroundColor == null) { this.backgroundColor = DEFAULT_BACKGROUND_COLOR; } // if (this.selectedColor == null) { // this.selectedColor = DEFAULT_SELECTED_COLOR; // } } protected Tile(TileBean tileBean) { this(tileBean, tileWidth(tileBean.getOrientation(), tileBean.getTileType()), tileHeight(tileBean.getOrientation(), tileBean.getTileType())); } protected Tile(TileBean tileBean, int width, int height) { this.tileBean = tileBean; //Quick properties this.id = tileBean.getId(); this.tileType = tileBean.getTileType(); //this.tileOrientation = tileBean.getOrientation(); //this.model.setTileOrienation(tileBean.getOrientation()); this.tileDirection = tileBean.getDirection(); this.tileX = tileBean.getX(); this.tileY = tileBean.getY(); this.accessoryId = tileBean.getAccessoryId(); this.accessoryBean = tileBean.getAccessoryBean(); this.signalType = tileBean.getSignalType(); this.sensorId = tileBean.getSensorId(); this.sensorBean = tileBean.getSensorBean(); this.blockBean = tileBean.getBlockBean(); setLayout(null); Dimension d = new Dimension(width, height); setSize(d); setPreferredSize(d); this.trackColor = DEFAULT_TRACK_COLOR; this.backgroundColor = DEFAULT_BACKGROUND_COLOR; // this.selectedColor = DEFAULT_SELECTED_COLOR; this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT; } protected static int tileWidth(Orientation orientation, TileType tileType) { if (Orientation.EAST == orientation || Orientation.WEST == orientation) { if (null == tileType) { return DEFAULT_WIDTH; } else { return switch (tileType) { case BLOCK -> BLOCK_WIDTH; case CROSS -> DEFAULT_WIDTH * 2; default -> DEFAULT_WIDTH; }; } } else { return DEFAULT_WIDTH; } } protected static int tileHeight(Orientation orientation, TileType tileType) { if (Orientation.EAST == orientation || Orientation.WEST == orientation) { return DEFAULT_HEIGHT; } else { if (null == tileType) { return DEFAULT_HEIGHT; } else { return switch (tileType) { case BLOCK -> BLOCK_HEIGHT; case CROSS -> DEFAULT_HEIGHT * 2; default -> DEFAULT_HEIGHT; }; } } } protected void populateModel() { if (this.blockBean != null) { this.model.setBlockState(this.blockBean.getBlockState()); this.model.setLocomotive(this.blockBean.getLocomotive()); this.model.setArrivalSuffix(this.blockBean.getArrivalSuffix()); this.model.setLogicalDirection(LocomotiveBean.Direction.get(this.blockBean.getLogicalDirection())); } } public TileBean getTileBean() { if (tileBean == null) { tileBean = new TileBean(); tileBean.setId(this.id); tileBean.setX(this.tileX); tileBean.setY(this.tileY); tileBean.setTileType(this.tileType); //tileBean.setTileOrientation(this.tileOrientation.getOrientation()); tileBean.setTileOrientation(this.model.getTileOrienation().getOrientation()); tileBean.setTileDirection(this.tileDirection.getDirection()); tileBean.setSignalType(this.signalType); tileBean.setAccessoryId(this.accessoryId); tileBean.setSensorId(this.sensorId); tileBean.setAccessoryBean(this.accessoryBean); tileBean.setSensorBean(this.sensorBean); tileBean.setBlockBean(this.blockBean); } return tileBean; } public boolean isSelected() { return model.isSelected(); } public void setSelected(boolean b) { //boolean oldValue = isSelected(); model.setSelected(b); } public String getId() { return id; } public void setId(String id) { this.id = id; } public SignalType getSignalType() { return signalType; } public void setSignalType(SignalType signalType) { this.signalType = signalType; } public Integer getTileX() { return tileX; } public Integer getTileY() { return tileY; } public Point getCenter() { return new Point(this.tileX, this.tileY); } public void setCenter(Point center) { tileX = center.x; tileY = center.y; if (tileBean != null) { tileBean.setCenter(center); } Logger.trace(id + " Cp: " + xyToString()); } public Orientation getOrientation() { //return tileOrientation; return model.getTileOrienation(); } public void setOrientation(Orientation orientation) { //this.tileOrientation = orientation; model.setTileOrienation(orientation); if (tileBean != null) { tileBean.setOrientation(orientation); } } public Direction getDirection() { return tileDirection; } public void setDirection(Direction direction) { this.tileDirection = direction; if (tileBean != null) { tileBean.setDirection(direction); } } public String getAccessoryId() { return accessoryId; } public void setAccessoryId(String accessoryId) { this.accessoryId = accessoryId; if (tileBean != null) { tileBean.setAccessoryId(accessoryId); } } public String getSensorId() { return sensorId; } public void setSensorId(String sensorId) { this.sensorId = sensorId; } public boolean isActive() { return model.isSensorActive(); } public void setActive(boolean active) { model.setSensorActive(active); } public BlockState getBlockState() { return model.getBlockState(); } public void setBlockState(BlockState blockState) { if (blockBean != null) { blockBean.setBlockState(blockState); LocomotiveBean locomotive = model.getLocomotive(); model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (blockState == BlockState.OCCUPIED || blockState == BlockState.INBOUND || blockState == BlockState.OUTBOUND)); } model.setBlockState(blockState); } public String getDepartureSuffix() { return model.getDepartureSuffix(); } public void setDepartureSuffix(String suffix) { if (blockBean != null) { blockBean.setDepartureSuffix(suffix); } model.setDepartureSuffix(suffix); } public boolean isReverseArrival() { return model.isReverseArrival(); } public void setReverseArrival(boolean reverseArrival) { if (blockBean != null) { blockBean.setReverseArrival(reverseArrival); } model.setReverseArrival(reverseArrival); } public LocomotiveBean.Direction getLogicalDirection() { return model.getLogicalDirection(); } public void setLogicalDirection(LocomotiveBean.Direction logicalDirection) { if (blockBean != null) { blockBean.setLogicalDirection(logicalDirection.getDirection()); } model.setLogicalDirection(logicalDirection); } public LocomotiveBean getLocomotive() { return model.getLocomotive(); } public void setLocomotive(LocomotiveBean locomotive) { if (blockBean != null) { blockBean.setLocomotive(locomotive); model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (model.getBlockState() == BlockState.OCCUPIED || model.getBlockState() == BlockState.INBOUND || model.getBlockState() == BlockState.OUTBOUND)); } model.setLocomotive(locomotive); } public AccessoryBean getAccessoryBean() { return accessoryBean; } public void setAccessoryBean(AccessoryBean accessoryBean) { this.accessoryBean = accessoryBean; if (accessoryBean != null) { accessoryId = accessoryBean.getId(); signalValue = accessoryBean.getSignalValue(); signalType = SignalType.getSignalType(accessoryBean.getType()); } else { accessoryId = null; signalType = SignalType.NONE; signalValue = AccessoryBean.SignalValue.OFF; } } public AccessoryValue getAccessoryValue() { if (this.accessoryValue == null) { return AccessoryValue.OFF; } else { return accessoryValue; } } public void setAccessoryValue(AccessoryValue value) { this.accessoryValue = value; repaint(); } public AccessoryValue getRouteValue() { if (routeValue == null) { return AccessoryValue.OFF; } else { return routeValue; } } public void setRouteValue(AccessoryValue value) { this.routeValue = value; repaint(); } public AccessoryBean.SignalValue getSignalValue() { return signalValue; } public void setSignalValue(AccessoryBean.SignalValue signalValue) { this.signalValue = signalValue; repaint(); } public SensorBean getSensorBean() { return sensorBean; } public void setSensorBean(SensorBean sensorBean) { this.sensorBean = sensorBean; } public BlockBean getBlockBean() { return blockBean; } public void setBlockBean(BlockBean blockBean) { this.blockBean = blockBean; } public void setRenderWidth(int renderWidth) { this.renderWidth = renderWidth; } public void setRenderHeight(int renderHeight) { this.renderHeight = renderHeight; } public int getRenderOffsetX() { return renderOffsetX; } public void setRenderOffsetX(int renderOffsetX) { this.renderOffsetX = renderOffsetX; } public int getRenderOffsetY() { return renderOffsetY; } public void setRenderOffsetY(int renderOffsetY) { this.renderOffsetY = renderOffsetY; } public TileBean.TileType getTileType() { return this.tileType; } public final void setTileType(TileType tileType) { this.tileType = tileType; } public Color getTrackColor() { return trackColor; } public final void setTrackColor(Color trackColor) { this.trackColor = trackColor; } public Color getTrackRouteColor() { return trackRouteColor; } public void setTrackRouteColor(Color trackRouteColor) { this.trackRouteColor = trackRouteColor; } public Color getSelectedColor() { return model.getSelectedColor(); } public void setSelectedColor(Color selectedColor) { this.model.setSelectedColor(selectedColor); } public Orientation getIncomingSide() { return incomingSide; } public void setIncomingSide(Orientation incomingSide) { this.incomingSide = incomingSide; } public Color getBackgroundColor() { return backgroundColor; } public void setBackgroundColor(Color backgroundColor) { this.backgroundColor = backgroundColor; } public boolean isDrawRoute() { return model.isShowRoute(); } public void setDrawRoute(boolean drawRoute) { this.model.setShowRoute(drawRoute); } public int getRenderWidth() { return renderWidth; } public int getRenderHeight() { return renderHeight; } abstract void renderTile(Graphics2D g2d); abstract void renderTileRoute(Graphics2D g2d); public abstract Map getNeighborPoints(); public abstract Map getEdgePoints(); //public abstract Set getAllPoints(); //public abstract Set getAllPoints(Point center); //public abstract Set getAltPoints(Point center); Set getAltPoints(Point center) { return Collections.EMPTY_SET; } public Set getAllPoints() { return getAllPoints(getCenter()); } Set getAllPoints(Point center) { Set aps = new HashSet<>(); aps.add(center); return aps; } /** * Draw the Tile * * @param g2d The graphics handle */ public void drawTile(Graphics2D g2d) { // by default and image is rendered in the EAST orientation Orientation tileOrientation = model.getTileOrienation(); // if (tileOrientation == null) { // tileOrientation = Orientation.EAST; // } BufferedImage bf = createImage(); Graphics2D g2di = bf.createGraphics(); //Avoid errors if (model.isShowRoute() && incomingSide == null) { incomingSide = getOrientation(); } if (model.isSelected()) { g2di.setBackground(model.getSelectedColor()); } else { g2di.setBackground(backgroundColor); } g2di.clearRect(0, 0, renderWidth, renderHeight); int ox = 0, oy = 0; AffineTransform trans = new AffineTransform(); switch (tileOrientation) { case SOUTH -> { trans.rotate(Math.PI / 2, renderWidth / 2, renderHeight / 2); ox = (renderHeight - renderWidth) / 2; oy = (renderWidth - renderHeight) / 2; trans.translate(-ox, -oy); } case WEST -> { trans.rotate(Math.PI, renderWidth / 2, renderHeight / 2); trans.translate(ox, oy); } case NORTH -> { trans.rotate(-Math.PI / 2, renderWidth / 2, renderHeight / 2); ox = (renderHeight - renderWidth) / 2; oy = (renderWidth - renderHeight) / 2; trans.translate(-ox, -oy); } default -> { trans.rotate(0.0, this.renderWidth / 2, this.renderHeight / 2); trans.translate(ox, oy); } } //Logger.trace(tileOrientation.getOrientation() + " renderWidth: " + renderWidth + " renderHeight: " + renderHeight + " CP: (" + renderWidth / 2 + "," + renderHeight / 2 + ")"); //Logger.trace(tileOrientation.getOrientation() + " ox: " + ox + " oy: " + oy); g2di.setTransform(trans); renderTile(g2di); if (model.isShowRoute()) { renderTileRoute(g2di); } if (model.isShowCenter()) { drawCenterPoint(g2di); } // Scale the image back... if (model.isScaleImage()) { tileImage = Scalr.resize(bf, Method.AUTOMATIC, Mode.FIT_EXACT, getWidth(), getHeight(), Scalr.OP_ANTIALIAS); } else { tileImage = bf; } g2di.dispose(); Logger.trace(id + " Cp: " + xyToString()); } public BufferedImage getTileImage() { return tileImage; } /** * Render a tile image Always starts at (0,0) used the default width and height * * @param g2 the Graphic context */ public void drawName(Graphics2D g2) { } protected void drawCenterPoint(Graphics2D g2d) { drawCenterPoint(g2d, Color.magenta); } protected void drawCenterPoint(Graphics2D g2, Color color) { drawCenterPoint(g2, color, 60); } protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { double dX = (renderWidth / 2 - size / 2); double dY = (renderHeight / 2 - size / 2); g2d.setColor(color); g2d.fill(new Ellipse2D.Double(dX, dY, size, size)); } /** * Rotate the tile clockwise 90 deg * * @return the new Orientation */ public Orientation rotate() { Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case EAST -> setOrientation(Orientation.SOUTH); case SOUTH -> setOrientation(Orientation.WEST); case WEST -> setOrientation(Orientation.NORTH); default -> setOrientation(Orientation.EAST); } return model.getTileOrienation(); } public void flipHorizontal() { Orientation tileOrientation = model.getTileOrienation(); if (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) { rotate(); rotate(); } } public void flipVertical() { Orientation tileOrientation = model.getTileOrienation(); if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { rotate(); rotate(); } } @Override public void move(int newX, int newY) { Point cs = LayoutUtil.snapToGrid(newX, newY); setCenter(cs); } protected static void drawRotate(Graphics2D g2d, double x, double y, int angle, String text) { g2d.translate((float) x, (float) y); g2d.rotate(Math.toRadians(angle)); g2d.drawString(text, 0, 0); g2d.rotate(-Math.toRadians(angle)); g2d.translate(-x, -y); } public static BufferedImage flipHorizontally(BufferedImage source) { BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); AffineTransform flip = AffineTransform.getScaleInstance(1, -1); flip.translate(0, -source.getHeight()); AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); op.filter(source, output); return output; } public static BufferedImage flipVertically(BufferedImage source) { BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); AffineTransform flip = AffineTransform.getScaleInstance(-1, 1); flip.translate(-source.getWidth(), 0); AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); op.filter(source, output); return output; } public Set getAltPoints() { return Collections.EMPTY_SET; } public final int getOffsetX() { return offsetX; } public void setOffsetX(int offsetX) { this.offsetX = offsetX; } public final int getOffsetY() { return offsetY; } public void setOffsetY(int offsetY) { this.offsetY = offsetY; } protected BufferedImage createImage() { return new BufferedImage(renderWidth, renderHeight, BufferedImage.TYPE_INT_RGB); } public int getCenterX() { if (tileX > 0) { return this.tileX; } else { return GRID; } } public int getCenterY() { if (tileY > 0) { return this.tileY; } else { return GRID; } } public boolean isDrawName() { return drawName; } public void setDrawName(boolean drawName) { this.drawName = drawName; } public boolean isScaleImage() { return model.isScaleImage(); } public void setScaleImage(boolean scaleImage) { Dimension d; if (scaleImage) { d = new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); } else { d = new Dimension(renderWidth, renderHeight); } setSize(d); setPreferredSize(d); model.setScaleImage(scaleImage); } public boolean isDrawCenterPoint() { return model.isShowCenter(); } public void setDrawCenterPoint(boolean drawCenterPoint) { model.setShowCenter(drawCenterPoint); } @Override public String toString() { return this.getClass().getSimpleName() + " {id: " + this.id + ", orientation: " + getOrientation() + ", direction: " + getDirection() + ", center: " + xyToString() + "}"; } public String xyToString() { return "(" + this.tileX + "," + this.tileY + ")"; } /** * The main route of the tile is horizontal * * @return true when main route goes from East to West or vv */ public boolean isHorizontal() { Orientation tileOrientation = model.getTileOrienation(); return (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) && TileType.CURVED != tileType; } /** * The main route of the tile is vertical * * @return true when main route goes from North to South or vv */ public boolean isVertical() { Orientation tileOrientation = model.getTileOrienation(); return (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) && TileType.CURVED != tileType; } public boolean isJunction() { return TileType.SWITCH == tileType || TileType.CROSS == tileType; } public boolean isBlock() { return TileType.BLOCK == tileType; } public boolean isDirectional() { return TileType.STRAIGHT_DIR == tileType; } /** * The main route of the tile is diagonal * * @return true when main route goes from North to East or West to South and vv */ public boolean isDiagonal() { return TileType.CURVED == tileType; } public boolean isCrossing() { return TileType.CROSSING == tileType; } public List getNeighbours() { return neighbours; } public void setNeighbours(List neighbours) { this.neighbours = neighbours; } public String getIdSuffix(Tile other) { return ""; } public Map getNeighborOrientations() { Map edgeOrientations = new HashMap<>(); Map neighborPoints = getNeighborPoints(); for (Orientation o : Orientation.values()) { edgeOrientations.put(neighborPoints.get(o), o); } return edgeOrientations; } public Map getEdgeOrientations() { Map edgeOrientations = new HashMap<>(); Map edgeConnections = getEdgePoints(); for (Orientation o : Orientation.values()) { edgeOrientations.put(edgeConnections.get(o), o); } return edgeOrientations; } public boolean isAdjacent(Tile other) { boolean adjacent = false; if (other != null) { Collection thisEdgePoints = getEdgePoints().values(); Collection otherEdgePoints = other.getEdgePoints().values(); for (Point p : thisEdgePoints) { adjacent = otherEdgePoints.contains(p); if (adjacent) { break; } } } return adjacent; } /** * When the tile has a specific direction a train may travel,
* then this method will indicate whether the other tile is in on the side where the arrow is pointing to. * * @param other A Tile * @return true where other is on the side of this tile where the arrow points to */ public boolean isArrowDirection(Tile other) { return true; } public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { return AccessoryValue.OFF; } public TileModel getModel() { return model; } public void setModel(TileModel newModel) { TileModel oldModel = getModel(); if (oldModel != null) { oldModel.removeChangeListener(changeListener); oldModel.removeActionListener(actionListener); changeListener = null; actionListener = null; } model = newModel; if (newModel != null) { changeListener = createChangeListener(); actionListener = createActionListener(); newModel.addChangeListener(changeListener); newModel.addActionListener(actionListener); } firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel); if (newModel != oldModel) { revalidate(); repaint(); } } // public TileUI getUI() { // return (TileUI) ui; // } // public void setUI(TileUI ui) { // super.setUI(ui); // } @Override public void updateUI() { } protected ChangeListener createChangeListener() { return getHandler(); } protected ActionListener createActionListener() { return getHandler(); } private Handler getHandler() { if (handler == null) { handler = new Handler(); } return handler; } class Handler implements ActionListener, ChangeListener, Serializable { @Override public void stateChanged(ChangeEvent e) { //Object source = e.getSource(); fireStateChanged(); repaint(); } @Override public void actionPerformed(ActionEvent event) { fireActionPerformed(event); } } protected void fireStateChanged() { Object[] listeners = listenerList.getListenerList(); //reverse order for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == ChangeListener.class) { // Lazily create the event: if (changeEvent == null) { changeEvent = new ChangeEvent(this); } ((ChangeListener) listeners[i + 1]).stateChanged(changeEvent); } } } protected void fireActionPerformed(ActionEvent event) { Object[] listeners = listenerList.getListenerList(); ActionEvent e = null; // reverse for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == ActionListener.class) { // Lazily create the event: if (e == null) { String actionCommand = event.getActionCommand(); //if(actionCommand == null) { // actionCommand = getActionCommand(); //} e = new ActionEvent(Tile.this, ActionEvent.ACTION_PERFORMED, actionCommand, event.getWhen(), event.getModifiers()); } ((ActionListener) listeners[i + 1]).actionPerformed(e); } } } public Rectangle getTileBounds() { if (model.isScaleImage()) { return new Rectangle(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); } else { return new Rectangle(tileX - renderWidth / 2, tileY - renderHeight / 2, renderWidth, renderHeight); } } @Override protected void paintComponent(Graphics g) { long started = System.currentTimeMillis(); Graphics2D g2 = (Graphics2D) g.create(); //Graphics2D g2 = (Graphics2D) g.create(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); drawTile(g2); g2.dispose(); g.drawImage(tileImage, 0, 0, null); long now = System.currentTimeMillis(); Logger.trace(id + " Duration: " + (now - started) + " ms. Cp: " + xyToString() + " O: " + model.getTileOrienation()); } } \ No newline at end of file diff --git a/src/main/java/jcs/ui/layout/tiles/TileCache.java b/src/main/java/jcs/ui/layout/tiles/TileCache.java new file mode 100644 index 00000000..2716f298 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/TileCache.java @@ -0,0 +1 @@ +/* * Copyright 2025 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.Point; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import jcs.entities.AccessoryBean.AccessoryValue; import jcs.entities.AccessoryBean.SignalValue; import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.EAST; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; import static jcs.entities.TileBean.TileType.BLOCK; import static jcs.entities.TileBean.TileType.CROSS; import static jcs.entities.TileBean.TileType.SENSOR; import static jcs.entities.TileBean.TileType.SIGNAL; import jcs.persistence.PersistenceFactory; import jcs.ui.layout.events.TileEvent; import jcs.ui.layout.events.TileEventListener; import org.tinylog.Logger; /** * Factory object to create Tiles and cache tiles * * @author frans */ public class TileCache { //private static final Map tileEventListeners = new HashMap<>(); private static boolean showValues; static final Map tiles = new HashMap<>(); static final Map tileAltPoints = new HashMap<>(); static final Map points = new HashMap<>(); //static final Map altTiles = new HashMap<>(); private TileCache() { } @Deprecated public static void setShowValues(boolean showValues) { TileCache.showValues = showValues; for (Tile tile : tiles.values()) { TileType tileType = tile.getTileType(); switch (tileType) { case SWITCH -> { if (showValues && ((Switch) tile).getTileBean().getAccessoryBean() != null) { tile.setAccessoryValue(tile.getTileBean().getAccessoryBean().getAccessoryValue()); } else { tile.setAccessoryValue(AccessoryValue.OFF); } } case CROSS -> { if (showValues && ((Cross) tile).getTileBean().getAccessoryBean() != null) { tile.setAccessoryValue(tile.getTileBean().getAccessoryBean().getAccessoryValue()); } else { tile.setAccessoryValue(AccessoryValue.OFF); } } case SIGNAL -> { if (showValues && ((Signal) tile).getTileBean().getAccessoryBean() != null) { tile.setSignalValue(tile.getTileBean().getAccessoryBean().getSignalValue()); } else { tile.setSignalValue(SignalValue.OFF); } } case SENSOR -> { if (showValues && ((Sensor) tile).getTileBean().getSensorBean() != null) { tile.setActive(tile.getTileBean().getSensorBean().isActive()); } else { tile.setActive(false); } } case BLOCK -> { } } } } public static List loadTiles() { tileAltPoints.clear(); points.clear(); tiles.clear(); List tileBeans = PersistenceFactory.getService().getTileBeans(); for (TileBean tb : tileBeans) { Tile tile = TileFactory.createTile(tb, showValues); tiles.put(tile.getCenter(), tile); points.put(tile.getId(), tile.getCenter()); //Alternative point(s) to be able to find all points if (!tile.getAltPoints().isEmpty()) { Set alt = tile.getAltPoints(); for (Point ap : alt) { tileAltPoints.put(ap, tile); } } } Logger.trace("Loaded " + tiles.size() + " Tiles..."); return tiles.values().stream().collect(Collectors.toList()); } public static List getTiles() { return tiles.values().stream().collect(Collectors.toList()); } public static void addAndSaveTile(Tile tile) { tiles.put(tile.getCenter(), tile); points.put(tile.getId(), tile.getCenter()); //Alternative point(s) to be able to find all points if (!tile.getAltPoints().isEmpty()) { Set alt = tile.getAltPoints(); for (Point ap : alt) { tileAltPoints.put(ap, tile); } } saveTile(tile); Logger.trace("Added " + tile + " There are now " + tiles.size() + " tiles..."); } public static void saveTile(final Tile tile) { if (tile != null) { TileBean tb = tile.getTileBean(); PersistenceFactory.getService().persist(tb); } else { Logger.warn("Tile is null?"); } } public static void saveTiles() { for (Tile tile : tiles.values()) { saveTile(tile); } } public static void deleteTile(final Tile tile) { if (tile != null) { if (tiles.containsKey(tile.getCenter())) { Set rps = tile.getAltPoints(); //Also remove alt points for (Point ap : rps) { tileAltPoints.remove(ap); } points.remove(tile.getId()); tiles.remove(tile.getCenter()); TileBean tb = tile.getTileBean(); PersistenceFactory.getService().remove(tb); Logger.trace("Deleted " + tile.getId()); } else { Logger.warn("Tile " + tile.getId() + " not found in cache"); } } else { Logger.warn("Tile is null?"); } } public static Tile findTile(Point cp) { Tile result = tiles.get(cp); if (result == null) { result = tileAltPoints.get(cp); } return result; } public static Tile findTile(String id) { Point p = points.get(id); if (p != null) { return findTile(p); } else { return null; } } public static boolean canMoveTo(Tile tile, Point p) { //check if a tile exist with point p Logger.trace("Checking " + tile.id + " New Point (" + p.x + "," + p.y + ")"); if (tiles.containsKey(p) && !tile.getCenter().equals(p) && !tile.getAltPoints().contains(p)) { return false; } if (tileAltPoints.containsKey(p) && !tile.getAltPoints().contains(p)) { return false; } //Check with the tile new alt points if these are also free... Set altPoints = tile.getAltPoints(p); Logger.trace("Checking " + tile.id + " on " + altPoints.size() + " alt points..."); for (Point ap : altPoints) { Logger.trace("Checking " + tile.id + " New Alt Point (" + ap.x + "," + ap.y + ")"); if (tiles.containsKey(ap) && !tile.getCenter().equals(ap) && !tile.getAltPoints().contains(ap)) { return false; } if (tileAltPoints.containsKey(ap) && !tile.getAltPoints().contains(ap)) { return false; } } Logger.trace("Checking " + tile.id + " can move to (" + p.x + "," + p.y + ")"); return true; } public static void moveTo(Tile tile, Point p) { if (canMoveTo(tile, p)) { Logger.trace("Moving tile " + tile.getId() + " from " + tile.xyToString() + " to (" + p.x + "," + p.y + ")"); Set rps = tile.getAltPoints(); //remove alt points for (Point ap : rps) { tileAltPoints.remove(ap); } points.remove(tile.getId()); tiles.remove(tile.getCenter()); tile.setCenter(p); addAndSaveTile(tile); } else { Tile occ = findTile(p); Logger.trace("Can't Move tile " + tile.id + " from " + tile.xyToString() + " to (" + p.x + "," + p.y + ") Is occupied by " + occ.id); } } @Deprecated public static boolean checkTileOccupation(Tile tile) { Set tilePoints = tile.getAllPoints(); for (Point p : tilePoints) { if (tiles.containsKey(p) || tileAltPoints.containsKey(p)) { //The is a match, check if it is an other tile Tile mt = findTile(p); if (tile.getId().equals(mt.getId())) { //same tile continue } else { //Other tile so really occupied return true; } } } return false; } @Deprecated public static boolean containsPoint(Set points) { for (Point p : points) { return tiles.containsKey(p) || tileAltPoints.containsKey(p); } return false; } public static boolean containsPoint(Point point) { return tiles.containsKey(point) || tileAltPoints.containsKey(point); } @Deprecated public static Point checkAvailable(Point newPoint, Orientation orientation) { if (tiles.containsKey(newPoint)) { Tile et = tiles.get(newPoint); Logger.trace("@ " + newPoint + " is allready occcupied by: " + et + "..."); //Search for the nearest avalaible free point //first get the Center point of the tile which is occuping this slot // show warning! Point ecp = et.getCenter(); int w = et.getWidth(); int h = et.getHeight(); Point np; np = switch (orientation) { case EAST -> new Point(ecp.x + w, ecp.y); case WEST -> new Point(newPoint.x - w, ecp.y); case SOUTH -> new Point(ecp.x, newPoint.y + h); default -> new Point(ecp.x, newPoint.y - h); }; Logger.trace("Alternative CP: " + np); // recursive check return checkAvailable(np, orientation); } else { Logger.trace("@ " + newPoint + " is not yet used..."); return newPoint; } } public static Tile rotateTile(Tile tile) { if (!tiles.containsKey(tile.getCenter())) { Logger.warn("Tile " + tile.getId() + " NOT in cache!"); } //Remove the alternative or extra points... for (Point ep : tile.getAltPoints()) { tileAltPoints.remove(ep); } tile.rotate(); //update tiles.put(tile.getCenter(), tile); for (Point ep : tile.getAltPoints()) { tileAltPoints.put(ep, tile); } saveTile(tile); return tile; } public static Tile flipHorizontal(Tile tile) { return flipTile(tile, true); } public static Tile flipVertical(Tile tile) { return flipTile(tile, false); } private static Tile flipTile(Tile tile, boolean horizontal) { if (!tiles.containsKey(tile.getCenter())) { Logger.warn("Tile " + tile.getId() + " NOT in cache!"); } //Remove the alternative or extra points... for (Point ep : tile.getAltPoints()) { tileAltPoints.remove(ep); } if (horizontal) { tile.flipHorizontal(); } else { tile.flipVertical(); } //update tiles.put(tile.getCenter(), tile); for (Point ep : tile.getAltPoints()) { tileAltPoints.put(ep, tile); } saveTile(tile); return tile; } @Deprecated public static void addTileEventListener(TileEventListener listener) { String key = listener.getId(); //tileEventListeners.put(key, listener); } @Deprecated public static void removeTileEventListener(Tile tile) { if (tile instanceof TileEventListener tileEventListener) { removeTileEventListener(tileEventListener); } } static void removeTileEventListener(TileEventListener listener) { String key = listener.getId(); //tileEventListeners.remove(key, listener); } @Deprecated public static void fireTileEventListener(TileEvent tileEvent) { // String key = tileEvent.getTileId(); // TileEventListener listener = tileEventListeners.get(key); // if (listener != null) { // listener.onTileChange(tileEvent); // Logger.trace("Fire listener on tile " + key); // } else { // //Logger.trace("Tile " + key + " not available"); // } } @Deprecated public static void fireAllTileEventListeners(TileEvent tileEvent) { // for (TileEventListener listener : tileEventListeners.values()) { // listener.onTileChange(tileEvent); // } } } \ No newline at end of file diff --git a/src/main/java/jcs/ui/layout/tiles/TileFactory.java b/src/main/java/jcs/ui/layout/tiles/TileFactory.java index 40d6db61..5b0439c2 100755 --- a/src/main/java/jcs/ui/layout/tiles/TileFactory.java +++ b/src/main/java/jcs/ui/layout/tiles/TileFactory.java @@ -1,292 +1 @@ -/* - * Copyright 2023 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout.tiles; - -import java.awt.Point; -import java.util.LinkedList; -import java.util.List; -import jcs.JCS; -import jcs.commandStation.events.AccessoryEventListener; -import jcs.commandStation.events.SensorEventListener; -import jcs.entities.AccessoryBean; -import jcs.entities.SensorBean; -import jcs.entities.TileBean; -import jcs.entities.TileBean.Direction; -import jcs.entities.TileBean.Orientation; -import static jcs.entities.TileBean.TileType.BLOCK; -import static jcs.entities.TileBean.TileType.CROSS; -import static jcs.entities.TileBean.TileType.CROSSING; -import static jcs.entities.TileBean.TileType.CURVED; -import static jcs.entities.TileBean.TileType.END; -import static jcs.entities.TileBean.TileType.SENSOR; -import static jcs.entities.TileBean.TileType.SIGNAL; -import static jcs.entities.TileBean.TileType.STRAIGHT; -import static jcs.entities.TileBean.TileType.STRAIGHT_DIR; -import static jcs.entities.TileBean.TileType.SWITCH; -import org.tinylog.Logger; - -/** - * Factory object to create Tiles and cache tiles - * - * @author frans - */ -public class TileFactory { - - // Keep the records of the used id sequence number - private static int straightIdSeq; - private static int crossingIdSeq; - private static int curvedIdSeq; - private static int switchIdSeq; - private static int crossIdSeq; - private static int signalIdSeq; - private static int sensorIdSeq; - private static int blockIdSeq; - private static int straightDirectionIdSeq; - private static int endIdSeq; - - //private static final Map tileEventListeners = new HashMap<>(); -// private static boolean drawOutline; -// private static boolean showValues; -// public static final Map tiles = new HashMap<>(); -// public static final Map altTiles = new HashMap<>(); - private TileFactory() { - } - - private static int nextIdSeq(String id) { - String idnr = id.substring(3); - int idSeq = Integer.parseInt(idnr); - return idSeq; - } - - private static String nextTileId(TileBean.TileType tileType) { - switch (tileType) { - case STRAIGHT -> { - straightIdSeq++; - return "st-" + straightIdSeq; - } - case CROSSING -> { - crossingIdSeq++; - return "cr-" + crossingIdSeq; - } - case CURVED -> { - curvedIdSeq++; - return "ct-" + curvedIdSeq; - } - case SWITCH -> { - switchIdSeq++; - return "sw-" + switchIdSeq; - } - case CROSS -> { - crossIdSeq++; - return "cs-" + crossIdSeq; - } - case SIGNAL -> { - signalIdSeq++; - return "si-" + signalIdSeq; - } - case SENSOR -> { - sensorIdSeq++; - return "se-" + sensorIdSeq; - } - case BLOCK -> { - blockIdSeq++; - return "bk-" + blockIdSeq; - } - case STRAIGHT_DIR -> { - straightDirectionIdSeq++; - return "sd-" + straightDirectionIdSeq; - } - case END -> { - endIdSeq++; - return "et-" + endIdSeq; - } - default -> { - Logger.warn("Unknown Tile Type " + tileType); - return null; - } - } - } - - private static int maxIdSeq(int currentId, int newId) { - if (currentId < newId) { - return newId; - } else { - return currentId; - } - } - - public static Tile createTile(String tileId) { - TileBean tileBean = JCS.getPersistenceService().getTileBean(tileId); - return createTile(tileBean); - } - - public static Tile createTile(TileBean tileBean) { - return createTile(tileBean, false); - } - - public static Tile createTile(TileBean tileBean, boolean showValues) { - if (tileBean == null) { - return null; - } - - TileBean.TileType tileType = tileBean.getTileType(); - Tile tile = null; - switch (tileType) { - case STRAIGHT -> { - tile = new Straight(tileBean); - straightIdSeq = maxIdSeq(straightIdSeq, nextIdSeq(tileBean.getId())); - } - case CROSSING -> { - tile = new Crossing(tileBean); - crossingIdSeq = maxIdSeq(crossingIdSeq, nextIdSeq(tileBean.getId())); - } - case CURVED -> { - tile = new Curved(tileBean); - curvedIdSeq = maxIdSeq(curvedIdSeq, nextIdSeq(tileBean.getId())); - } - case SWITCH -> { - tile = new Switch(tileBean); - tile.setAccessoryBean(tileBean.getAccessoryBean()); - - switchIdSeq = maxIdSeq(switchIdSeq, nextIdSeq(tileBean.getId())); - if (showValues && tileBean.getAccessoryBean() != null) { - tile.setAccessoryValue((tileBean.getAccessoryBean()).getAccessoryValue()); - } - JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); - } - case CROSS -> { - tile = new Cross(tileBean); - tile.setAccessoryBean(tileBean.getAccessoryBean()); - - crossIdSeq = maxIdSeq(crossIdSeq, nextIdSeq(tileBean.getId())); - if (showValues && tileBean.getAccessoryBean() != null) { - tile.setAccessoryValue((tileBean.getAccessoryBean()).getAccessoryValue()); - } - JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); - } - case SIGNAL -> { - tile = new Signal(tileBean); - tile.setAccessoryBean(tileBean.getAccessoryBean()); - - signalIdSeq = maxIdSeq(signalIdSeq, nextIdSeq(tileBean.getId())); - if (showValues && tileBean.getAccessoryBean() != null) { - ((Signal) tile).setSignalValue(((AccessoryBean) tileBean.getAccessoryBean()).getSignalValue()); - } - JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); - } - case SENSOR -> { - tile = new Sensor(tileBean); - tile.setSensorBean(tileBean.getSensorBean()); - sensorIdSeq = maxIdSeq(sensorIdSeq, nextIdSeq(tileBean.getId())); - if (showValues && tileBean.getSensorBean() != null) { - ((Sensor) tile).setActive(((SensorBean) tileBean.getSensorBean()).isActive()); - } - JCS.getJcsCommandStation().addSensorEventListener((SensorEventListener) tile); - } - case BLOCK -> { - tile = new Block(tileBean); - tile.setBlockBean(tileBean.getBlockBean()); - blockIdSeq = maxIdSeq(blockIdSeq, nextIdSeq(tileBean.getId())); - } - case STRAIGHT_DIR -> { - tile = new StraightDirection(tileBean); - straightDirectionIdSeq = maxIdSeq(straightDirectionIdSeq, nextIdSeq(tileBean.getId())); - } - case END -> { - tile = new End(tileBean); - endIdSeq = maxIdSeq(endIdSeq, nextIdSeq(tileBean.getId())); - } - default -> - Logger.warn("Unknown Tile Type " + tileType); - } - -// if (tile != null) { -// tile.setDrawOutline(drawOutline); -// } -// addTileEventListener((TileEventListener) tile); - return (Tile) tile; - } - - /** - * @param tileType type of type to create - * @param orientation whether the orientation of the Tile is EAST, WEST, NORTH or SOUTH - * @param x the tile center X - * @param y the tile center Y - * @return a Tile object - */ - public static Tile createTile(TileBean.TileType tileType, Orientation orientation, int x, int y) { - return createTile(tileType, orientation, Direction.CENTER, x, y); - } - - /** - * @param tileType type of type to create - * @param orientation whether the orientation of the Tile is EAST, WEST, NORTH or SOUTH - * @param direction direction plays a role with Turnout tiles whether it goes to the Left or Right - * @param x the tile center X - * @param y the tile center Y - * @return a Tile object - */ - public static Tile createTile(TileBean.TileType tileType, Orientation orientation, Direction direction, int x, int y) { - return createTile(tileType, orientation, direction, new Point(x, y)); - } - - public static Tile createTile(TileBean.TileType tileType, Orientation orientation, Direction direction, Point center) { - Tile tile = null; - switch (tileType) { - case STRAIGHT -> { - tile = new Straight(orientation, center); - } - case CROSSING -> { - tile = new Crossing(orientation, center); - } - case CURVED -> - tile = new Curved(orientation, center); - case SWITCH -> - tile = new Switch(orientation, direction, center); - case CROSS -> - tile = new Cross(orientation, direction, center); - case SIGNAL -> - tile = new Signal(orientation, center); - case SENSOR -> - tile = new Sensor(orientation, center); - case BLOCK -> - tile = new Block(orientation, center); - case STRAIGHT_DIR -> - tile = new StraightDirection(orientation, center); - case END -> - tile = new End(orientation, center); - default -> - Logger.warn("Unknown Tile Type " + tileType); - } - - if (tile != null) { - tile.setId(nextTileId(tileType)); - } - - return (Tile) tile; - } - - public static List toTiles(List tileBeans, boolean drawOutline, boolean showValues) { - List tileList = new LinkedList<>(); - - for (TileBean tileBean : tileBeans) { - Tile tile = createTile(tileBean, showValues); - tileList.add(tile); - } - return tileList; - } - -} +/* * Copyright 2023 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.Point; import java.util.LinkedList; import java.util.List; import jcs.JCS; import jcs.commandStation.events.AccessoryEventListener; import jcs.commandStation.events.SensorEventListener; import jcs.entities.AccessoryBean; import jcs.entities.SensorBean; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.TileType.BLOCK; import static jcs.entities.TileBean.TileType.CROSS; import static jcs.entities.TileBean.TileType.CROSSING; import static jcs.entities.TileBean.TileType.CURVED; import static jcs.entities.TileBean.TileType.END; import static jcs.entities.TileBean.TileType.SENSOR; import static jcs.entities.TileBean.TileType.SIGNAL; import static jcs.entities.TileBean.TileType.STRAIGHT; import static jcs.entities.TileBean.TileType.STRAIGHT_DIR; import static jcs.entities.TileBean.TileType.SWITCH; import org.tinylog.Logger; /** * Factory object to create Tiles and cache tiles * * @author frans */ public class TileFactory { // Keep the records of the used id sequence number private static int straightIdSeq; private static int crossingIdSeq; private static int curvedIdSeq; private static int switchIdSeq; private static int crossIdSeq; private static int signalIdSeq; private static int sensorIdSeq; private static int blockIdSeq; private static int straightDirectionIdSeq; private static int endIdSeq; private TileFactory() { } private static int nextIdSeq(String id) { String idnr = id.substring(3); int idSeq = Integer.parseInt(idnr); return idSeq; } private static String nextTileId(TileBean.TileType tileType) { switch (tileType) { case STRAIGHT -> { straightIdSeq++; return "st-" + straightIdSeq; } case CROSSING -> { crossingIdSeq++; return "cr-" + crossingIdSeq; } case CURVED -> { curvedIdSeq++; return "ct-" + curvedIdSeq; } case SWITCH -> { switchIdSeq++; return "sw-" + switchIdSeq; } case CROSS -> { crossIdSeq++; return "cs-" + crossIdSeq; } case SIGNAL -> { signalIdSeq++; return "si-" + signalIdSeq; } case SENSOR -> { sensorIdSeq++; return "se-" + sensorIdSeq; } case BLOCK -> { blockIdSeq++; return "bk-" + blockIdSeq; } case STRAIGHT_DIR -> { straightDirectionIdSeq++; return "sd-" + straightDirectionIdSeq; } case END -> { endIdSeq++; return "et-" + endIdSeq; } default -> { Logger.warn("Unknown Tile Type " + tileType); return null; } } } private static int maxIdSeq(int currentId, int newId) { if (currentId < newId) { return newId; } else { return currentId; } } public static Tile createTile(String tileId) { TileBean tileBean = JCS.getPersistenceService().getTileBean(tileId); return createTile(tileBean); } public static Tile createTile(TileBean tileBean) { return createTile(tileBean, false); } public static Tile createTile(TileBean tileBean, boolean showValues) { if (tileBean == null) { return null; } TileBean.TileType tileType = tileBean.getTileType(); Tile tile = null; switch (tileType) { case STRAIGHT -> { tile = new Straight(tileBean); straightIdSeq = maxIdSeq(straightIdSeq, nextIdSeq(tileBean.getId())); } case CROSSING -> { tile = new Crossing(tileBean); crossingIdSeq = maxIdSeq(crossingIdSeq, nextIdSeq(tileBean.getId())); } case CURVED -> { tile = new Curved(tileBean); curvedIdSeq = maxIdSeq(curvedIdSeq, nextIdSeq(tileBean.getId())); } case SWITCH -> { tile = new Switch(tileBean); tile.setAccessoryBean(tileBean.getAccessoryBean()); switchIdSeq = maxIdSeq(switchIdSeq, nextIdSeq(tileBean.getId())); if (showValues && tileBean.getAccessoryBean() != null) { tile.setAccessoryValue((tileBean.getAccessoryBean()).getAccessoryValue()); } JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); } case CROSS -> { tile = new Cross(tileBean); tile.setAccessoryBean(tileBean.getAccessoryBean()); crossIdSeq = maxIdSeq(crossIdSeq, nextIdSeq(tileBean.getId())); if (showValues && tileBean.getAccessoryBean() != null) { tile.setAccessoryValue((tileBean.getAccessoryBean()).getAccessoryValue()); } JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); } case SIGNAL -> { tile = new Signal(tileBean); tile.setAccessoryBean(tileBean.getAccessoryBean()); signalIdSeq = maxIdSeq(signalIdSeq, nextIdSeq(tileBean.getId())); if (showValues && tileBean.getAccessoryBean() != null) { ((Signal) tile).setSignalValue(((AccessoryBean) tileBean.getAccessoryBean()).getSignalValue()); } JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); } case SENSOR -> { tile = new Sensor(tileBean); tile.setSensorBean(tileBean.getSensorBean()); sensorIdSeq = maxIdSeq(sensorIdSeq, nextIdSeq(tileBean.getId())); if (showValues && tileBean.getSensorBean() != null) { ((Sensor) tile).setActive(((SensorBean) tileBean.getSensorBean()).isActive()); } JCS.getJcsCommandStation().addSensorEventListener((SensorEventListener) tile); } case BLOCK -> { tile = new Block(tileBean); tile.setBlockBean(tileBean.getBlockBean()); blockIdSeq = maxIdSeq(blockIdSeq, nextIdSeq(tileBean.getId())); } case STRAIGHT_DIR -> { tile = new StraightDirection(tileBean); straightDirectionIdSeq = maxIdSeq(straightDirectionIdSeq, nextIdSeq(tileBean.getId())); } case END -> { tile = new End(tileBean); endIdSeq = maxIdSeq(endIdSeq, nextIdSeq(tileBean.getId())); } default -> Logger.warn("Unknown Tile Type " + tileType); } return (Tile) tile; } public static void rollback(Tile tile) { switch (tile.tileType) { case STRAIGHT -> { straightIdSeq--; } case CROSSING -> { crossingIdSeq--; } case CURVED -> { curvedIdSeq--; } case SWITCH -> { switchIdSeq--; } case CROSS -> { crossIdSeq--; } case SIGNAL -> { signalIdSeq--; } case SENSOR -> { sensorIdSeq--; } case BLOCK -> { blockIdSeq--; } case STRAIGHT_DIR -> { straightDirectionIdSeq--; } case END -> { endIdSeq--; } } } /** * @param tileType type of type to create * @param orientation whether the orientation of the Tile is EAST, WEST, NORTH or SOUTH * @param x the tile center X * @param y the tile center Y * @return a Tile object */ public static Tile createTile(TileBean.TileType tileType, Orientation orientation, int x, int y) { return createTile(tileType, orientation, Direction.CENTER, x, y); } /** * @param tileType type of type to create * @param orientation whether the orientation of the Tile is EAST, WEST, NORTH or SOUTH * @param direction direction plays a role with Turnout tiles whether it goes to the Left or Right * @param x the tile center X * @param y the tile center Y * @return a Tile object */ public static Tile createTile(TileBean.TileType tileType, Orientation orientation, Direction direction, int x, int y) { return createTile(tileType, orientation, direction, new Point(x, y)); } public static Tile createTile(TileBean.TileType tileType, Orientation orientation, Direction direction, Point center) { Tile tile = null; switch (tileType) { case STRAIGHT -> { tile = new Straight(orientation, center); } case CROSSING -> { tile = new Crossing(orientation, center); } case CURVED -> tile = new Curved(orientation, center); case SWITCH -> tile = new Switch(orientation, direction, center); case CROSS -> tile = new Cross(orientation, direction, center); case SIGNAL -> tile = new Signal(orientation, center); case SENSOR -> tile = new Sensor(orientation, center); case BLOCK -> tile = new Block(orientation, center); case STRAIGHT_DIR -> tile = new StraightDirection(orientation, center); case END -> tile = new End(orientation, center); default -> Logger.warn("Unknown Tile Type " + tileType); } if (tile != null) { tile.setId(nextTileId(tileType)); } return (Tile) tile; } public static List toTiles(List tileBeans, boolean drawOutline, boolean showValues) { List tileList = new LinkedList<>(); for (TileBean tileBean : tileBeans) { Tile tile = createTile(tileBean, showValues); tileList.add(tile); } return tileList; } } \ No newline at end of file From 0a9560e5ee0a4dd46632ebbbea99604e3929c34b Mon Sep 17 00:00:00 2001 From: Frans Jacobs <41232225+fransjacobs@users.noreply.github.com> Date: Thu, 30 Jan 2025 16:03:14 +0100 Subject: [PATCH 12/70] Fix moving of tile in edit screen --- src/main/java/jcs/ui/layout/LayoutCanvas.java | 68 +- src/main/java/jcs/ui/layout/tiles/Tile.java | 1142 ++++++++++++++++- .../java/jcs/ui/layout/tiles/TileCache.java | 404 +++++- 3 files changed, 1597 insertions(+), 17 deletions(-) diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.java b/src/main/java/jcs/ui/layout/LayoutCanvas.java index edc748ef..15011e12 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.java +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.java @@ -30,7 +30,6 @@ import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import java.util.List; -import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import javax.swing.JFrame; @@ -50,6 +49,7 @@ import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; +import static jcs.entities.TileBean.Orientation.SOUTH; import jcs.entities.TileBean.TileType; import static jcs.entities.TileBean.TileType.BLOCK; import static jcs.entities.TileBean.TileType.CROSS; @@ -74,7 +74,6 @@ import jcs.ui.layout.tiles.Tile; import jcs.ui.layout.tiles.TileFactory; import jcs.ui.layout.tiles.TileCache; -import static jcs.ui.layout.tiles.TileCache.findTile; import org.tinylog.Logger; /** @@ -108,9 +107,7 @@ public enum Mode { private Tile selectedTile; private RoutesDialog routesDialog; - //private final Map selectedRouteElements; - //private Point mousePressedPoint; public LayoutCanvas() { this(false); } @@ -271,7 +268,7 @@ private void mouseMoveAction(MouseEvent evt) { private void mousePressedAction(MouseEvent evt) { Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); //Clear any previous selection - Tile previousSelected = this.selectedTile; + Tile previousSelected = selectedTile; selectedTile = TileCache.findTile(snapPoint); if (selectedTile != null) { selectedTile.setSelected(true); @@ -363,15 +360,10 @@ void removeTile(Tile tile) { private void mouseDragAction(MouseEvent evt) { Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); - if (selectedTile != null) { int z = getComponentZOrder(selectedTile); - Logger.trace("Moving Tile: " + selectedTile.getId() + " Z: " + z + " @ " + selectedTile.xyToString()); - - //Put on Top setComponentZOrder(selectedTile, 0); - int curX = snapPoint.x - Tile.GRID; - int curY = snapPoint.y - Tile.GRID; + //Logger.trace("Moving: " + selectedTile.getId() + " @ " + selectedTile.xyToString() + " P: " + snapPoint.x + "," + snapPoint.y + ")"); if (TileCache.canMoveTo(selectedTile, snapPoint)) { selectedTile.setSelectedColor(Tile.DEFAULT_SELECTED_COLOR); @@ -379,20 +371,66 @@ private void mouseDragAction(MouseEvent evt) { selectedTile.setSelectedColor(Tile.DEFAULT_WARN_COLOR); } + int curX, curY; + switch (selectedTile.getTileType()) { + case BLOCK -> { + if (selectedTile.isHorizontal()) { + curX = snapPoint.x - Tile.GRID - Tile.GRID * 2; + curY = snapPoint.y - Tile.GRID; + } else { + curX = snapPoint.x - Tile.GRID; + curY = snapPoint.y - Tile.GRID - Tile.GRID * 2; + } + } + case CROSS -> { + switch (selectedTile.getOrientation()) { + case SOUTH -> { + curX = snapPoint.x - Tile.GRID; + curY = snapPoint.y - Tile.GRID; + } + case WEST -> { + curX = snapPoint.x - Tile.GRID - Tile.GRID * 2; + curY = snapPoint.y - Tile.GRID; + } + case NORTH -> { + curX = snapPoint.x - Tile.GRID; + curY = snapPoint.y - Tile.GRID - Tile.GRID * 2; + } + default -> { + //East + curX = snapPoint.x - Tile.GRID; + curY = snapPoint.y - Tile.GRID; + } + } + } + default -> { + curX = snapPoint.x - Tile.GRID; + curY = snapPoint.y - Tile.GRID; + } + } selectedTile.setBounds(curX, curY, selectedTile.getWidth(), selectedTile.getHeight()); + //this.repaint(selectedTile.getTileBounds()); } } private void mouseReleasedAction(MouseEvent evt) { Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); + //if (selectedTile != null) { + // Logger.trace(selectedTile.getId() + " sp: (" + snapPoint.x + "," + snapPoint.y + ")"); + //} else { + // Logger.trace("No Tile @ (" + snapPoint.x + "," + snapPoint.y + ")"); + //} - if (!Mode.CONTROL.equals(mode) && MouseEvent.BUTTON1 == evt.getButton() && selectedTile != null && !selectedTile.getCenter().equals(snapPoint)) { - + if (!Mode.CONTROL.equals(mode) && MouseEvent.BUTTON1 == evt.getButton() && selectedTile != null) { if (TileCache.canMoveTo(selectedTile, snapPoint)) { TileCache.moveTo(selectedTile, snapPoint); } else { - Tile occ = TileCache.findTile(snapPoint); - Logger.trace("Can't Move tile " + selectedTile.getId() + " from " + selectedTile.xyToString() + " to (" + snapPoint.x + "," + snapPoint.y + ") Is occupied by " + occ.getId()); + //Tile occ = TileCache.findTile(snapPoint); + //String occtile = ""; + //if (occ != null) { + // occtile = " Is occupied by " + occ.getId(); + //} + //Logger.trace("Can't Move tile " + selectedTile.getId() + " from " + selectedTile.xyToString() + " to (" + snapPoint.x + "," + snapPoint.y + ")" + occtile); selectedTile.setSelectedColor(Tile.DEFAULT_SELECTED_COLOR); selectedTile.setBounds(selectedTile.getTileBounds()); diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java index 48c1598a..07127650 100755 --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -1 +1,1141 @@ -/* * Copyright 2024 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.AffineTransform; import java.awt.geom.Ellipse2D; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; import java.beans.PropertyChangeListener; import java.io.Serializable; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.swing.JComponent; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.AccessoryValue; import jcs.entities.AccessoryBean.SignalType; import jcs.entities.BlockBean; import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; import jcs.entities.SensorBean; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import jcs.entities.TileBean.TileType; import jcs.ui.layout.LayoutUtil; import static jcs.ui.layout.tiles.Block.BLOCK_HEIGHT; import static jcs.ui.layout.tiles.Block.BLOCK_WIDTH; import org.imgscalr.Scalr; import org.imgscalr.Scalr.Method; import org.imgscalr.Scalr.Mode; import org.tinylog.Logger; /** * Basic graphic element to display a track, turnout, etc on the screen.
* By default the drawing of a Tile is Horizontal from L to R or West to East.
* The default orientation is East. * *

* The default size of a Tile is 40 tileX 40 pixels.
* The center point of a Tile is stored and always snapped to the nearest grid point.
* The basic grid is 20x 20 pixels.
* *

* A Tile can be rotated (always clockwise).
* Rotation will change the orientation from East -> South -> West -> North -> East.
* *

* A Tile is rendered to a Buffered Image to speed up the display */ public abstract class Tile extends JComponent { //implements TileEventListener { //, ItemSelectable { public static final int GRID = 20; public static final int DEFAULT_WIDTH = GRID * 2; public static final int DEFAULT_HEIGHT = GRID * 2; static final int RENDER_GRID = GRID * 10; static final int RENDER_WIDTH = RENDER_GRID * 2; static final int RENDER_HEIGHT = RENDER_GRID * 2; public static final Color DEFAULT_BACKGROUND_COLOR = Color.white; public static final Color DEFAULT_TRACK_COLOR = Color.lightGray; public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.blue; public static final Color DEFAULT_SELECTED_COLOR = Color.orange; public static final Color DEFAULT_WARN_COLOR = Color.red; public static final String MODEL_CHANGED_PROPERTY = "model"; public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled"; /** * The data model that determines the button's state. */ protected TileModel model = null; protected String id; protected Integer tileX; protected Integer tileY; protected int renderWidth; protected int renderHeight; //protected Orientation tileOrientation; protected Direction tileDirection; protected TileType tileType; protected String accessoryId; protected String sensorId; protected AccessoryValue accessoryValue; protected AccessoryValue routeValue; protected SignalType signalType; protected AccessoryBean.SignalValue signalValue; protected TileBean tileBean; protected AccessoryBean accessoryBean; protected SensorBean sensorBean; protected BlockBean blockBean; protected List neighbours; protected int offsetX = 0; protected int offsetY = 0; protected int renderOffsetX = 0; protected int renderOffsetY = 0; //protected Color selectedColor; protected Color trackColor; protected Color trackRouteColor; protected Orientation incomingSide; protected Color backgroundColor; protected boolean drawName = true; protected BufferedImage tileImage; protected PropertyChangeListener propertyChangeListener; protected ChangeListener changeListener = null; protected ActionListener actionListener = null; protected transient ChangeEvent changeEvent; private Handler handler; protected Tile(TileType tileType, Orientation orientation, Point center, int width, int height) { this(tileType, orientation, Direction.CENTER, center.x, center.y, width, height); } protected Tile(TileType tileType, Orientation orientation, int x, int y, int width, int height) { this(tileType, orientation, Direction.CENTER, x, y, width, height); } protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { this(tileType, orientation, direction, x, y, width, height, null, null); } protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height, Color backgroundColor, Color selectedColor) { this.tileType = tileType; //this.tileOrientation = orientation; //model.setTileOrienation(orientation); this.tileDirection = direction; this.tileX = x; this.tileY = y; setLayout(null); Dimension d = new Dimension(width, height); setSize(d); setPreferredSize(d); this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT; this.trackColor = DEFAULT_TRACK_COLOR; this.backgroundColor = backgroundColor; //this.selectedColor = selectedColor; if (this.backgroundColor == null) { this.backgroundColor = DEFAULT_BACKGROUND_COLOR; } // if (this.selectedColor == null) { // this.selectedColor = DEFAULT_SELECTED_COLOR; // } } protected Tile(TileBean tileBean) { this(tileBean, tileWidth(tileBean.getOrientation(), tileBean.getTileType()), tileHeight(tileBean.getOrientation(), tileBean.getTileType())); } protected Tile(TileBean tileBean, int width, int height) { this.tileBean = tileBean; //Quick properties this.id = tileBean.getId(); this.tileType = tileBean.getTileType(); //this.tileOrientation = tileBean.getOrientation(); //this.model.setTileOrienation(tileBean.getOrientation()); this.tileDirection = tileBean.getDirection(); this.tileX = tileBean.getX(); this.tileY = tileBean.getY(); this.accessoryId = tileBean.getAccessoryId(); this.accessoryBean = tileBean.getAccessoryBean(); this.signalType = tileBean.getSignalType(); this.sensorId = tileBean.getSensorId(); this.sensorBean = tileBean.getSensorBean(); this.blockBean = tileBean.getBlockBean(); setLayout(null); Dimension d = new Dimension(width, height); setSize(d); setPreferredSize(d); this.trackColor = DEFAULT_TRACK_COLOR; this.backgroundColor = DEFAULT_BACKGROUND_COLOR; // this.selectedColor = DEFAULT_SELECTED_COLOR; this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT; } protected static int tileWidth(Orientation orientation, TileType tileType) { if (Orientation.EAST == orientation || Orientation.WEST == orientation) { if (null == tileType) { return DEFAULT_WIDTH; } else { return switch (tileType) { case BLOCK -> BLOCK_WIDTH; case CROSS -> DEFAULT_WIDTH * 2; default -> DEFAULT_WIDTH; }; } } else { return DEFAULT_WIDTH; } } protected static int tileHeight(Orientation orientation, TileType tileType) { if (Orientation.EAST == orientation || Orientation.WEST == orientation) { return DEFAULT_HEIGHT; } else { if (null == tileType) { return DEFAULT_HEIGHT; } else { return switch (tileType) { case BLOCK -> BLOCK_HEIGHT; case CROSS -> DEFAULT_HEIGHT * 2; default -> DEFAULT_HEIGHT; }; } } } protected void populateModel() { if (this.blockBean != null) { this.model.setBlockState(this.blockBean.getBlockState()); this.model.setLocomotive(this.blockBean.getLocomotive()); this.model.setArrivalSuffix(this.blockBean.getArrivalSuffix()); this.model.setLogicalDirection(LocomotiveBean.Direction.get(this.blockBean.getLogicalDirection())); } } public TileBean getTileBean() { if (tileBean == null) { tileBean = new TileBean(); tileBean.setId(this.id); tileBean.setX(this.tileX); tileBean.setY(this.tileY); tileBean.setTileType(this.tileType); //tileBean.setTileOrientation(this.tileOrientation.getOrientation()); tileBean.setTileOrientation(this.model.getTileOrienation().getOrientation()); tileBean.setTileDirection(this.tileDirection.getDirection()); tileBean.setSignalType(this.signalType); tileBean.setAccessoryId(this.accessoryId); tileBean.setSensorId(this.sensorId); tileBean.setAccessoryBean(this.accessoryBean); tileBean.setSensorBean(this.sensorBean); tileBean.setBlockBean(this.blockBean); } return tileBean; } public boolean isSelected() { return model.isSelected(); } public void setSelected(boolean b) { //boolean oldValue = isSelected(); model.setSelected(b); } public String getId() { return id; } public void setId(String id) { this.id = id; } public SignalType getSignalType() { return signalType; } public void setSignalType(SignalType signalType) { this.signalType = signalType; } public Integer getTileX() { return tileX; } public Integer getTileY() { return tileY; } public Point getCenter() { return new Point(this.tileX, this.tileY); } public void setCenter(Point center) { tileX = center.x; tileY = center.y; if (tileBean != null) { tileBean.setCenter(center); } Logger.trace(id + " Cp: " + xyToString()); } public Orientation getOrientation() { //return tileOrientation; return model.getTileOrienation(); } public void setOrientation(Orientation orientation) { //this.tileOrientation = orientation; model.setTileOrienation(orientation); if (tileBean != null) { tileBean.setOrientation(orientation); } } public Direction getDirection() { return tileDirection; } public void setDirection(Direction direction) { this.tileDirection = direction; if (tileBean != null) { tileBean.setDirection(direction); } } public String getAccessoryId() { return accessoryId; } public void setAccessoryId(String accessoryId) { this.accessoryId = accessoryId; if (tileBean != null) { tileBean.setAccessoryId(accessoryId); } } public String getSensorId() { return sensorId; } public void setSensorId(String sensorId) { this.sensorId = sensorId; } public boolean isActive() { return model.isSensorActive(); } public void setActive(boolean active) { model.setSensorActive(active); } public BlockState getBlockState() { return model.getBlockState(); } public void setBlockState(BlockState blockState) { if (blockBean != null) { blockBean.setBlockState(blockState); LocomotiveBean locomotive = model.getLocomotive(); model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (blockState == BlockState.OCCUPIED || blockState == BlockState.INBOUND || blockState == BlockState.OUTBOUND)); } model.setBlockState(blockState); } public String getDepartureSuffix() { return model.getDepartureSuffix(); } public void setDepartureSuffix(String suffix) { if (blockBean != null) { blockBean.setDepartureSuffix(suffix); } model.setDepartureSuffix(suffix); } public boolean isReverseArrival() { return model.isReverseArrival(); } public void setReverseArrival(boolean reverseArrival) { if (blockBean != null) { blockBean.setReverseArrival(reverseArrival); } model.setReverseArrival(reverseArrival); } public LocomotiveBean.Direction getLogicalDirection() { return model.getLogicalDirection(); } public void setLogicalDirection(LocomotiveBean.Direction logicalDirection) { if (blockBean != null) { blockBean.setLogicalDirection(logicalDirection.getDirection()); } model.setLogicalDirection(logicalDirection); } public LocomotiveBean getLocomotive() { return model.getLocomotive(); } public void setLocomotive(LocomotiveBean locomotive) { if (blockBean != null) { blockBean.setLocomotive(locomotive); model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (model.getBlockState() == BlockState.OCCUPIED || model.getBlockState() == BlockState.INBOUND || model.getBlockState() == BlockState.OUTBOUND)); } model.setLocomotive(locomotive); } public AccessoryBean getAccessoryBean() { return accessoryBean; } public void setAccessoryBean(AccessoryBean accessoryBean) { this.accessoryBean = accessoryBean; if (accessoryBean != null) { accessoryId = accessoryBean.getId(); signalValue = accessoryBean.getSignalValue(); signalType = SignalType.getSignalType(accessoryBean.getType()); } else { accessoryId = null; signalType = SignalType.NONE; signalValue = AccessoryBean.SignalValue.OFF; } } public AccessoryValue getAccessoryValue() { if (this.accessoryValue == null) { return AccessoryValue.OFF; } else { return accessoryValue; } } public void setAccessoryValue(AccessoryValue value) { this.accessoryValue = value; repaint(); } public AccessoryValue getRouteValue() { if (routeValue == null) { return AccessoryValue.OFF; } else { return routeValue; } } public void setRouteValue(AccessoryValue value) { this.routeValue = value; repaint(); } public AccessoryBean.SignalValue getSignalValue() { return signalValue; } public void setSignalValue(AccessoryBean.SignalValue signalValue) { this.signalValue = signalValue; repaint(); } public SensorBean getSensorBean() { return sensorBean; } public void setSensorBean(SensorBean sensorBean) { this.sensorBean = sensorBean; } public BlockBean getBlockBean() { return blockBean; } public void setBlockBean(BlockBean blockBean) { this.blockBean = blockBean; } public void setRenderWidth(int renderWidth) { this.renderWidth = renderWidth; } public void setRenderHeight(int renderHeight) { this.renderHeight = renderHeight; } public int getRenderOffsetX() { return renderOffsetX; } public void setRenderOffsetX(int renderOffsetX) { this.renderOffsetX = renderOffsetX; } public int getRenderOffsetY() { return renderOffsetY; } public void setRenderOffsetY(int renderOffsetY) { this.renderOffsetY = renderOffsetY; } public TileBean.TileType getTileType() { return this.tileType; } public final void setTileType(TileType tileType) { this.tileType = tileType; } public Color getTrackColor() { return trackColor; } public final void setTrackColor(Color trackColor) { this.trackColor = trackColor; } public Color getTrackRouteColor() { return trackRouteColor; } public void setTrackRouteColor(Color trackRouteColor) { this.trackRouteColor = trackRouteColor; } public Color getSelectedColor() { return model.getSelectedColor(); } public void setSelectedColor(Color selectedColor) { this.model.setSelectedColor(selectedColor); } public Orientation getIncomingSide() { return incomingSide; } public void setIncomingSide(Orientation incomingSide) { this.incomingSide = incomingSide; } public Color getBackgroundColor() { return backgroundColor; } public void setBackgroundColor(Color backgroundColor) { this.backgroundColor = backgroundColor; } public boolean isDrawRoute() { return model.isShowRoute(); } public void setDrawRoute(boolean drawRoute) { this.model.setShowRoute(drawRoute); } public int getRenderWidth() { return renderWidth; } public int getRenderHeight() { return renderHeight; } abstract void renderTile(Graphics2D g2d); abstract void renderTileRoute(Graphics2D g2d); public abstract Map getNeighborPoints(); public abstract Map getEdgePoints(); //public abstract Set getAllPoints(); //public abstract Set getAllPoints(Point center); //public abstract Set getAltPoints(Point center); Set getAltPoints(Point center) { return Collections.EMPTY_SET; } public Set getAllPoints() { return getAllPoints(getCenter()); } Set getAllPoints(Point center) { Set aps = new HashSet<>(); aps.add(center); return aps; } /** * Draw the Tile * * @param g2d The graphics handle */ public void drawTile(Graphics2D g2d) { // by default and image is rendered in the EAST orientation Orientation tileOrientation = model.getTileOrienation(); // if (tileOrientation == null) { // tileOrientation = Orientation.EAST; // } BufferedImage bf = createImage(); Graphics2D g2di = bf.createGraphics(); //Avoid errors if (model.isShowRoute() && incomingSide == null) { incomingSide = getOrientation(); } if (model.isSelected()) { g2di.setBackground(model.getSelectedColor()); } else { g2di.setBackground(backgroundColor); } g2di.clearRect(0, 0, renderWidth, renderHeight); int ox = 0, oy = 0; AffineTransform trans = new AffineTransform(); switch (tileOrientation) { case SOUTH -> { trans.rotate(Math.PI / 2, renderWidth / 2, renderHeight / 2); ox = (renderHeight - renderWidth) / 2; oy = (renderWidth - renderHeight) / 2; trans.translate(-ox, -oy); } case WEST -> { trans.rotate(Math.PI, renderWidth / 2, renderHeight / 2); trans.translate(ox, oy); } case NORTH -> { trans.rotate(-Math.PI / 2, renderWidth / 2, renderHeight / 2); ox = (renderHeight - renderWidth) / 2; oy = (renderWidth - renderHeight) / 2; trans.translate(-ox, -oy); } default -> { trans.rotate(0.0, this.renderWidth / 2, this.renderHeight / 2); trans.translate(ox, oy); } } //Logger.trace(tileOrientation.getOrientation() + " renderWidth: " + renderWidth + " renderHeight: " + renderHeight + " CP: (" + renderWidth / 2 + "," + renderHeight / 2 + ")"); //Logger.trace(tileOrientation.getOrientation() + " ox: " + ox + " oy: " + oy); g2di.setTransform(trans); renderTile(g2di); if (model.isShowRoute()) { renderTileRoute(g2di); } if (model.isShowCenter()) { drawCenterPoint(g2di); } // Scale the image back... if (model.isScaleImage()) { tileImage = Scalr.resize(bf, Method.AUTOMATIC, Mode.FIT_EXACT, getWidth(), getHeight(), Scalr.OP_ANTIALIAS); } else { tileImage = bf; } g2di.dispose(); Logger.trace(id + " Cp: " + xyToString()); } public BufferedImage getTileImage() { return tileImage; } /** * Render a tile image Always starts at (0,0) used the default width and height * * @param g2 the Graphic context */ public void drawName(Graphics2D g2) { } protected void drawCenterPoint(Graphics2D g2d) { drawCenterPoint(g2d, Color.magenta); } protected void drawCenterPoint(Graphics2D g2, Color color) { drawCenterPoint(g2, color, 60); } protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { double dX = (renderWidth / 2 - size / 2); double dY = (renderHeight / 2 - size / 2); g2d.setColor(color); g2d.fill(new Ellipse2D.Double(dX, dY, size, size)); } /** * Rotate the tile clockwise 90 deg * * @return the new Orientation */ public Orientation rotate() { Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case EAST -> setOrientation(Orientation.SOUTH); case SOUTH -> setOrientation(Orientation.WEST); case WEST -> setOrientation(Orientation.NORTH); default -> setOrientation(Orientation.EAST); } return model.getTileOrienation(); } public void flipHorizontal() { Orientation tileOrientation = model.getTileOrienation(); if (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) { rotate(); rotate(); } } public void flipVertical() { Orientation tileOrientation = model.getTileOrienation(); if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { rotate(); rotate(); } } @Override public void move(int newX, int newY) { Point cs = LayoutUtil.snapToGrid(newX, newY); setCenter(cs); } protected static void drawRotate(Graphics2D g2d, double x, double y, int angle, String text) { g2d.translate((float) x, (float) y); g2d.rotate(Math.toRadians(angle)); g2d.drawString(text, 0, 0); g2d.rotate(-Math.toRadians(angle)); g2d.translate(-x, -y); } public static BufferedImage flipHorizontally(BufferedImage source) { BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); AffineTransform flip = AffineTransform.getScaleInstance(1, -1); flip.translate(0, -source.getHeight()); AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); op.filter(source, output); return output; } public static BufferedImage flipVertically(BufferedImage source) { BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); AffineTransform flip = AffineTransform.getScaleInstance(-1, 1); flip.translate(-source.getWidth(), 0); AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); op.filter(source, output); return output; } public Set getAltPoints() { return Collections.EMPTY_SET; } public final int getOffsetX() { return offsetX; } public void setOffsetX(int offsetX) { this.offsetX = offsetX; } public final int getOffsetY() { return offsetY; } public void setOffsetY(int offsetY) { this.offsetY = offsetY; } protected BufferedImage createImage() { return new BufferedImage(renderWidth, renderHeight, BufferedImage.TYPE_INT_RGB); } public int getCenterX() { if (tileX > 0) { return this.tileX; } else { return GRID; } } public int getCenterY() { if (tileY > 0) { return this.tileY; } else { return GRID; } } public boolean isDrawName() { return drawName; } public void setDrawName(boolean drawName) { this.drawName = drawName; } public boolean isScaleImage() { return model.isScaleImage(); } public void setScaleImage(boolean scaleImage) { Dimension d; if (scaleImage) { d = new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); } else { d = new Dimension(renderWidth, renderHeight); } setSize(d); setPreferredSize(d); model.setScaleImage(scaleImage); } public boolean isDrawCenterPoint() { return model.isShowCenter(); } public void setDrawCenterPoint(boolean drawCenterPoint) { model.setShowCenter(drawCenterPoint); } @Override public String toString() { return this.getClass().getSimpleName() + " {id: " + this.id + ", orientation: " + getOrientation() + ", direction: " + getDirection() + ", center: " + xyToString() + "}"; } public String xyToString() { return "(" + this.tileX + "," + this.tileY + ")"; } /** * The main route of the tile is horizontal * * @return true when main route goes from East to West or vv */ public boolean isHorizontal() { Orientation tileOrientation = model.getTileOrienation(); return (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) && TileType.CURVED != tileType; } /** * The main route of the tile is vertical * * @return true when main route goes from North to South or vv */ public boolean isVertical() { Orientation tileOrientation = model.getTileOrienation(); return (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) && TileType.CURVED != tileType; } public boolean isJunction() { return TileType.SWITCH == tileType || TileType.CROSS == tileType; } public boolean isBlock() { return TileType.BLOCK == tileType; } public boolean isDirectional() { return TileType.STRAIGHT_DIR == tileType; } /** * The main route of the tile is diagonal * * @return true when main route goes from North to East or West to South and vv */ public boolean isDiagonal() { return TileType.CURVED == tileType; } public boolean isCrossing() { return TileType.CROSSING == tileType; } public List getNeighbours() { return neighbours; } public void setNeighbours(List neighbours) { this.neighbours = neighbours; } public String getIdSuffix(Tile other) { return ""; } public Map getNeighborOrientations() { Map edgeOrientations = new HashMap<>(); Map neighborPoints = getNeighborPoints(); for (Orientation o : Orientation.values()) { edgeOrientations.put(neighborPoints.get(o), o); } return edgeOrientations; } public Map getEdgeOrientations() { Map edgeOrientations = new HashMap<>(); Map edgeConnections = getEdgePoints(); for (Orientation o : Orientation.values()) { edgeOrientations.put(edgeConnections.get(o), o); } return edgeOrientations; } public boolean isAdjacent(Tile other) { boolean adjacent = false; if (other != null) { Collection thisEdgePoints = getEdgePoints().values(); Collection otherEdgePoints = other.getEdgePoints().values(); for (Point p : thisEdgePoints) { adjacent = otherEdgePoints.contains(p); if (adjacent) { break; } } } return adjacent; } /** * When the tile has a specific direction a train may travel,
* then this method will indicate whether the other tile is in on the side where the arrow is pointing to. * * @param other A Tile * @return true where other is on the side of this tile where the arrow points to */ public boolean isArrowDirection(Tile other) { return true; } public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { return AccessoryValue.OFF; } public TileModel getModel() { return model; } public void setModel(TileModel newModel) { TileModel oldModel = getModel(); if (oldModel != null) { oldModel.removeChangeListener(changeListener); oldModel.removeActionListener(actionListener); changeListener = null; actionListener = null; } model = newModel; if (newModel != null) { changeListener = createChangeListener(); actionListener = createActionListener(); newModel.addChangeListener(changeListener); newModel.addActionListener(actionListener); } firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel); if (newModel != oldModel) { revalidate(); repaint(); } } // public TileUI getUI() { // return (TileUI) ui; // } // public void setUI(TileUI ui) { // super.setUI(ui); // } @Override public void updateUI() { } protected ChangeListener createChangeListener() { return getHandler(); } protected ActionListener createActionListener() { return getHandler(); } private Handler getHandler() { if (handler == null) { handler = new Handler(); } return handler; } class Handler implements ActionListener, ChangeListener, Serializable { @Override public void stateChanged(ChangeEvent e) { //Object source = e.getSource(); fireStateChanged(); repaint(); } @Override public void actionPerformed(ActionEvent event) { fireActionPerformed(event); } } protected void fireStateChanged() { Object[] listeners = listenerList.getListenerList(); //reverse order for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == ChangeListener.class) { // Lazily create the event: if (changeEvent == null) { changeEvent = new ChangeEvent(this); } ((ChangeListener) listeners[i + 1]).stateChanged(changeEvent); } } } protected void fireActionPerformed(ActionEvent event) { Object[] listeners = listenerList.getListenerList(); ActionEvent e = null; // reverse for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == ActionListener.class) { // Lazily create the event: if (e == null) { String actionCommand = event.getActionCommand(); //if(actionCommand == null) { // actionCommand = getActionCommand(); //} e = new ActionEvent(Tile.this, ActionEvent.ACTION_PERFORMED, actionCommand, event.getWhen(), event.getModifiers()); } ((ActionListener) listeners[i + 1]).actionPerformed(e); } } } public Rectangle getTileBounds() { if (model.isScaleImage()) { return new Rectangle(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); } else { return new Rectangle(tileX - renderWidth / 2, tileY - renderHeight / 2, renderWidth, renderHeight); } } @Override protected void paintComponent(Graphics g) { long started = System.currentTimeMillis(); Graphics2D g2 = (Graphics2D) g.create(); //Graphics2D g2 = (Graphics2D) g.create(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); drawTile(g2); g2.dispose(); g.drawImage(tileImage, 0, 0, null); long now = System.currentTimeMillis(); Logger.trace(id + " Duration: " + (now - started) + " ms. Cp: " + xyToString() + " O: " + model.getTileOrienation()); } } \ No newline at end of file +/* + * Copyright 2024 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.geom.AffineTransform; +import java.awt.geom.Ellipse2D; +import java.awt.image.AffineTransformOp; +import java.awt.image.BufferedImage; +import java.beans.PropertyChangeListener; +import java.io.Serializable; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.swing.JComponent; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import jcs.entities.AccessoryBean; +import jcs.entities.AccessoryBean.AccessoryValue; +import jcs.entities.AccessoryBean.SignalType; +import jcs.entities.BlockBean; +import jcs.entities.BlockBean.BlockState; +import jcs.entities.LocomotiveBean; +import jcs.entities.SensorBean; +import jcs.entities.TileBean; +import jcs.entities.TileBean.Direction; +import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean.TileType; +import jcs.ui.layout.LayoutUtil; +import static jcs.ui.layout.tiles.Block.BLOCK_HEIGHT; +import static jcs.ui.layout.tiles.Block.BLOCK_WIDTH; +import org.imgscalr.Scalr; +import org.imgscalr.Scalr.Method; +import org.imgscalr.Scalr.Mode; +import org.tinylog.Logger; + +/** + * Basic graphic element to display a track, turnout, etc on the screen.
+ * By default the drawing of a Tile is Horizontal from L to R or West to East.
+ * The default orientation is East. + * + *

+ * The default size of a Tile is 40 tileX 40 pixels.
+ * The center point of a Tile is stored and always snapped to the nearest grid point.
+ * The basic grid is 20x 20 pixels.
+ * + *

+ * A Tile can be rotated (always clockwise).
+ * Rotation will change the orientation from East -> South -> West -> North -> East.
+ * + *

+ * A Tile is rendered to a Buffered Image to speed up the display + */ +public abstract class Tile extends JComponent { //implements TileEventListener { //, ItemSelectable { + + public static final int GRID = 20; + public static final int DEFAULT_WIDTH = GRID * 2; + public static final int DEFAULT_HEIGHT = GRID * 2; + + static final int RENDER_GRID = GRID * 10; + static final int RENDER_WIDTH = RENDER_GRID * 2; + static final int RENDER_HEIGHT = RENDER_GRID * 2; + + public static final Color DEFAULT_BACKGROUND_COLOR = Color.white; + public static final Color DEFAULT_TRACK_COLOR = Color.lightGray; + public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.blue; + public static final Color DEFAULT_SELECTED_COLOR = Color.orange; + public static final Color DEFAULT_WARN_COLOR = Color.red; + + public static final String MODEL_CHANGED_PROPERTY = "model"; + public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled"; + + /** + * The data model that determines the button's state. + */ + protected TileModel model = null; + + protected String id; + protected Integer tileX; + protected Integer tileY; + + protected int renderWidth; + protected int renderHeight; + + //protected Orientation tileOrientation; + protected Direction tileDirection; + + protected TileType tileType; + protected String accessoryId; + protected String sensorId; + + protected AccessoryValue accessoryValue; + protected AccessoryValue routeValue; + + protected SignalType signalType; + protected AccessoryBean.SignalValue signalValue; + + protected TileBean tileBean; + protected AccessoryBean accessoryBean; + protected SensorBean sensorBean; + protected BlockBean blockBean; + + protected List neighbours; + + protected int offsetX = 0; + protected int offsetY = 0; + + protected int renderOffsetX = 0; + protected int renderOffsetY = 0; + + //protected Color selectedColor; + protected Color trackColor; + protected Color trackRouteColor; + protected Orientation incomingSide; + + protected Color backgroundColor; + protected boolean drawName = true; + + protected BufferedImage tileImage; + + protected PropertyChangeListener propertyChangeListener; + + protected ChangeListener changeListener = null; + protected ActionListener actionListener = null; + + protected transient ChangeEvent changeEvent; + + private Handler handler; + + protected Tile(TileType tileType, Orientation orientation, Point center, int width, int height) { + this(tileType, orientation, Direction.CENTER, center.x, center.y, width, height); + } + + protected Tile(TileType tileType, Orientation orientation, int x, int y, int width, int height) { + this(tileType, orientation, Direction.CENTER, x, y, width, height); + } + + protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { + this(tileType, orientation, direction, x, y, width, height, null, null); + } + + protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height, Color backgroundColor, Color selectedColor) { + this.tileType = tileType; + //this.tileOrientation = orientation; + //model.setTileOrienation(orientation); + this.tileDirection = direction; + this.tileX = x; + this.tileY = y; + + setLayout(null); + Dimension d = new Dimension(width, height); + setSize(d); + setPreferredSize(d); + + this.renderWidth = RENDER_WIDTH; + this.renderHeight = RENDER_HEIGHT; + + this.trackColor = DEFAULT_TRACK_COLOR; + this.backgroundColor = backgroundColor; + //this.selectedColor = selectedColor; + + if (this.backgroundColor == null) { + this.backgroundColor = DEFAULT_BACKGROUND_COLOR; + } +// if (this.selectedColor == null) { +// this.selectedColor = DEFAULT_SELECTED_COLOR; +// } + } + + protected Tile(TileBean tileBean) { + this(tileBean, tileWidth(tileBean.getOrientation(), tileBean.getTileType()), tileHeight(tileBean.getOrientation(), tileBean.getTileType())); + } + + protected Tile(TileBean tileBean, int width, int height) { + this.tileBean = tileBean; + //Quick properties + this.id = tileBean.getId(); + this.tileType = tileBean.getTileType(); + //this.tileOrientation = tileBean.getOrientation(); + //this.model.setTileOrienation(tileBean.getOrientation()); + this.tileDirection = tileBean.getDirection(); + this.tileX = tileBean.getX(); + this.tileY = tileBean.getY(); + + this.accessoryId = tileBean.getAccessoryId(); + this.accessoryBean = tileBean.getAccessoryBean(); + this.signalType = tileBean.getSignalType(); + + this.sensorId = tileBean.getSensorId(); + this.sensorBean = tileBean.getSensorBean(); + this.blockBean = tileBean.getBlockBean(); + + setLayout(null); + Dimension d = new Dimension(width, height); + setSize(d); + setPreferredSize(d); + + this.trackColor = DEFAULT_TRACK_COLOR; + this.backgroundColor = DEFAULT_BACKGROUND_COLOR; +// this.selectedColor = DEFAULT_SELECTED_COLOR; + this.renderWidth = RENDER_WIDTH; + this.renderHeight = RENDER_HEIGHT; + } + + protected static int tileWidth(Orientation orientation, TileType tileType) { + if (Orientation.EAST == orientation || Orientation.WEST == orientation) { + if (null == tileType) { + return DEFAULT_WIDTH; + } else { + return switch (tileType) { + case BLOCK -> + BLOCK_WIDTH; + case CROSS -> + DEFAULT_WIDTH * 2; + default -> + DEFAULT_WIDTH; + }; + } + } else { + return DEFAULT_WIDTH; + } + } + + protected static int tileHeight(Orientation orientation, TileType tileType) { + if (Orientation.EAST == orientation || Orientation.WEST == orientation) { + return DEFAULT_HEIGHT; + } else { + if (null == tileType) { + return DEFAULT_HEIGHT; + } else { + return switch (tileType) { + case BLOCK -> + BLOCK_HEIGHT; + case CROSS -> + DEFAULT_HEIGHT * 2; + default -> + DEFAULT_HEIGHT; + }; + } + } + } + + protected void populateModel() { + if (this.blockBean != null) { + this.model.setBlockState(this.blockBean.getBlockState()); + this.model.setLocomotive(this.blockBean.getLocomotive()); + this.model.setArrivalSuffix(this.blockBean.getArrivalSuffix()); + this.model.setLogicalDirection(LocomotiveBean.Direction.get(this.blockBean.getLogicalDirection())); + } + } + + public TileBean getTileBean() { + if (tileBean == null) { + tileBean = new TileBean(); + tileBean.setId(this.id); + tileBean.setX(this.tileX); + tileBean.setY(this.tileY); + tileBean.setTileType(this.tileType); + //tileBean.setTileOrientation(this.tileOrientation.getOrientation()); + tileBean.setTileOrientation(this.model.getTileOrienation().getOrientation()); + + tileBean.setTileDirection(this.tileDirection.getDirection()); + tileBean.setSignalType(this.signalType); + tileBean.setAccessoryId(this.accessoryId); + tileBean.setSensorId(this.sensorId); + tileBean.setAccessoryBean(this.accessoryBean); + tileBean.setSensorBean(this.sensorBean); + tileBean.setBlockBean(this.blockBean); + } + return tileBean; + } + + public boolean isSelected() { + return model.isSelected(); + } + + public void setSelected(boolean b) { + //boolean oldValue = isSelected(); + model.setSelected(b); + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public SignalType getSignalType() { + return signalType; + } + + public void setSignalType(SignalType signalType) { + this.signalType = signalType; + } + + public Integer getTileX() { + return tileX; + } + + public Integer getTileY() { + return tileY; + } + + public Point getCenter() { + return new Point(this.tileX, this.tileY); + } + + public void setCenter(Point center) { + tileX = center.x; + tileY = center.y; + if (tileBean != null) { + tileBean.setCenter(center); + } + } + + public Orientation getOrientation() { + //return tileOrientation; + return model.getTileOrienation(); + } + + public void setOrientation(Orientation orientation) { + //this.tileOrientation = orientation; + model.setTileOrienation(orientation); + if (tileBean != null) { + tileBean.setOrientation(orientation); + } + } + + public Direction getDirection() { + return tileDirection; + } + + public void setDirection(Direction direction) { + this.tileDirection = direction; + if (tileBean != null) { + tileBean.setDirection(direction); + } + } + + public String getAccessoryId() { + return accessoryId; + } + + public void setAccessoryId(String accessoryId) { + this.accessoryId = accessoryId; + if (tileBean != null) { + tileBean.setAccessoryId(accessoryId); + } + } + + public String getSensorId() { + return sensorId; + } + + public void setSensorId(String sensorId) { + this.sensorId = sensorId; + } + + public boolean isActive() { + return model.isSensorActive(); + } + + public void setActive(boolean active) { + model.setSensorActive(active); + } + + public BlockState getBlockState() { + return model.getBlockState(); + } + + public void setBlockState(BlockState blockState) { + if (blockBean != null) { + blockBean.setBlockState(blockState); + LocomotiveBean locomotive = model.getLocomotive(); + model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (blockState == BlockState.OCCUPIED || blockState == BlockState.INBOUND || blockState == BlockState.OUTBOUND)); + } + model.setBlockState(blockState); + } + + public String getDepartureSuffix() { + return model.getDepartureSuffix(); + } + + public void setDepartureSuffix(String suffix) { + if (blockBean != null) { + blockBean.setDepartureSuffix(suffix); + } + model.setDepartureSuffix(suffix); + } + + public boolean isReverseArrival() { + return model.isReverseArrival(); + } + + public void setReverseArrival(boolean reverseArrival) { + if (blockBean != null) { + blockBean.setReverseArrival(reverseArrival); + } + model.setReverseArrival(reverseArrival); + } + + public LocomotiveBean.Direction getLogicalDirection() { + return model.getLogicalDirection(); + } + + public void setLogicalDirection(LocomotiveBean.Direction logicalDirection) { + if (blockBean != null) { + blockBean.setLogicalDirection(logicalDirection.getDirection()); + } + model.setLogicalDirection(logicalDirection); + } + + public LocomotiveBean getLocomotive() { + return model.getLocomotive(); + } + + public void setLocomotive(LocomotiveBean locomotive) { + if (blockBean != null) { + blockBean.setLocomotive(locomotive); + model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (model.getBlockState() == BlockState.OCCUPIED || model.getBlockState() == BlockState.INBOUND || model.getBlockState() == BlockState.OUTBOUND)); + } + + model.setLocomotive(locomotive); + } + + public AccessoryBean getAccessoryBean() { + return accessoryBean; + } + + public void setAccessoryBean(AccessoryBean accessoryBean) { + this.accessoryBean = accessoryBean; + + if (accessoryBean != null) { + accessoryId = accessoryBean.getId(); + signalValue = accessoryBean.getSignalValue(); + signalType = SignalType.getSignalType(accessoryBean.getType()); + } else { + accessoryId = null; + signalType = SignalType.NONE; + signalValue = AccessoryBean.SignalValue.OFF; + } + } + + public AccessoryValue getAccessoryValue() { + if (this.accessoryValue == null) { + return AccessoryValue.OFF; + } else { + return accessoryValue; + } + } + + public void setAccessoryValue(AccessoryValue value) { + this.accessoryValue = value; + repaint(); + } + + public AccessoryValue getRouteValue() { + if (routeValue == null) { + return AccessoryValue.OFF; + } else { + return routeValue; + } + } + + public void setRouteValue(AccessoryValue value) { + this.routeValue = value; + repaint(); + } + + public AccessoryBean.SignalValue getSignalValue() { + return signalValue; + } + + public void setSignalValue(AccessoryBean.SignalValue signalValue) { + this.signalValue = signalValue; + repaint(); + } + + public SensorBean getSensorBean() { + return sensorBean; + } + + public void setSensorBean(SensorBean sensorBean) { + this.sensorBean = sensorBean; + } + + public BlockBean getBlockBean() { + return blockBean; + } + + public void setBlockBean(BlockBean blockBean) { + this.blockBean = blockBean; + } + + public void setRenderWidth(int renderWidth) { + this.renderWidth = renderWidth; + } + + public void setRenderHeight(int renderHeight) { + this.renderHeight = renderHeight; + } + + public int getRenderOffsetX() { + return renderOffsetX; + } + + public void setRenderOffsetX(int renderOffsetX) { + this.renderOffsetX = renderOffsetX; + } + + public int getRenderOffsetY() { + return renderOffsetY; + } + + public void setRenderOffsetY(int renderOffsetY) { + this.renderOffsetY = renderOffsetY; + } + + public TileBean.TileType getTileType() { + return this.tileType; + } + + public final void setTileType(TileType tileType) { + this.tileType = tileType; + } + + public Color getTrackColor() { + return trackColor; + } + + public final void setTrackColor(Color trackColor) { + this.trackColor = trackColor; + } + + public Color getTrackRouteColor() { + return trackRouteColor; + } + + public void setTrackRouteColor(Color trackRouteColor) { + this.trackRouteColor = trackRouteColor; + } + + public Color getSelectedColor() { + return model.getSelectedColor(); + } + + public void setSelectedColor(Color selectedColor) { + this.model.setSelectedColor(selectedColor); + } + + public Orientation getIncomingSide() { + return incomingSide; + } + + public void setIncomingSide(Orientation incomingSide) { + this.incomingSide = incomingSide; + } + + public Color getBackgroundColor() { + return backgroundColor; + } + + public void setBackgroundColor(Color backgroundColor) { + this.backgroundColor = backgroundColor; + } + + public boolean isDrawRoute() { + return model.isShowRoute(); + } + + public void setDrawRoute(boolean drawRoute) { + this.model.setShowRoute(drawRoute); + } + + public int getRenderWidth() { + return renderWidth; + } + + public int getRenderHeight() { + return renderHeight; + } + + abstract void renderTile(Graphics2D g2d); + + abstract void renderTileRoute(Graphics2D g2d); + + public abstract Map getNeighborPoints(); + + public abstract Map getEdgePoints(); + + //public abstract Set getAllPoints(); + //public abstract Set getAllPoints(Point center); + //public abstract Set getAltPoints(Point center); + Set getAltPoints(Point center) { + return Collections.EMPTY_SET; + } + + public Set getAllPoints() { + return getAllPoints(getCenter()); + } + + Set getAllPoints(Point center) { + Set aps = new HashSet<>(); + aps.add(center); + return aps; + } + + /** + * Draw the Tile + * + * @param g2d The graphics handle + */ + public void drawTile(Graphics2D g2d) { + // by default and image is rendered in the EAST orientation + Orientation tileOrientation = model.getTileOrienation(); + + BufferedImage bf = createImage(); + Graphics2D g2di = bf.createGraphics(); + + //Avoid errors + if (model.isShowRoute() && incomingSide == null) { + incomingSide = getOrientation(); + } + + if (model.isSelected()) { + g2di.setBackground(model.getSelectedColor()); + } else { + g2di.setBackground(backgroundColor); + } + + g2di.clearRect(0, 0, renderWidth, renderHeight); + int ox = 0, oy = 0; + + AffineTransform trans = new AffineTransform(); + switch (tileOrientation) { + case SOUTH -> { + trans.rotate(Math.PI / 2, renderWidth / 2, renderHeight / 2); + ox = (renderHeight - renderWidth) / 2; + oy = (renderWidth - renderHeight) / 2; + trans.translate(-ox, -oy); + } + case WEST -> { + trans.rotate(Math.PI, renderWidth / 2, renderHeight / 2); + trans.translate(ox, oy); + } + case NORTH -> { + trans.rotate(-Math.PI / 2, renderWidth / 2, renderHeight / 2); + ox = (renderHeight - renderWidth) / 2; + oy = (renderWidth - renderHeight) / 2; + trans.translate(-ox, -oy); + } + default -> { + trans.rotate(0.0, this.renderWidth / 2, this.renderHeight / 2); + trans.translate(ox, oy); + } + } + + //Logger.trace(tileOrientation.getOrientation() + " renderWidth: " + renderWidth + " renderHeight: " + renderHeight + " CP: (" + renderWidth / 2 + "," + renderHeight / 2 + ")"); + //Logger.trace(tileOrientation.getOrientation() + " ox: " + ox + " oy: " + oy); + g2di.setTransform(trans); + + renderTile(g2di); + + if (model.isShowRoute()) { + renderTileRoute(g2di); + } + + if (model.isShowCenter()) { + drawCenterPoint(g2di); + } + + // Scale the image back... + if (model.isScaleImage()) { + tileImage = Scalr.resize(bf, Method.AUTOMATIC, Mode.FIT_EXACT, getWidth(), getHeight(), Scalr.OP_ANTIALIAS); + } else { + tileImage = bf; + } + g2di.dispose(); + } + + public BufferedImage getTileImage() { + return tileImage; + } + + /** + * Render a tile image Always starts at (0,0) used the default width and height + * + * @param g2 the Graphic context + */ + public void drawName(Graphics2D g2) { + } + + protected void drawCenterPoint(Graphics2D g2d) { + drawCenterPoint(g2d, Color.magenta); + } + + protected void drawCenterPoint(Graphics2D g2, Color color) { + drawCenterPoint(g2, color, 60); + } + + protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { + double dX = (renderWidth / 2 - size / 2); + double dY = (renderHeight / 2 - size / 2); + + g2d.setColor(color); + g2d.fill(new Ellipse2D.Double(dX, dY, size, size)); + } + + /** + * Rotate the tile clockwise 90 deg + * + * @return the new Orientation + */ + public Orientation rotate() { + Orientation tileOrientation = model.getTileOrienation(); + switch (tileOrientation) { + case EAST -> + setOrientation(Orientation.SOUTH); + case SOUTH -> + setOrientation(Orientation.WEST); + case WEST -> + setOrientation(Orientation.NORTH); + default -> + setOrientation(Orientation.EAST); + } + return model.getTileOrienation(); + } + + public void flipHorizontal() { + Orientation tileOrientation = model.getTileOrienation(); + if (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) { + rotate(); + rotate(); + } + } + + public void flipVertical() { + Orientation tileOrientation = model.getTileOrienation(); + if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { + rotate(); + rotate(); + } + } + + @Override + public void move(int newX, int newY) { + Point cs = LayoutUtil.snapToGrid(newX, newY); + setCenter(cs); + } + + protected static void drawRotate(Graphics2D g2d, double x, double y, int angle, String text) { + g2d.translate((float) x, (float) y); + g2d.rotate(Math.toRadians(angle)); + g2d.drawString(text, 0, 0); + g2d.rotate(-Math.toRadians(angle)); + g2d.translate(-x, -y); + } + + public static BufferedImage flipHorizontally(BufferedImage source) { + BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); + + AffineTransform flip = AffineTransform.getScaleInstance(1, -1); + flip.translate(0, -source.getHeight()); + AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); + + op.filter(source, output); + + return output; + } + + public static BufferedImage flipVertically(BufferedImage source) { + BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); + + AffineTransform flip = AffineTransform.getScaleInstance(-1, 1); + flip.translate(-source.getWidth(), 0); + AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); + + op.filter(source, output); + + return output; + } + + public Set getAltPoints() { + return Collections.EMPTY_SET; + } + + public final int getOffsetX() { + return offsetX; + } + + public void setOffsetX(int offsetX) { + this.offsetX = offsetX; + } + + public final int getOffsetY() { + return offsetY; + } + + public void setOffsetY(int offsetY) { + this.offsetY = offsetY; + } + + protected BufferedImage createImage() { + return new BufferedImage(renderWidth, renderHeight, BufferedImage.TYPE_INT_RGB); + } + + public int getCenterX() { + if (tileX > 0) { + return this.tileX; + } else { + return GRID; + } + } + + public int getCenterY() { + if (tileY > 0) { + return this.tileY; + } else { + return GRID; + } + } + + public boolean isDrawName() { + return drawName; + } + + public void setDrawName(boolean drawName) { + this.drawName = drawName; + } + + public boolean isScaleImage() { + return model.isScaleImage(); + } + + public void setScaleImage(boolean scaleImage) { + Dimension d; + if (scaleImage) { + d = new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); + } else { + d = new Dimension(renderWidth, renderHeight); + } + + setSize(d); + setPreferredSize(d); + + model.setScaleImage(scaleImage); + } + + public boolean isDrawCenterPoint() { + return model.isShowCenter(); + } + + public void setDrawCenterPoint(boolean drawCenterPoint) { + model.setShowCenter(drawCenterPoint); + } + + @Override + public String toString() { + return this.getClass().getSimpleName() + + " {id: " + + this.id + + ", orientation: " + + getOrientation() + + ", direction: " + + getDirection() + + ", center: " + + xyToString() + + "}"; + } + + public String xyToString() { + return "(" + this.tileX + "," + this.tileY + ")"; + } + + /** + * The main route of the tile is horizontal + * + * @return true when main route goes from East to West or vv + */ + public boolean isHorizontal() { + Orientation tileOrientation = model.getTileOrienation(); + return (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) && TileType.CURVED != tileType; + } + + /** + * The main route of the tile is vertical + * + * @return true when main route goes from North to South or vv + */ + public boolean isVertical() { + Orientation tileOrientation = model.getTileOrienation(); + return (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) && TileType.CURVED != tileType; + } + + public boolean isJunction() { + return TileType.SWITCH == tileType || TileType.CROSS == tileType; + } + + public boolean isBlock() { + return TileType.BLOCK == tileType; + } + + public boolean isDirectional() { + return TileType.STRAIGHT_DIR == tileType; + } + + /** + * The main route of the tile is diagonal + * + * @return true when main route goes from North to East or West to South and vv + */ + public boolean isDiagonal() { + return TileType.CURVED == tileType; + } + + public boolean isCrossing() { + return TileType.CROSSING == tileType; + } + + public List getNeighbours() { + return neighbours; + } + + public void setNeighbours(List neighbours) { + this.neighbours = neighbours; + } + + public String getIdSuffix(Tile other) { + return ""; + } + + public Map getNeighborOrientations() { + Map edgeOrientations = new HashMap<>(); + + Map neighborPoints = getNeighborPoints(); + + for (Orientation o : Orientation.values()) { + edgeOrientations.put(neighborPoints.get(o), o); + } + return edgeOrientations; + } + + public Map getEdgeOrientations() { + Map edgeOrientations = new HashMap<>(); + + Map edgeConnections = getEdgePoints(); + + for (Orientation o : Orientation.values()) { + edgeOrientations.put(edgeConnections.get(o), o); + } + return edgeOrientations; + } + + public boolean isAdjacent(Tile other) { + boolean adjacent = false; + + if (other != null) { + Collection thisEdgePoints = getEdgePoints().values(); + Collection otherEdgePoints = other.getEdgePoints().values(); + + for (Point p : thisEdgePoints) { + adjacent = otherEdgePoints.contains(p); + if (adjacent) { + break; + } + } + } + + return adjacent; + } + + /** + * When the tile has a specific direction a train may travel,
+ * then this method will indicate whether the other tile is in on the side where the arrow is pointing to. + * + * @param other A Tile + * @return true where other is on the side of this tile where the arrow points to + */ + public boolean isArrowDirection(Tile other) { + return true; + } + + public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { + return AccessoryValue.OFF; + } + + public TileModel getModel() { + return model; + } + + public void setModel(TileModel newModel) { + TileModel oldModel = getModel(); + + if (oldModel != null) { + oldModel.removeChangeListener(changeListener); + oldModel.removeActionListener(actionListener); + changeListener = null; + actionListener = null; + } + + model = newModel; + + if (newModel != null) { + changeListener = createChangeListener(); + actionListener = createActionListener(); + + newModel.addChangeListener(changeListener); + newModel.addActionListener(actionListener); + } + + firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel); + if (newModel != oldModel) { + revalidate(); + repaint(); + } + } + +// public TileUI getUI() { +// return (TileUI) ui; +// } +// public void setUI(TileUI ui) { +// super.setUI(ui); +// } + @Override + public void updateUI() { + } + + protected ChangeListener createChangeListener() { + return getHandler(); + } + + protected ActionListener createActionListener() { + return getHandler(); + } + + private Handler getHandler() { + if (handler == null) { + handler = new Handler(); + } + return handler; + } + + class Handler implements ActionListener, ChangeListener, Serializable { + + @Override + public void stateChanged(ChangeEvent e) { + //Object source = e.getSource(); + + fireStateChanged(); + repaint(); + } + + @Override + public void actionPerformed(ActionEvent event) { + fireActionPerformed(event); + } + } + + protected void fireStateChanged() { + Object[] listeners = listenerList.getListenerList(); + //reverse order + for (int i = listeners.length - 2; i >= 0; i -= 2) { + if (listeners[i] == ChangeListener.class) { + // Lazily create the event: + if (changeEvent == null) { + changeEvent = new ChangeEvent(this); + } + ((ChangeListener) listeners[i + 1]).stateChanged(changeEvent); + } + } + } + + protected void fireActionPerformed(ActionEvent event) { + Object[] listeners = listenerList.getListenerList(); + ActionEvent e = null; + // reverse + for (int i = listeners.length - 2; i >= 0; i -= 2) { + if (listeners[i] == ActionListener.class) { + // Lazily create the event: + if (e == null) { + String actionCommand = event.getActionCommand(); + //if(actionCommand == null) { + // actionCommand = getActionCommand(); + //} + e = new ActionEvent(Tile.this, ActionEvent.ACTION_PERFORMED, actionCommand, event.getWhen(), event.getModifiers()); + } + ((ActionListener) listeners[i + 1]).actionPerformed(e); + } + } + } + + public Rectangle getTileBounds() { + if (model.isScaleImage()) { + return new Rectangle(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); + } else { + return new Rectangle(tileX - renderWidth / 2, tileY - renderHeight / 2, renderWidth, renderHeight); + } + } + + @Override + protected void paintComponent(Graphics g) { + long started = System.currentTimeMillis(); + + Graphics2D g2 = (Graphics2D) g.create(); + //Graphics2D g2 = (Graphics2D) g.create(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); + drawTile(g2); + g2.dispose(); + + g.drawImage(tileImage, 0, 0, null); + + long now = System.currentTimeMillis(); + Logger.trace(id + " Duration: " + (now - started) + " ms. Cp: " + xyToString() + " O: " + model.getTileOrienation()); + } + +} diff --git a/src/main/java/jcs/ui/layout/tiles/TileCache.java b/src/main/java/jcs/ui/layout/tiles/TileCache.java index 2716f298..3d32de97 100644 --- a/src/main/java/jcs/ui/layout/tiles/TileCache.java +++ b/src/main/java/jcs/ui/layout/tiles/TileCache.java @@ -1 +1,403 @@ -/* * Copyright 2025 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.Point; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import jcs.entities.AccessoryBean.AccessoryValue; import jcs.entities.AccessoryBean.SignalValue; import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.EAST; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; import static jcs.entities.TileBean.TileType.BLOCK; import static jcs.entities.TileBean.TileType.CROSS; import static jcs.entities.TileBean.TileType.SENSOR; import static jcs.entities.TileBean.TileType.SIGNAL; import jcs.persistence.PersistenceFactory; import jcs.ui.layout.events.TileEvent; import jcs.ui.layout.events.TileEventListener; import org.tinylog.Logger; /** * Factory object to create Tiles and cache tiles * * @author frans */ public class TileCache { //private static final Map tileEventListeners = new HashMap<>(); private static boolean showValues; static final Map tiles = new HashMap<>(); static final Map tileAltPoints = new HashMap<>(); static final Map points = new HashMap<>(); //static final Map altTiles = new HashMap<>(); private TileCache() { } @Deprecated public static void setShowValues(boolean showValues) { TileCache.showValues = showValues; for (Tile tile : tiles.values()) { TileType tileType = tile.getTileType(); switch (tileType) { case SWITCH -> { if (showValues && ((Switch) tile).getTileBean().getAccessoryBean() != null) { tile.setAccessoryValue(tile.getTileBean().getAccessoryBean().getAccessoryValue()); } else { tile.setAccessoryValue(AccessoryValue.OFF); } } case CROSS -> { if (showValues && ((Cross) tile).getTileBean().getAccessoryBean() != null) { tile.setAccessoryValue(tile.getTileBean().getAccessoryBean().getAccessoryValue()); } else { tile.setAccessoryValue(AccessoryValue.OFF); } } case SIGNAL -> { if (showValues && ((Signal) tile).getTileBean().getAccessoryBean() != null) { tile.setSignalValue(tile.getTileBean().getAccessoryBean().getSignalValue()); } else { tile.setSignalValue(SignalValue.OFF); } } case SENSOR -> { if (showValues && ((Sensor) tile).getTileBean().getSensorBean() != null) { tile.setActive(tile.getTileBean().getSensorBean().isActive()); } else { tile.setActive(false); } } case BLOCK -> { } } } } public static List loadTiles() { tileAltPoints.clear(); points.clear(); tiles.clear(); List tileBeans = PersistenceFactory.getService().getTileBeans(); for (TileBean tb : tileBeans) { Tile tile = TileFactory.createTile(tb, showValues); tiles.put(tile.getCenter(), tile); points.put(tile.getId(), tile.getCenter()); //Alternative point(s) to be able to find all points if (!tile.getAltPoints().isEmpty()) { Set alt = tile.getAltPoints(); for (Point ap : alt) { tileAltPoints.put(ap, tile); } } } Logger.trace("Loaded " + tiles.size() + " Tiles..."); return tiles.values().stream().collect(Collectors.toList()); } public static List getTiles() { return tiles.values().stream().collect(Collectors.toList()); } public static void addAndSaveTile(Tile tile) { tiles.put(tile.getCenter(), tile); points.put(tile.getId(), tile.getCenter()); //Alternative point(s) to be able to find all points if (!tile.getAltPoints().isEmpty()) { Set alt = tile.getAltPoints(); for (Point ap : alt) { tileAltPoints.put(ap, tile); } } saveTile(tile); Logger.trace("Added " + tile + " There are now " + tiles.size() + " tiles..."); } public static void saveTile(final Tile tile) { if (tile != null) { TileBean tb = tile.getTileBean(); PersistenceFactory.getService().persist(tb); } else { Logger.warn("Tile is null?"); } } public static void saveTiles() { for (Tile tile : tiles.values()) { saveTile(tile); } } public static void deleteTile(final Tile tile) { if (tile != null) { if (tiles.containsKey(tile.getCenter())) { Set rps = tile.getAltPoints(); //Also remove alt points for (Point ap : rps) { tileAltPoints.remove(ap); } points.remove(tile.getId()); tiles.remove(tile.getCenter()); TileBean tb = tile.getTileBean(); PersistenceFactory.getService().remove(tb); Logger.trace("Deleted " + tile.getId()); } else { Logger.warn("Tile " + tile.getId() + " not found in cache"); } } else { Logger.warn("Tile is null?"); } } public static Tile findTile(Point cp) { Tile result = tiles.get(cp); if (result == null) { result = tileAltPoints.get(cp); } return result; } public static Tile findTile(String id) { Point p = points.get(id); if (p != null) { return findTile(p); } else { return null; } } public static boolean canMoveTo(Tile tile, Point p) { //check if a tile exist with point p Logger.trace("Checking " + tile.id + " New Point (" + p.x + "," + p.y + ")"); if (tiles.containsKey(p) && !tile.getCenter().equals(p) && !tile.getAltPoints().contains(p)) { return false; } if (tileAltPoints.containsKey(p) && !tile.getAltPoints().contains(p)) { return false; } //Check with the tile new alt points if these are also free... Set altPoints = tile.getAltPoints(p); Logger.trace("Checking " + tile.id + " on " + altPoints.size() + " alt points..."); for (Point ap : altPoints) { Logger.trace("Checking " + tile.id + " New Alt Point (" + ap.x + "," + ap.y + ")"); if (tiles.containsKey(ap) && !tile.getCenter().equals(ap) && !tile.getAltPoints().contains(ap)) { return false; } if (tileAltPoints.containsKey(ap) && !tile.getAltPoints().contains(ap)) { return false; } } Logger.trace("Checking " + tile.id + " can move to (" + p.x + "," + p.y + ")"); return true; } public static void moveTo(Tile tile, Point p) { if (canMoveTo(tile, p)) { Logger.trace("Moving tile " + tile.getId() + " from " + tile.xyToString() + " to (" + p.x + "," + p.y + ")"); Set rps = tile.getAltPoints(); //remove alt points for (Point ap : rps) { tileAltPoints.remove(ap); } points.remove(tile.getId()); tiles.remove(tile.getCenter()); tile.setCenter(p); addAndSaveTile(tile); } else { Tile occ = findTile(p); Logger.trace("Can't Move tile " + tile.id + " from " + tile.xyToString() + " to (" + p.x + "," + p.y + ") Is occupied by " + occ.id); } } @Deprecated public static boolean checkTileOccupation(Tile tile) { Set tilePoints = tile.getAllPoints(); for (Point p : tilePoints) { if (tiles.containsKey(p) || tileAltPoints.containsKey(p)) { //The is a match, check if it is an other tile Tile mt = findTile(p); if (tile.getId().equals(mt.getId())) { //same tile continue } else { //Other tile so really occupied return true; } } } return false; } @Deprecated public static boolean containsPoint(Set points) { for (Point p : points) { return tiles.containsKey(p) || tileAltPoints.containsKey(p); } return false; } public static boolean containsPoint(Point point) { return tiles.containsKey(point) || tileAltPoints.containsKey(point); } @Deprecated public static Point checkAvailable(Point newPoint, Orientation orientation) { if (tiles.containsKey(newPoint)) { Tile et = tiles.get(newPoint); Logger.trace("@ " + newPoint + " is allready occcupied by: " + et + "..."); //Search for the nearest avalaible free point //first get the Center point of the tile which is occuping this slot // show warning! Point ecp = et.getCenter(); int w = et.getWidth(); int h = et.getHeight(); Point np; np = switch (orientation) { case EAST -> new Point(ecp.x + w, ecp.y); case WEST -> new Point(newPoint.x - w, ecp.y); case SOUTH -> new Point(ecp.x, newPoint.y + h); default -> new Point(ecp.x, newPoint.y - h); }; Logger.trace("Alternative CP: " + np); // recursive check return checkAvailable(np, orientation); } else { Logger.trace("@ " + newPoint + " is not yet used..."); return newPoint; } } public static Tile rotateTile(Tile tile) { if (!tiles.containsKey(tile.getCenter())) { Logger.warn("Tile " + tile.getId() + " NOT in cache!"); } //Remove the alternative or extra points... for (Point ep : tile.getAltPoints()) { tileAltPoints.remove(ep); } tile.rotate(); //update tiles.put(tile.getCenter(), tile); for (Point ep : tile.getAltPoints()) { tileAltPoints.put(ep, tile); } saveTile(tile); return tile; } public static Tile flipHorizontal(Tile tile) { return flipTile(tile, true); } public static Tile flipVertical(Tile tile) { return flipTile(tile, false); } private static Tile flipTile(Tile tile, boolean horizontal) { if (!tiles.containsKey(tile.getCenter())) { Logger.warn("Tile " + tile.getId() + " NOT in cache!"); } //Remove the alternative or extra points... for (Point ep : tile.getAltPoints()) { tileAltPoints.remove(ep); } if (horizontal) { tile.flipHorizontal(); } else { tile.flipVertical(); } //update tiles.put(tile.getCenter(), tile); for (Point ep : tile.getAltPoints()) { tileAltPoints.put(ep, tile); } saveTile(tile); return tile; } @Deprecated public static void addTileEventListener(TileEventListener listener) { String key = listener.getId(); //tileEventListeners.put(key, listener); } @Deprecated public static void removeTileEventListener(Tile tile) { if (tile instanceof TileEventListener tileEventListener) { removeTileEventListener(tileEventListener); } } static void removeTileEventListener(TileEventListener listener) { String key = listener.getId(); //tileEventListeners.remove(key, listener); } @Deprecated public static void fireTileEventListener(TileEvent tileEvent) { // String key = tileEvent.getTileId(); // TileEventListener listener = tileEventListeners.get(key); // if (listener != null) { // listener.onTileChange(tileEvent); // Logger.trace("Fire listener on tile " + key); // } else { // //Logger.trace("Tile " + key + " not available"); // } } @Deprecated public static void fireAllTileEventListeners(TileEvent tileEvent) { // for (TileEventListener listener : tileEventListeners.values()) { // listener.onTileChange(tileEvent); // } } } \ No newline at end of file +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles; + +import java.awt.Point; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collector; +import java.util.stream.Collectors; +import jcs.entities.AccessoryBean.AccessoryValue; +import jcs.entities.AccessoryBean.SignalValue; +import jcs.entities.TileBean; +import jcs.entities.TileBean.Orientation; +import static jcs.entities.TileBean.Orientation.EAST; +import static jcs.entities.TileBean.Orientation.SOUTH; +import static jcs.entities.TileBean.Orientation.WEST; +import jcs.entities.TileBean.TileType; +import static jcs.entities.TileBean.TileType.BLOCK; +import static jcs.entities.TileBean.TileType.CROSS; +import static jcs.entities.TileBean.TileType.SENSOR; +import static jcs.entities.TileBean.TileType.SIGNAL; +import jcs.persistence.PersistenceFactory; +import jcs.ui.layout.events.TileEvent; +import jcs.ui.layout.events.TileEventListener; +import org.tinylog.Logger; + +/** + * Factory object to create Tiles and cache tiles + * + * @author frans + */ +public class TileCache { + + //private static final Map tileEventListeners = new HashMap<>(); + private static boolean showValues; + + static final Map tiles = new HashMap<>(); + static final Map tileAltPoints = new HashMap<>(); + static final Map points = new HashMap<>(); + //static final Map altTiles = new HashMap<>(); + + private TileCache() { + } + + @Deprecated + public static void setShowValues(boolean showValues) { + TileCache.showValues = showValues; + + for (Tile tile : tiles.values()) { + TileType tileType = tile.getTileType(); + switch (tileType) { + case SWITCH -> { + if (showValues && ((Switch) tile).getTileBean().getAccessoryBean() != null) { + tile.setAccessoryValue(tile.getTileBean().getAccessoryBean().getAccessoryValue()); + } else { + tile.setAccessoryValue(AccessoryValue.OFF); + } + } + case CROSS -> { + if (showValues && ((Cross) tile).getTileBean().getAccessoryBean() != null) { + tile.setAccessoryValue(tile.getTileBean().getAccessoryBean().getAccessoryValue()); + } else { + tile.setAccessoryValue(AccessoryValue.OFF); + } + } + case SIGNAL -> { + if (showValues && ((Signal) tile).getTileBean().getAccessoryBean() != null) { + tile.setSignalValue(tile.getTileBean().getAccessoryBean().getSignalValue()); + } else { + tile.setSignalValue(SignalValue.OFF); + } + } + case SENSOR -> { + if (showValues && ((Sensor) tile).getTileBean().getSensorBean() != null) { + tile.setActive(tile.getTileBean().getSensorBean().isActive()); + } else { + tile.setActive(false); + } + } + case BLOCK -> { + } + } + } + } + + public static List loadTiles() { + tileAltPoints.clear(); + points.clear(); + tiles.clear(); + + List tileBeans = PersistenceFactory.getService().getTileBeans(); + + for (TileBean tb : tileBeans) { + Tile tile = TileFactory.createTile(tb, showValues); + tiles.put(tile.getCenter(), tile); + points.put(tile.getId(), tile.getCenter()); + //Alternative point(s) to be able to find all points + if (!tile.getAltPoints().isEmpty()) { + Set alt = tile.getAltPoints(); + for (Point ap : alt) { + tileAltPoints.put(ap, tile); + } + } + } + + Logger.trace("Loaded " + tiles.size() + " Tiles..."); + return tiles.values().stream().collect(Collectors.toList()); + } + + public static List getTiles() { + return tiles.values().stream().collect(Collectors.toList()); + } + + public static Tile addAndSaveTile(Tile tile) { + tiles.put(tile.getCenter(), tile); + points.put(tile.getId(), tile.getCenter()); + + //Alternative point(s) to be able to find all points + if (!tile.getAltPoints().isEmpty()) { + Set alt = tile.getAltPoints(); + for (Point ap : alt) { + tileAltPoints.put(ap, tile); + } + } + + saveTile(tile); + //Logger.trace("Added " + tile + " There are now " + tiles.size() + " tiles..."); + return tile; + } + + public static void saveTile(final Tile tile) { + if (tile != null) { + TileBean tb = tile.getTileBean(); + PersistenceFactory.getService().persist(tb); + } else { + Logger.warn("Tile is null?"); + } + } + + public static void saveTiles() { + for (Tile tile : tiles.values()) { + saveTile(tile); + } + } + + public static void deleteTile(final Tile tile) { + if (tile != null) { + if (tiles.containsKey(tile.getCenter())) { + Set rps = tile.getAltPoints(); + //Also remove alt points + for (Point ap : rps) { + tileAltPoints.remove(ap); + } + points.remove(tile.getId()); + tiles.remove(tile.getCenter()); + + TileBean tb = tile.getTileBean(); + PersistenceFactory.getService().remove(tb); + Logger.trace("Deleted " + tile.getId()); + } else { + Logger.warn("Tile " + tile.getId() + " not found in cache"); + } + } else { + Logger.warn("Tile is null?"); + } + } + + public static Tile findTile(Point cp) { + Tile result = tiles.get(cp); + if (result == null) { + result = tileAltPoints.get(cp); + } + return result; + } + + public static Tile findTile(String id) { + Point p = points.get(id); + if (p != null) { + return findTile(p); + } else { + return null; + } + } + + public static boolean canMoveTo(Tile tile, Point p) { + //check if a tile exist with point p + //Check if the cache contains a Cp of a tile on p + //Logger.trace("Checking " + tile.id + " New Point (" + p.x + "," + p.y + ")"); + if (tiles.containsKey(p) && !tile.getCenter().equals(p) && !tile.getAltPoints().contains(p)) { + return false; + } + //Check if the cache contains a Cp on any of the Alt point is case of a Block or Cross + if (tileAltPoints.containsKey(p) && !tile.getAltPoints().contains(p)) { + return false; + } + + //Check with the tile on the new Cp with the new alt points if that is also free... + Set altPoints = tile.getAltPoints(p); + for (Point ap : altPoints) { + if (tiles.containsKey(ap) && !tile.getCenter().equals(ap) && !tile.getAltPoints().contains(ap)) { + return false; + } + if (tileAltPoints.containsKey(ap) && !tile.getAltPoints().contains(ap)) { + return false; + } + } + //Logger.trace("Checked " + tile.id + " can move to (" + p.x + "," + p.y + ")"); + return true; + } + + public static void moveTo(Tile tile, Point p) { + if (canMoveTo(tile, p)) { + //Logger.trace("Moving " + tile.getId() + " from " + tile.xyToString() + " to (" + p.x + "," + p.y + ")"); + Set rps = tile.getAltPoints(); + //remove alt points + for (Point ap : rps) { + tileAltPoints.remove(ap); + } + points.remove(tile.getId()); + tiles.remove(tile.getCenter()); + + tile.setCenter(p); + Tile t = addAndSaveTile(tile); + //Logger.trace("Moved " + t.id + " to " + t.xyToString()); + } else { + Tile occ = findTile(p); + Logger.trace("Can't Move tile " + tile.id + " from " + tile.xyToString() + " to (" + p.x + "," + p.y + ") Is occupied by " + occ.id); + } + } + + @Deprecated + public static boolean checkTileOccupation(Tile tile) { + Set tilePoints = tile.getAllPoints(); + for (Point p : tilePoints) { + if (tiles.containsKey(p) || tileAltPoints.containsKey(p)) { + //The is a match, check if it is an other tile + Tile mt = findTile(p); + if (tile.getId().equals(mt.getId())) { + //same tile continue + } else { + //Other tile so really occupied + return true; + } + } + } + return false; + } + + @Deprecated + public static boolean containsPoint(Set points) { + for (Point p : points) { + return tiles.containsKey(p) || tileAltPoints.containsKey(p); + } + return false; + } + + public static boolean containsPoint(Point point) { + return tiles.containsKey(point) || tileAltPoints.containsKey(point); + } + + @Deprecated + public static Point checkAvailable(Point newPoint, Orientation orientation) { + if (tiles.containsKey(newPoint)) { + Tile et = tiles.get(newPoint); + Logger.trace("@ " + newPoint + " is allready occcupied by: " + et + "..."); + //Search for the nearest avalaible free point + //first get the Center point of the tile which is occuping this slot + // show warning! + Point ecp = et.getCenter(); + + int w = et.getWidth(); + int h = et.getHeight(); + + Point np; + np = switch (orientation) { + case EAST -> + new Point(ecp.x + w, ecp.y); + case WEST -> + new Point(newPoint.x - w, ecp.y); + case SOUTH -> + new Point(ecp.x, newPoint.y + h); + default -> + new Point(ecp.x, newPoint.y - h); + }; + + Logger.trace("Alternative CP: " + np); + // recursive check + return checkAvailable(np, orientation); + } else { + Logger.trace("@ " + newPoint + " is not yet used..."); + + return newPoint; + } + } + + public static Tile rotateTile(Tile tile) { + if (!tiles.containsKey(tile.getCenter())) { + Logger.warn("Tile " + tile.getId() + " NOT in cache!"); + } + + //Remove the alternative or extra points... + for (Point ep : tile.getAltPoints()) { + tileAltPoints.remove(ep); + } + + tile.rotate(); + + //update + tiles.put(tile.getCenter(), tile); + for (Point ep : tile.getAltPoints()) { + tileAltPoints.put(ep, tile); + } + + saveTile(tile); + return tile; + } + + public static Tile flipHorizontal(Tile tile) { + return flipTile(tile, true); + } + + public static Tile flipVertical(Tile tile) { + return flipTile(tile, false); + } + + private static Tile flipTile(Tile tile, boolean horizontal) { + if (!tiles.containsKey(tile.getCenter())) { + Logger.warn("Tile " + tile.getId() + " NOT in cache!"); + } + + //Remove the alternative or extra points... + for (Point ep : tile.getAltPoints()) { + tileAltPoints.remove(ep); + } + + if (horizontal) { + tile.flipHorizontal(); + } else { + tile.flipVertical(); + } + //update + tiles.put(tile.getCenter(), tile); + for (Point ep : tile.getAltPoints()) { + tileAltPoints.put(ep, tile); + } + + saveTile(tile); + return tile; + } + + @Deprecated + public static void addTileEventListener(TileEventListener listener) { + String key = listener.getId(); + //tileEventListeners.put(key, listener); + } + + @Deprecated + public static void removeTileEventListener(Tile tile) { + if (tile instanceof TileEventListener tileEventListener) { + removeTileEventListener(tileEventListener); + } + } + + static void removeTileEventListener(TileEventListener listener) { + String key = listener.getId(); + //tileEventListeners.remove(key, listener); + } + + @Deprecated + public static void fireTileEventListener(TileEvent tileEvent) { +// String key = tileEvent.getTileId(); +// TileEventListener listener = tileEventListeners.get(key); +// if (listener != null) { +// listener.onTileChange(tileEvent); +// Logger.trace("Fire listener on tile " + key); +// } else { +// //Logger.trace("Tile " + key + " not available"); +// } + } + + @Deprecated + public static void fireAllTileEventListeners(TileEvent tileEvent) { +// for (TileEventListener listener : tileEventListeners.values()) { +// listener.onTileChange(tileEvent); +// } + } + +} From 0b4cff3e702cd61987227f0c1f91dda70d6a58fb Mon Sep 17 00:00:00 2001 From: Frans Jacobs <41232225+fransjacobs@users.noreply.github.com> Date: Thu, 30 Jan 2025 19:15:03 +0100 Subject: [PATCH 13/70] Multiple fixes --- .../commandStation/autopilot/AutoPilot.java | 4 +- .../autopilot/state/Dispatcher.java | 6 +- .../esu/ecos/EsuEcosCommandStationImpl.java | 19 +- src/main/java/jcs/ui/VNCPanel.java | 38 +-- src/main/java/jcs/ui/layout/LayoutCanvas.java | 36 ++- src/main/java/jcs/ui/layout/LayoutPanel.form | 94 +----- src/main/java/jcs/ui/layout/LayoutPanel.java | 112 +------ src/main/java/jcs/ui/layout/RoutesDialog.java | 43 ++- .../ui/layout/dialogs/BlockControlDialog.java | 3 +- src/main/java/jcs/ui/layout/tiles/Tile.java | 8 +- .../java/jcs/ui/layout/tiles/TileCache.java | 295 ++++++++---------- .../jcs/ui/layout/tiles/BlockTileTester.java | 8 +- .../jcs/ui/layout/tiles/CrossTileTester.java | 16 +- .../ui/layout/tiles/CrossingTileTester.java | 8 +- .../jcs/ui/layout/tiles/CurvedTileTester.java | 8 +- .../jcs/ui/layout/tiles/EndTileTester.java | 8 +- .../jcs/ui/layout/tiles/SensorTileTester.java | 8 +- .../jcs/ui/layout/tiles/SignalTileTester.java | 8 +- .../tiles/StraightDirectionTileTester.java | 8 +- .../ui/layout/tiles/StraightTileTester.java | 8 +- .../jcs/ui/layout/tiles/SwitchTileTester.java | 16 +- .../jcs/ui/layout/tiles/TileTesterFrame.java | 2 +- 22 files changed, 278 insertions(+), 478 deletions(-) diff --git a/src/main/java/jcs/commandStation/autopilot/AutoPilot.java b/src/main/java/jcs/commandStation/autopilot/AutoPilot.java index 23ce3b8b..d31d1637 100644 --- a/src/main/java/jcs/commandStation/autopilot/AutoPilot.java +++ b/src/main/java/jcs/commandStation/autopilot/AutoPilot.java @@ -322,7 +322,7 @@ public static void resetStates() { } PersistenceFactory.getService().persist(block); TileEvent tileEvent = new TileEvent(block); - TileCache.fireTileEventListener(tileEvent); + //TileCache.fireTileEventListener(tileEvent); } JCS.getJcsCommandStation().switchPower(true); @@ -403,7 +403,7 @@ private static void handleGhost(SensorEvent event) { JCS.getJcsCommandStation().switchPower(false); TileEvent tileEvent = new TileEvent(block); - TileCache.fireTileEventListener(tileEvent); + //TileCache.fireTileEventListener(tileEvent); } else { if (block.getLocomotiveId() != null) { //keep state as is diff --git a/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java b/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java index 70801fc9..715e54dc 100644 --- a/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java +++ b/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java @@ -327,14 +327,14 @@ public static void resetRoute(RouteBean route) { for (RouteElementBean re : routeElements) { String tileId = re.getTileId(); TileEvent tileEvent = new TileEvent(tileId, false); - TileCache.fireTileEventListener(tileEvent); + //TileCache.fireTileEventListener(tileEvent); } } void showBlockState(BlockBean blockBean) { Logger.trace("Show block " + blockBean); TileEvent tileEvent = new TileEvent(blockBean); - TileCache.fireTileEventListener(tileEvent); + //TileCache.fireTileEventListener(tileEvent); } void showRoute(RouteBean routeBean, Color routeColor) { @@ -351,7 +351,7 @@ void showRoute(RouteBean routeBean, Color routeColor) { } else { tileEvent = new TileEvent(tileId, true, incomingSide, routeColor); } - TileCache.fireTileEventListener(tileEvent); + //TileCache.fireTileEventListener(tileEvent); } } diff --git a/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java b/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java index 2e2b5766..53ec814a 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java @@ -56,6 +56,7 @@ import static jcs.entities.AccessoryBean.AccessoryValue.GREEN; import static jcs.entities.AccessoryBean.AccessoryValue.RED; import jcs.entities.LocomotiveBean; +import jcs.util.NetworkUtil; import org.tinylog.Logger; public class EsuEcosCommandStationImpl extends AbstractController implements DecoderController, AccessoryController, FeedbackController { @@ -98,8 +99,6 @@ public void setVirtual(boolean flag) { connect(); } - - @Override public boolean connect() { if (!connected) { @@ -122,10 +121,17 @@ public boolean connect() { if (commandStationBean.getIpAddress() != null) { EcosConnectionFactory.writeLastUsedIpAddressProperty(commandStationBean.getIpAddress()); } else { - //try to discover the ECoS - InetAddress ecosAddr = EcosConnectionFactory.discoverEcos(); - String ip = ecosAddr.getHostAddress(); + + String ip; + if (!virtual) { + //try to discover the ECoS + InetAddress ecosAddr = EcosConnectionFactory.discoverEcos(); + ip = ecosAddr.getHostAddress(); + } else { + ip = NetworkUtil.getIPv4HostAddress().getHostAddress(); + } commandStationBean.setIpAddress(ip); + EcosConnectionFactory.writeLastUsedIpAddressProperty(commandStationBean.getIpAddress()); canConnect = ip != null; if (!canConnect) { @@ -231,10 +237,9 @@ private void initFeedbackManager() { for (int i = 0; i < feedbackManager.getSize(); i++) { int moduleId = i + FeedbackManager.S88_OFFSET; reply = connection.sendMessage(EcosMessageFactory.getFeedbackModuleInfo(moduleId)); - + //TODO: Start of day... //feedbackManager.update(reply); - connection.sendMessage(EcosMessageFactory.subscribeFeedbackModule(moduleId)); //Logger.trace("r: "+reply.getResponse()); } diff --git a/src/main/java/jcs/ui/VNCPanel.java b/src/main/java/jcs/ui/VNCPanel.java index bf69b6c6..c3ba8bc1 100644 --- a/src/main/java/jcs/ui/VNCPanel.java +++ b/src/main/java/jcs/ui/VNCPanel.java @@ -42,6 +42,7 @@ import javax.swing.JPanel; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; +import jcs.JCS; import jcs.commandStation.esu.ecos.net.EcosConnectionFactory; import org.tinylog.Logger; @@ -69,25 +70,25 @@ public VNCPanel() { } private void initVnc() { - addDrawingSurface(); - //clipboardMonitor.start(); - initialiseVernacularClient(); - - - String host; - InetAddress ia = EcosConnectionFactory.discoverEcos(); - //InetAddress ia = CSConnectionFactory.discoverCs(); - - if (ia != null) { - host = ia.getHostAddress(); - } else { - Logger.warn("Use a default host ip....."); - host = "192.168.1.110"; + if (JCS.getJcsCommandStation() != null) { + if (!JCS.getJcsCommandStation().getCommandStationBean().isVirtual()) { + addDrawingSurface(); + //clipboardMonitor.start(); + initialiseVernacularClient(); + String host = JCS.getJcsCommandStation().getCommandStationInfo().getHostname(); + + //InetAddress ia = EcosConnectionFactory.discoverEcos(); + //InetAddress ia = CSConnectionFactory.discoverCs(); + //if (ia != null) { + // host = ia.getHostAddress(); + //} else { + // Logger.warn("Use a default host ip....."); + // host = "192.168.1.110"; + //} + int port = DEFAULT_VNC_PORT; + this.connect(host, port); } - - int port = DEFAULT_VNC_PORT; - this.connect(host, port); - + } } private void addDrawingSurface() { @@ -415,7 +416,6 @@ public void windowClosing(java.awt.event.WindowEvent e) { // // int port = DEFAULT_VNC_PORT; // vncPanel.connect(host, port); - testFrame.pack(); testFrame.setLocationRelativeTo(null); testFrame.setVisible(true); diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.java b/src/main/java/jcs/ui/layout/LayoutCanvas.java index 15011e12..bc89dd21 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.java +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.java @@ -91,10 +91,14 @@ public enum Mode { CONTROL } + static final int LINE_GRID = 0; + static final int DOT_GRID = 1; + + private int gridType = LINE_GRID; + private boolean readonly; private Mode mode; private boolean drawGrid = true; - private boolean lineGrid = true; private Orientation orientation; private Direction direction; @@ -133,24 +137,23 @@ public LayoutCanvas(boolean readonly) { private void postInit() { routesDialog = new RoutesDialog(getParentFrame(), false, this, this.readonly); - lineGrid = "true".equals(System.getProperty("draw.linegrid", "true")); } @Override public void paint(Graphics g) { - long started = System.currentTimeMillis(); + //long started = System.currentTimeMillis(); super.paint(g); if (drawGrid) { - if (lineGrid) { + if (this.gridType == LINE_GRID) { paintLineGrid(g); } else { paintDotGrid(g); } } - long now = System.currentTimeMillis(); - Logger.trace("Duration: " + (now - started) + " ms."); + //long now = System.currentTimeMillis(); + //Logger.trace("Duration: " + (now - started) + " ms."); } @Override @@ -214,8 +217,18 @@ void setMode(LayoutCanvas.Mode mode) { } void setDrawGrid(boolean flag) { - this.drawGrid = flag; - this.repaint(); + if (flag) { + switch (gridType) { + case LINE_GRID -> + gridType = DOT_GRID; + case DOT_GRID -> + gridType = LINE_GRID; + default -> + gridType = LINE_GRID; + } + } + drawGrid = flag; + repaint(); } void setTileType(TileBean.TileType tileType) { @@ -250,10 +263,11 @@ private void loadTiles() { for (Tile tile : tiles) { add(tile); - tile.setDrawCenterPoint(!readonly); + boolean showCenter = "true".equalsIgnoreCase(System.getProperty("tile.show.center", "false")); + if (showCenter) { + tile.setDrawCenterPoint(showCenter); + } } - - repaint(); } private void mouseMoveAction(MouseEvent evt) { diff --git a/src/main/java/jcs/ui/layout/LayoutPanel.form b/src/main/java/jcs/ui/layout/LayoutPanel.form index 1386e2e4..158b41a2 100755 --- a/src/main/java/jcs/ui/layout/LayoutPanel.form +++ b/src/main/java/jcs/ui/layout/LayoutPanel.form @@ -181,29 +181,6 @@ - - - - - - - - - - - - - - - - - - - - - - - @@ -227,29 +204,6 @@ - - - - - - - - - - - - - - - - - - - - - - - @@ -458,7 +412,7 @@ - + @@ -845,29 +799,6 @@ - - - - - - - - - - - - - - - - - - - - - - - @@ -914,29 +845,6 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/main/java/jcs/ui/layout/LayoutPanel.java b/src/main/java/jcs/ui/layout/LayoutPanel.java index 909a4fd1..df6383c0 100755 --- a/src/main/java/jcs/ui/layout/LayoutPanel.java +++ b/src/main/java/jcs/ui/layout/LayoutPanel.java @@ -73,17 +73,10 @@ private void postInit() { if (readonly) { this.canvas.setDrawGrid(!readonly); - this.saveBtn.setEnabled(!readonly); - this.saveBtn.setVisible(!readonly); - this.toolBar.remove(this.saveBtn); - this.loadBtn.setEnabled(!readonly); this.loadBtn.setVisible(!readonly); this.toolBar.remove(this.loadBtn); - this.repaintBtn.setEnabled(readonly); - this.repaintBtn.setVisible(readonly); - this.routeBtn.setEnabled(readonly); this.routeBtn.setVisible(readonly); @@ -136,18 +129,12 @@ private void postInit() { this.crossingBtn.setEnabled(!readonly); this.crossingBtn.setVisible(!readonly); - this.moveBtn.setEnabled(!readonly); - this.moveBtn.setVisible(!readonly); - this.flipVerticalBtn.setEnabled(!readonly); this.flipVerticalBtn.setVisible(!readonly); this.flipHorizontalBtn.setEnabled(!readonly); this.flipHorizontalBtn.setVisible(!readonly); - this.rotateBtn.setEnabled(!readonly); - this.rotateBtn.setVisible(!readonly); - //Todo Remove the Autopilot related things from this panel //this.autoPilotBtn.setEnabled(readonly && JCS.getJcsCommandStation().isPowerOn()); // this.autoPilotBtn.setEnabled(readonly); @@ -157,15 +144,6 @@ private void postInit() { // this.startAllLocomotivesBtn.setEnabled(readonly && this.autoPilotBtn.isSelected()); // this.startAllLocomotivesBtn.setVisible(readonly); } else { - if ("true".equals(System.getProperty("batch.tile.persist", "true"))) { - this.saveBtn.setEnabled(true); - this.saveBtn.setVisible(true); - } else { - this.saveBtn.setEnabled(false); - this.saveBtn.setVisible(false); - this.toolBar.remove(this.saveBtn); - } - // this.toolBar.remove(this.autoPilotBtn); // this.autoPilotBtn.setEnabled(readonly); // this.autoPilotBtn.setVisible(readonly); @@ -194,7 +172,6 @@ private void postInit() { // void saveLayout() { // this.canvas.saveLayout(); // } - public void loadLayout() { this.canvas.loadLayoutInBackground(); } @@ -223,9 +200,7 @@ private void initComponents() { tileBtnGroup = new ButtonGroup(); topPanel = new JPanel(); toolBar = new JToolBar(); - saveBtn = new JButton(); loadBtn = new JButton(); - repaintBtn = new JButton(); routeBtn = new JButton(); autoPilotBtn = new JToggleButton(); startAllLocomotivesBtn = new JToggleButton(); @@ -250,10 +225,8 @@ private void initComponents() { endTrackBtn = new JToggleButton(); crossingBtn = new JToggleButton(); filler4 = new Box.Filler(new Dimension(20, 0), new Dimension(20, 0), new Dimension(20, 32767)); - moveBtn = new JButton(); flipVerticalBtn = new JButton(); flipHorizontalBtn = new JButton(); - rotateBtn = new JButton(); canvasScrollPane = new JScrollPane(); canvas = new LayoutCanvas(this.readonly); @@ -370,21 +343,6 @@ public void componentShown(ComponentEvent evt) { toolBar.setName(""); // NOI18N toolBar.setPreferredSize(new Dimension(1100, 42)); - saveBtn.setIcon(new ImageIcon(getClass().getResource("/media/save-24.png"))); // NOI18N - saveBtn.setToolTipText("Save"); - saveBtn.setFocusable(false); - saveBtn.setHorizontalTextPosition(SwingConstants.CENTER); - saveBtn.setMaximumSize(new Dimension(40, 40)); - saveBtn.setMinimumSize(new Dimension(40, 40)); - saveBtn.setPreferredSize(new Dimension(40, 40)); - saveBtn.setVerticalTextPosition(SwingConstants.BOTTOM); - saveBtn.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent evt) { - saveBtnActionPerformed(evt); - } - }); - toolBar.add(saveBtn); - loadBtn.setIcon(new ImageIcon(getClass().getResource("/media/load-24.png"))); // NOI18N loadBtn.setToolTipText("Load"); loadBtn.setFocusable(false); @@ -400,21 +358,6 @@ public void actionPerformed(ActionEvent evt) { }); toolBar.add(loadBtn); - repaintBtn.setIcon(new ImageIcon(getClass().getResource("/media/CS2-3-Sync.png"))); // NOI18N - repaintBtn.setToolTipText("Repaint"); - repaintBtn.setFocusable(false); - repaintBtn.setHorizontalTextPosition(SwingConstants.CENTER); - repaintBtn.setMaximumSize(new Dimension(40, 40)); - repaintBtn.setMinimumSize(new Dimension(38, 38)); - repaintBtn.setPreferredSize(new Dimension(38, 38)); - repaintBtn.setVerticalTextPosition(SwingConstants.BOTTOM); - repaintBtn.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent evt) { - repaintBtnActionPerformed(evt); - } - }); - toolBar.add(repaintBtn); - routeBtn.setIcon(new ImageIcon(getClass().getResource("/media/river-black.png"))); // NOI18N routeBtn.setToolTipText("Route"); routeBtn.setFocusable(false); @@ -529,7 +472,7 @@ public void actionPerformed(ActionEvent evt) { gridBtn.setIcon(new ImageIcon(getClass().getResource("/media/grid-2-24.png"))); // NOI18N gridBtn.setSelected(true); - gridBtn.setToolTipText("Grid"); + gridBtn.setToolTipText("Show Grid"); gridBtn.setHorizontalTextPosition(SwingConstants.CENTER); gridBtn.setSelectedIcon(new ImageIcon(getClass().getResource("/media/grid-dot-24.png"))); // NOI18N gridBtn.setVerticalTextPosition(SwingConstants.BOTTOM); @@ -742,21 +685,6 @@ public void actionPerformed(ActionEvent evt) { toolBar.add(crossingBtn); toolBar.add(filler4); - moveBtn.setIcon(new ImageIcon(getClass().getResource("/media/drag-24.png"))); // NOI18N - moveBtn.setToolTipText("Move"); - moveBtn.setFocusable(false); - moveBtn.setHorizontalTextPosition(SwingConstants.CENTER); - moveBtn.setMaximumSize(new Dimension(40, 40)); - moveBtn.setMinimumSize(new Dimension(38, 38)); - moveBtn.setPreferredSize(new Dimension(38, 38)); - moveBtn.setVerticalTextPosition(SwingConstants.BOTTOM); - moveBtn.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent evt) { - moveBtnActionPerformed(evt); - } - }); - toolBar.add(moveBtn); - flipVerticalBtn.setIcon(new ImageIcon(getClass().getResource("/media/flip-vertical-24.png"))); // NOI18N flipVerticalBtn.setToolTipText("Flip Vertical"); flipVerticalBtn.setFocusable(false); @@ -787,21 +715,6 @@ public void actionPerformed(ActionEvent evt) { }); toolBar.add(flipHorizontalBtn); - rotateBtn.setIcon(new ImageIcon(getClass().getResource("/media/rotate2-24.png"))); // NOI18N - rotateBtn.setToolTipText("Rotate"); - rotateBtn.setFocusable(false); - rotateBtn.setHorizontalTextPosition(SwingConstants.CENTER); - rotateBtn.setMaximumSize(new Dimension(40, 40)); - rotateBtn.setMinimumSize(new Dimension(38, 38)); - rotateBtn.setPreferredSize(new Dimension(38, 38)); - rotateBtn.setVerticalTextPosition(SwingConstants.BOTTOM); - rotateBtn.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent evt) { - rotateBtnActionPerformed(evt); - } - }); - toolBar.add(rotateBtn); - topPanel.add(toolBar); add(topPanel, BorderLayout.NORTH); @@ -881,10 +794,6 @@ private void propertiesMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_pro // editSelectedTileProperties(); }//GEN-LAST:event_propertiesMIActionPerformed - private void saveBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_saveBtnActionPerformed - //this.canvas.saveLayout(); - }//GEN-LAST:event_saveBtnActionPerformed - private void loadBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_loadBtnActionPerformed this.loadLayout(); }//GEN-LAST:event_loadBtnActionPerformed @@ -902,10 +811,6 @@ private void deleteBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_delete //this.canvas.removeTiles(); }//GEN-LAST:event_deleteBtnActionPerformed - private void repaintBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_repaintBtnActionPerformed - this.canvas.repaint(); - }//GEN-LAST:event_repaintBtnActionPerformed - private void straightBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_straightBtnActionPerformed setTileType(TileBean.TileType.STRAIGHT); }//GEN-LAST:event_straightBtnActionPerformed @@ -918,10 +823,6 @@ private void blockBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_blockBt setTileType(TileBean.TileType.BLOCK); }//GEN-LAST:event_blockBtnActionPerformed - private void rotateBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_rotateBtnActionPerformed - this.canvas.rotateSelectedTile(); - }//GEN-LAST:event_rotateBtnActionPerformed - private void flipHorizontalBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_flipHorizontalBtnActionPerformed this.canvas.flipSelectedTileHorizontal(); }//GEN-LAST:event_flipHorizontalBtnActionPerformed @@ -930,10 +831,6 @@ private void flipVerticalBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_ this.canvas.flipSelectedTileVertical(); }//GEN-LAST:event_flipVerticalBtnActionPerformed - private void moveBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_moveBtnActionPerformed - setMode(LayoutCanvas.Mode.MOVE); - }//GEN-LAST:event_moveBtnActionPerformed - private void rightSwitchBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_rightSwitchBtnActionPerformed this.setTileType(TileBean.TileType.SWITCH); this.setDirection(Direction.RIGHT); @@ -953,8 +850,7 @@ private void sensorBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_sensor }//GEN-LAST:event_sensorBtnActionPerformed private void gridBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_gridBtnActionPerformed - this.canvas.setDrawGrid(this.gridBtn.isSelected()); - this.canvas.repaint(); + this.canvas.setDrawGrid(this.gridBtn.isSelected()); }//GEN-LAST:event_gridBtnActionPerformed private void formComponentResized(ComponentEvent evt) {//GEN-FIRST:event_formComponentResized @@ -1117,18 +1013,14 @@ public void onPowerChange(PowerEvent event) { private JMenuItem leftMI; private JToggleButton leftSwitchBtn; private JButton loadBtn; - private JButton moveBtn; private JMenuItem moveMI; private JPopupMenu operationsPM; private JMenuItem propertiesMI; - private JButton repaintBtn; private JButton resetAutopilotBtn; private JMenuItem rightMI; private JToggleButton rightSwitchBtn; - private JButton rotateBtn; private JMenuItem rotateMI; private JButton routeBtn; - private JButton saveBtn; private JButton selectBtn; private JToggleButton sensorBtn; private JToggleButton signalBtn; diff --git a/src/main/java/jcs/ui/layout/RoutesDialog.java b/src/main/java/jcs/ui/layout/RoutesDialog.java index 6f564d26..12cf89a2 100644 --- a/src/main/java/jcs/ui/layout/RoutesDialog.java +++ b/src/main/java/jcs/ui/layout/RoutesDialog.java @@ -33,7 +33,7 @@ import jcs.entities.RouteElementBean; import jcs.entities.TileBean.Orientation; import jcs.persistence.PersistenceFactory; -import jcs.ui.layout.events.TileEvent; +import jcs.ui.layout.tiles.Tile; import org.tinylog.Logger; /** @@ -74,16 +74,16 @@ public RoutesDialog(java.awt.Frame parent, boolean modal, LayoutCanvas layoutCan this.setIconImage(new ImageIcon(iconUrl).getImage()); } - if (this.readonly) { - this.routeBtn.setEnabled(!readonly); - this.routeBtn.setVisible(!readonly); + if (readonly) { + routeBtn.setEnabled(!readonly); + routeBtn.setVisible(!readonly); - this.deleteRoutesBtn.setEnabled(!readonly); - this.deleteRoutesBtn.setVisible(!readonly); + deleteRoutesBtn.setEnabled(!readonly); + deleteRoutesBtn.setVisible(!readonly); } - if (this.defaultRouteColor == null) { - this.defaultRouteColor = Color.darkGray; + if (defaultRouteColor == null) { + defaultRouteColor = Tile.DEFAULT_ROUTE_TRACK_COLOR; } } @@ -119,8 +119,16 @@ private void setSelectedRoute(RouteBean route) { private void resetRoute(List routeElements) { for (RouteElementBean re : routeElements) { String tileId = re.getTileId(); - TileEvent tileEvent = new TileEvent(tileId, false); - TileCache.fireTileEventListener(tileEvent); + Tile tile = TileCache.findTile(tileId); + + if (tile.isBlock()) { + tile.setBlockState(BlockState.FREE); + } + if (tile.isJunction()) { + tile.setRouteValue(AccessoryBean.AccessoryValue.OFF); + } + + tile.setShowRoute(false); } } @@ -131,21 +139,22 @@ private void showRoute(RouteBean routeBean) { String tileId = re.getTileId(); Orientation incomingSide = re.getIncomingOrientation(); - TileEvent tileEvent; + Tile tile = TileCache.findTile(tileId); + tile.setIncomingSide(incomingSide); + tile.setTrackRouteColor(defaultRouteColor); + if (re.isTurnout()) { AccessoryBean.AccessoryValue routeState = re.getAccessoryValue(); - tileEvent = new TileEvent(tileId, true, incomingSide, routeState); + tile.setRouteValue(routeState); } else if (re.isBlock()) { if (re.getTileId().equals(routeBean.getFromTileId())) { //departure block - tileEvent = new TileEvent(tileId, true, BlockState.OUTBOUND); + tile.setBlockState(BlockState.OUTBOUND); } else { - tileEvent = new TileEvent(tileId, true, BlockState.INBOUND); + tile.setBlockState(BlockState.INBOUND); } - } else { - tileEvent = new TileEvent(tileId, true, incomingSide); } - TileCache.fireTileEventListener(tileEvent); + tile.setShowRoute(true); } } diff --git a/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java b/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java index b5881650..3ea13750 100644 --- a/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java +++ b/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java @@ -24,7 +24,6 @@ import jcs.entities.BlockBean; import jcs.entities.LocomotiveBean; import jcs.persistence.PersistenceFactory; -import jcs.ui.layout.tiles.TileCache; import jcs.ui.layout.events.TileEvent; import jcs.ui.layout.tiles.Block; import org.tinylog.Logger; @@ -422,7 +421,7 @@ private void saveExitBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-F } TileEvent tileEvent = new TileEvent(bb); //TileFactory.fireTileEventListener(tileEvent); - TileCache.fireTileEventListener(tileEvent); + //TileCache.fireTileEventListener(tileEvent); } diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java index 07127650..44b3636a 100755 --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -87,8 +87,8 @@ public abstract class Tile extends JComponent { //implements TileEventListener { public static final Color DEFAULT_BACKGROUND_COLOR = Color.white; public static final Color DEFAULT_TRACK_COLOR = Color.lightGray; - public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.blue; - public static final Color DEFAULT_SELECTED_COLOR = Color.orange; + public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.darkGray; + public static final Color DEFAULT_SELECTED_COLOR = Color.yellow; public static final Color DEFAULT_WARN_COLOR = Color.red; public static final String MODEL_CHANGED_PROPERTY = "model"; @@ -590,11 +590,11 @@ public void setBackgroundColor(Color backgroundColor) { this.backgroundColor = backgroundColor; } - public boolean isDrawRoute() { + public boolean isShowRoute() { return model.isShowRoute(); } - public void setDrawRoute(boolean drawRoute) { + public void setShowRoute(boolean drawRoute) { this.model.setShowRoute(drawRoute); } diff --git a/src/main/java/jcs/ui/layout/tiles/TileCache.java b/src/main/java/jcs/ui/layout/tiles/TileCache.java index 3d32de97..a2f9d7c5 100644 --- a/src/main/java/jcs/ui/layout/tiles/TileCache.java +++ b/src/main/java/jcs/ui/layout/tiles/TileCache.java @@ -20,23 +20,9 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.stream.Collector; import java.util.stream.Collectors; -import jcs.entities.AccessoryBean.AccessoryValue; -import jcs.entities.AccessoryBean.SignalValue; import jcs.entities.TileBean; -import jcs.entities.TileBean.Orientation; -import static jcs.entities.TileBean.Orientation.EAST; -import static jcs.entities.TileBean.Orientation.SOUTH; -import static jcs.entities.TileBean.Orientation.WEST; -import jcs.entities.TileBean.TileType; -import static jcs.entities.TileBean.TileType.BLOCK; -import static jcs.entities.TileBean.TileType.CROSS; -import static jcs.entities.TileBean.TileType.SENSOR; -import static jcs.entities.TileBean.TileType.SIGNAL; import jcs.persistence.PersistenceFactory; -import jcs.ui.layout.events.TileEvent; -import jcs.ui.layout.events.TileEventListener; import org.tinylog.Logger; /** @@ -46,58 +32,54 @@ */ public class TileCache { - //private static final Map tileEventListeners = new HashMap<>(); - private static boolean showValues; - + //private static boolean showValues; static final Map tiles = new HashMap<>(); static final Map tileAltPoints = new HashMap<>(); static final Map points = new HashMap<>(); - //static final Map altTiles = new HashMap<>(); private TileCache() { } - @Deprecated - public static void setShowValues(boolean showValues) { - TileCache.showValues = showValues; - - for (Tile tile : tiles.values()) { - TileType tileType = tile.getTileType(); - switch (tileType) { - case SWITCH -> { - if (showValues && ((Switch) tile).getTileBean().getAccessoryBean() != null) { - tile.setAccessoryValue(tile.getTileBean().getAccessoryBean().getAccessoryValue()); - } else { - tile.setAccessoryValue(AccessoryValue.OFF); - } - } - case CROSS -> { - if (showValues && ((Cross) tile).getTileBean().getAccessoryBean() != null) { - tile.setAccessoryValue(tile.getTileBean().getAccessoryBean().getAccessoryValue()); - } else { - tile.setAccessoryValue(AccessoryValue.OFF); - } - } - case SIGNAL -> { - if (showValues && ((Signal) tile).getTileBean().getAccessoryBean() != null) { - tile.setSignalValue(tile.getTileBean().getAccessoryBean().getSignalValue()); - } else { - tile.setSignalValue(SignalValue.OFF); - } - } - case SENSOR -> { - if (showValues && ((Sensor) tile).getTileBean().getSensorBean() != null) { - tile.setActive(tile.getTileBean().getSensorBean().isActive()); - } else { - tile.setActive(false); - } - } - case BLOCK -> { - } - } - } - } - +// @Deprecated +// public static void setShowValues(boolean showValues) { +// TileCache.showValues = showValues; +// +// for (Tile tile : tiles.values()) { +// TileType tileType = tile.getTileType(); +// switch (tileType) { +// case SWITCH -> { +// if (showValues && ((Switch) tile).getTileBean().getAccessoryBean() != null) { +// tile.setAccessoryValue(tile.getTileBean().getAccessoryBean().getAccessoryValue()); +// } else { +// tile.setAccessoryValue(AccessoryValue.OFF); +// } +// } +// case CROSS -> { +// if (showValues && ((Cross) tile).getTileBean().getAccessoryBean() != null) { +// tile.setAccessoryValue(tile.getTileBean().getAccessoryBean().getAccessoryValue()); +// } else { +// tile.setAccessoryValue(AccessoryValue.OFF); +// } +// } +// case SIGNAL -> { +// if (showValues && ((Signal) tile).getTileBean().getAccessoryBean() != null) { +// tile.setSignalValue(tile.getTileBean().getAccessoryBean().getSignalValue()); +// } else { +// tile.setSignalValue(SignalValue.OFF); +// } +// } +// case SENSOR -> { +// if (showValues && ((Sensor) tile).getTileBean().getSensorBean() != null) { +// tile.setActive(tile.getTileBean().getSensorBean().isActive()); +// } else { +// tile.setActive(false); +// } +// } +// case BLOCK -> { +// } +// } +// } +// } public static List loadTiles() { tileAltPoints.clear(); points.clear(); @@ -106,7 +88,7 @@ public static List loadTiles() { List tileBeans = PersistenceFactory.getService().getTileBeans(); for (TileBean tb : tileBeans) { - Tile tile = TileFactory.createTile(tb, showValues); + Tile tile = TileFactory.createTile(tb, false); tiles.put(tile.getCenter(), tile); points.put(tile.getId(), tile.getCenter()); //Alternative point(s) to be able to find all points @@ -243,71 +225,67 @@ public static void moveTo(Tile tile, Point p) { } } - @Deprecated - public static boolean checkTileOccupation(Tile tile) { - Set tilePoints = tile.getAllPoints(); - for (Point p : tilePoints) { - if (tiles.containsKey(p) || tileAltPoints.containsKey(p)) { - //The is a match, check if it is an other tile - Tile mt = findTile(p); - if (tile.getId().equals(mt.getId())) { - //same tile continue - } else { - //Other tile so really occupied - return true; - } - } - } - return false; - } - - @Deprecated - public static boolean containsPoint(Set points) { - for (Point p : points) { - return tiles.containsKey(p) || tileAltPoints.containsKey(p); - } - return false; - } - - public static boolean containsPoint(Point point) { - return tiles.containsKey(point) || tileAltPoints.containsKey(point); - } - - @Deprecated - public static Point checkAvailable(Point newPoint, Orientation orientation) { - if (tiles.containsKey(newPoint)) { - Tile et = tiles.get(newPoint); - Logger.trace("@ " + newPoint + " is allready occcupied by: " + et + "..."); - //Search for the nearest avalaible free point - //first get the Center point of the tile which is occuping this slot - // show warning! - Point ecp = et.getCenter(); - - int w = et.getWidth(); - int h = et.getHeight(); - - Point np; - np = switch (orientation) { - case EAST -> - new Point(ecp.x + w, ecp.y); - case WEST -> - new Point(newPoint.x - w, ecp.y); - case SOUTH -> - new Point(ecp.x, newPoint.y + h); - default -> - new Point(ecp.x, newPoint.y - h); - }; - - Logger.trace("Alternative CP: " + np); - // recursive check - return checkAvailable(np, orientation); - } else { - Logger.trace("@ " + newPoint + " is not yet used..."); - - return newPoint; - } - } - +// @Deprecated +// public static boolean checkTileOccupation(Tile tile) { +// Set tilePoints = tile.getAllPoints(); +// for (Point p : tilePoints) { +// if (tiles.containsKey(p) || tileAltPoints.containsKey(p)) { +// //The is a match, check if it is an other tile +// Tile mt = findTile(p); +// if (tile.getId().equals(mt.getId())) { +// //same tile continue +// } else { +// //Other tile so really occupied +// return true; +// } +// } +// } +// return false; +// } +// @Deprecated +// public static boolean containsPoint(Set points) { +// for (Point p : points) { +// return tiles.containsKey(p) || tileAltPoints.containsKey(p); +// } +// return false; +// } +// public static boolean containsPoint(Point point) { +// return tiles.containsKey(point) || tileAltPoints.containsKey(point); +// } +// @Deprecated +// public static Point checkAvailable(Point newPoint, Orientation orientation) { +// if (tiles.containsKey(newPoint)) { +// Tile et = tiles.get(newPoint); +// Logger.trace("@ " + newPoint + " is allready occcupied by: " + et + "..."); +// //Search for the nearest avalaible free point +// //first get the Center point of the tile which is occuping this slot +// // show warning! +// Point ecp = et.getCenter(); +// +// int w = et.getWidth(); +// int h = et.getHeight(); +// +// Point np; +// np = switch (orientation) { +// case EAST -> +// new Point(ecp.x + w, ecp.y); +// case WEST -> +// new Point(newPoint.x - w, ecp.y); +// case SOUTH -> +// new Point(ecp.x, newPoint.y + h); +// default -> +// new Point(ecp.x, newPoint.y - h); +// }; +// +// Logger.trace("Alternative CP: " + np); +// // recursive check +// return checkAvailable(np, orientation); +// } else { +// Logger.trace("@ " + newPoint + " is not yet used..."); +// +// return newPoint; +// } +// } public static Tile rotateTile(Tile tile) { if (!tiles.containsKey(tile.getCenter())) { Logger.warn("Tile " + tile.getId() + " NOT in cache!"); @@ -363,41 +341,36 @@ private static Tile flipTile(Tile tile, boolean horizontal) { return tile; } - @Deprecated - public static void addTileEventListener(TileEventListener listener) { - String key = listener.getId(); - //tileEventListeners.put(key, listener); - } - - @Deprecated - public static void removeTileEventListener(Tile tile) { - if (tile instanceof TileEventListener tileEventListener) { - removeTileEventListener(tileEventListener); - } - } - - static void removeTileEventListener(TileEventListener listener) { - String key = listener.getId(); - //tileEventListeners.remove(key, listener); - } - - @Deprecated - public static void fireTileEventListener(TileEvent tileEvent) { -// String key = tileEvent.getTileId(); -// TileEventListener listener = tileEventListeners.get(key); -// if (listener != null) { -// listener.onTileChange(tileEvent); -// Logger.trace("Fire listener on tile " + key); -// } else { -// //Logger.trace("Tile " + key + " not available"); +// @Deprecated +// public static void addTileEventListener(TileEventListener listener) { +// String key = listener.getId(); +// //tileEventListeners.put(key, listener); +// } +// @Deprecated +// public static void removeTileEventListener(Tile tile) { +// if (tile instanceof TileEventListener tileEventListener) { +// removeTileEventListener(tileEventListener); // } - } - - @Deprecated - public static void fireAllTileEventListeners(TileEvent tileEvent) { -// for (TileEventListener listener : tileEventListeners.values()) { -// listener.onTileChange(tileEvent); -// } - } - +// } +// static void removeTileEventListener(TileEventListener listener) { +// String key = listener.getId(); +// //tileEventListeners.remove(key, listener); +// } +// @Deprecated +// public static void fireTileEventListener(TileEvent tileEvent) { +//// String key = tileEvent.getTileId(); +//// TileEventListener listener = tileEventListeners.get(key); +//// if (listener != null) { +//// listener.onTileChange(tileEvent); +//// Logger.trace("Fire listener on tile " + key); +//// } else { +//// //Logger.trace("Tile " + key + " not available"); +//// } +// } +// @Deprecated +// public static void fireAllTileEventListeners(TileEvent tileEvent) { +//// for (TileEventListener listener : tileEventListeners.values()) { +//// listener.onTileChange(tileEvent); +//// } +// } } diff --git a/src/test/java/jcs/ui/layout/tiles/BlockTileTester.java b/src/test/java/jcs/ui/layout/tiles/BlockTileTester.java index d50b4f9f..620fef4b 100644 --- a/src/test/java/jcs/ui/layout/tiles/BlockTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/BlockTileTester.java @@ -261,19 +261,19 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed Logger.trace(blockNorth.id + "..."); - blockNorth.setDrawRoute(this.northTileBtn.isSelected()); + blockNorth.setShowRoute(this.northTileBtn.isSelected()); }//GEN-LAST:event_northTileBtnActionPerformed private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed - blockEast.setDrawRoute(this.eastTileBtn.isSelected()); + blockEast.setShowRoute(this.eastTileBtn.isSelected()); }//GEN-LAST:event_eastTileBtnActionPerformed private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed - blockWest.setDrawRoute(this.westTileBtn.isSelected()); + blockWest.setShowRoute(this.westTileBtn.isSelected()); }//GEN-LAST:event_westTileBtnActionPerformed private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed - blockSouth.setDrawRoute(this.southTileBtn.isSelected()); + blockSouth.setShowRoute(this.southTileBtn.isSelected()); }//GEN-LAST:event_southTileBtnActionPerformed private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed diff --git a/src/test/java/jcs/ui/layout/tiles/CrossTileTester.java b/src/test/java/jcs/ui/layout/tiles/CrossTileTester.java index 308066e9..7a15ae65 100644 --- a/src/test/java/jcs/ui/layout/tiles/CrossTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/CrossTileTester.java @@ -218,23 +218,23 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed Logger.trace(crossNorthR.id + "..."); - this.crossNorthR.setDrawRoute(this.northTileBtn.isSelected()); - this.crossNorthL.setDrawRoute(this.northTileBtn.isSelected()); + this.crossNorthR.setShowRoute(this.northTileBtn.isSelected()); + this.crossNorthL.setShowRoute(this.northTileBtn.isSelected()); }//GEN-LAST:event_northTileBtnActionPerformed private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed - this.crossEastR.setDrawRoute(this.eastTileBtn.isSelected()); - this.crossEastL.setDrawRoute(this.eastTileBtn.isSelected()); + this.crossEastR.setShowRoute(this.eastTileBtn.isSelected()); + this.crossEastL.setShowRoute(this.eastTileBtn.isSelected()); }//GEN-LAST:event_eastTileBtnActionPerformed private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed - this.crossWestR.setDrawRoute(this.westTileBtn.isSelected()); - this.crossWestL.setDrawRoute(this.westTileBtn.isSelected()); + this.crossWestR.setShowRoute(this.westTileBtn.isSelected()); + this.crossWestL.setShowRoute(this.westTileBtn.isSelected()); }//GEN-LAST:event_westTileBtnActionPerformed private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed - this.crossSouthR.setDrawRoute(this.southTileBtn.isSelected()); - this.crossSouthL.setDrawRoute(this.southTileBtn.isSelected()); + this.crossSouthR.setShowRoute(this.southTileBtn.isSelected()); + this.crossSouthL.setShowRoute(this.southTileBtn.isSelected()); }//GEN-LAST:event_southTileBtnActionPerformed private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed diff --git a/src/test/java/jcs/ui/layout/tiles/CrossingTileTester.java b/src/test/java/jcs/ui/layout/tiles/CrossingTileTester.java index 04773a8d..11ee9511 100644 --- a/src/test/java/jcs/ui/layout/tiles/CrossingTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/CrossingTileTester.java @@ -179,19 +179,19 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed Logger.trace(trackNorth.id + "..."); - this.trackNorth.setDrawRoute(this.northTileBtn.isSelected()); + this.trackNorth.setShowRoute(this.northTileBtn.isSelected()); }//GEN-LAST:event_northTileBtnActionPerformed private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed - this.trackEast.setDrawRoute(this.eastTileBtn.isSelected()); + this.trackEast.setShowRoute(this.eastTileBtn.isSelected()); }//GEN-LAST:event_eastTileBtnActionPerformed private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed - this.trackWest.setDrawRoute(this.westTileBtn.isSelected()); + this.trackWest.setShowRoute(this.westTileBtn.isSelected()); }//GEN-LAST:event_westTileBtnActionPerformed private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed - this.trackSouth.setDrawRoute(this.southTileBtn.isSelected()); + this.trackSouth.setShowRoute(this.southTileBtn.isSelected()); }//GEN-LAST:event_southTileBtnActionPerformed private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed diff --git a/src/test/java/jcs/ui/layout/tiles/CurvedTileTester.java b/src/test/java/jcs/ui/layout/tiles/CurvedTileTester.java index a2dfcc60..32b0b76f 100644 --- a/src/test/java/jcs/ui/layout/tiles/CurvedTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/CurvedTileTester.java @@ -177,19 +177,19 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed Logger.trace(trackNorth.id + "..."); - this.trackNorth.setDrawRoute(this.northTileBtn.isSelected()); + this.trackNorth.setShowRoute(this.northTileBtn.isSelected()); }//GEN-LAST:event_northTileBtnActionPerformed private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed - this.trackEast.setDrawRoute(this.eastTileBtn.isSelected()); + this.trackEast.setShowRoute(this.eastTileBtn.isSelected()); }//GEN-LAST:event_eastTileBtnActionPerformed private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed - this.trackWest.setDrawRoute(this.westTileBtn.isSelected()); + this.trackWest.setShowRoute(this.westTileBtn.isSelected()); }//GEN-LAST:event_westTileBtnActionPerformed private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed - this.trackSouth.setDrawRoute(this.southTileBtn.isSelected()); + this.trackSouth.setShowRoute(this.southTileBtn.isSelected()); }//GEN-LAST:event_southTileBtnActionPerformed private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed diff --git a/src/test/java/jcs/ui/layout/tiles/EndTileTester.java b/src/test/java/jcs/ui/layout/tiles/EndTileTester.java index 1a9400ed..15b3ed3c 100644 --- a/src/test/java/jcs/ui/layout/tiles/EndTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/EndTileTester.java @@ -177,19 +177,19 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed Logger.trace(trackNorth.id + "..."); - this.trackNorth.setDrawRoute(this.northTileBtn.isSelected()); + this.trackNorth.setShowRoute(this.northTileBtn.isSelected()); }//GEN-LAST:event_northTileBtnActionPerformed private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed - this.trackEast.setDrawRoute(this.eastTileBtn.isSelected()); + this.trackEast.setShowRoute(this.eastTileBtn.isSelected()); }//GEN-LAST:event_eastTileBtnActionPerformed private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed - this.trackWest.setDrawRoute(this.westTileBtn.isSelected()); + this.trackWest.setShowRoute(this.westTileBtn.isSelected()); }//GEN-LAST:event_westTileBtnActionPerformed private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed - this.trackSouth.setDrawRoute(this.southTileBtn.isSelected()); + this.trackSouth.setShowRoute(this.southTileBtn.isSelected()); }//GEN-LAST:event_southTileBtnActionPerformed private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed diff --git a/src/test/java/jcs/ui/layout/tiles/SensorTileTester.java b/src/test/java/jcs/ui/layout/tiles/SensorTileTester.java index 4e016041..d0987c8d 100644 --- a/src/test/java/jcs/ui/layout/tiles/SensorTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/SensorTileTester.java @@ -185,19 +185,19 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed Logger.trace(sensorNorth.id + "..."); - sensorNorth.setDrawRoute(this.northTileBtn.isSelected()); + sensorNorth.setShowRoute(this.northTileBtn.isSelected()); }//GEN-LAST:event_northTileBtnActionPerformed private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed - sensorEast.setDrawRoute(this.eastTileBtn.isSelected()); + sensorEast.setShowRoute(this.eastTileBtn.isSelected()); }//GEN-LAST:event_eastTileBtnActionPerformed private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed - sensorWest.setDrawRoute(this.westTileBtn.isSelected()); + sensorWest.setShowRoute(this.westTileBtn.isSelected()); }//GEN-LAST:event_westTileBtnActionPerformed private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed - sensorSouth.setDrawRoute(this.southTileBtn.isSelected()); + sensorSouth.setShowRoute(this.southTileBtn.isSelected()); }//GEN-LAST:event_southTileBtnActionPerformed private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed diff --git a/src/test/java/jcs/ui/layout/tiles/SignalTileTester.java b/src/test/java/jcs/ui/layout/tiles/SignalTileTester.java index c06af5b8..a1e62419 100644 --- a/src/test/java/jcs/ui/layout/tiles/SignalTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/SignalTileTester.java @@ -271,19 +271,19 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed Logger.trace(signal2North.id + "..."); - this.signal2North.setDrawRoute(this.northTileBtn.isSelected()); + this.signal2North.setShowRoute(this.northTileBtn.isSelected()); }//GEN-LAST:event_northTileBtnActionPerformed private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed - this.signal2East.setDrawRoute(this.eastTileBtn.isSelected()); + this.signal2East.setShowRoute(this.eastTileBtn.isSelected()); }//GEN-LAST:event_eastTileBtnActionPerformed private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed - this.signal2West.setDrawRoute(this.westTileBtn.isSelected()); + this.signal2West.setShowRoute(this.westTileBtn.isSelected()); }//GEN-LAST:event_westTileBtnActionPerformed private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed - this.signal2South.setDrawRoute(this.southTileBtn.isSelected()); + this.signal2South.setShowRoute(this.southTileBtn.isSelected()); }//GEN-LAST:event_southTileBtnActionPerformed private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed diff --git a/src/test/java/jcs/ui/layout/tiles/StraightDirectionTileTester.java b/src/test/java/jcs/ui/layout/tiles/StraightDirectionTileTester.java index 138f32c2..30ad25da 100644 --- a/src/test/java/jcs/ui/layout/tiles/StraightDirectionTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/StraightDirectionTileTester.java @@ -173,19 +173,19 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed Logger.trace(trackNorth.id + "..."); - this.trackNorth.setDrawRoute(this.northTileBtn.isSelected()); + this.trackNorth.setShowRoute(this.northTileBtn.isSelected()); }//GEN-LAST:event_northTileBtnActionPerformed private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed - this.trackEast.setDrawRoute(this.eastTileBtn.isSelected()); + this.trackEast.setShowRoute(this.eastTileBtn.isSelected()); }//GEN-LAST:event_eastTileBtnActionPerformed private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed - this.trackWest.setDrawRoute(this.westTileBtn.isSelected()); + this.trackWest.setShowRoute(this.westTileBtn.isSelected()); }//GEN-LAST:event_westTileBtnActionPerformed private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed - this.trackSouth.setDrawRoute(this.southTileBtn.isSelected()); + this.trackSouth.setShowRoute(this.southTileBtn.isSelected()); }//GEN-LAST:event_southTileBtnActionPerformed private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed diff --git a/src/test/java/jcs/ui/layout/tiles/StraightTileTester.java b/src/test/java/jcs/ui/layout/tiles/StraightTileTester.java index df3bcbdd..ea006b17 100644 --- a/src/test/java/jcs/ui/layout/tiles/StraightTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/StraightTileTester.java @@ -172,19 +172,19 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed Logger.trace(trackNorth.id + "..."); - this.trackNorth.setDrawRoute(this.northTileBtn.isSelected()); + this.trackNorth.setShowRoute(this.northTileBtn.isSelected()); }//GEN-LAST:event_northTileBtnActionPerformed private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed - this.trackEast.setDrawRoute(this.eastTileBtn.isSelected()); + this.trackEast.setShowRoute(this.eastTileBtn.isSelected()); }//GEN-LAST:event_eastTileBtnActionPerformed private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed - this.trackWest.setDrawRoute(this.westTileBtn.isSelected()); + this.trackWest.setShowRoute(this.westTileBtn.isSelected()); }//GEN-LAST:event_westTileBtnActionPerformed private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed - this.trackSouth.setDrawRoute(this.southTileBtn.isSelected()); + this.trackSouth.setShowRoute(this.southTileBtn.isSelected()); }//GEN-LAST:event_southTileBtnActionPerformed private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed diff --git a/src/test/java/jcs/ui/layout/tiles/SwitchTileTester.java b/src/test/java/jcs/ui/layout/tiles/SwitchTileTester.java index 4b615a58..584d6df0 100644 --- a/src/test/java/jcs/ui/layout/tiles/SwitchTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/SwitchTileTester.java @@ -226,23 +226,23 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed Logger.trace(switchNorthR.id + "..."); - this.switchNorthR.setDrawRoute(this.northTileBtn.isSelected()); - this.switchNorthL.setDrawRoute(this.northTileBtn.isSelected()); + this.switchNorthR.setShowRoute(this.northTileBtn.isSelected()); + this.switchNorthL.setShowRoute(this.northTileBtn.isSelected()); }//GEN-LAST:event_northTileBtnActionPerformed private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed - this.switchEastR.setDrawRoute(this.eastTileBtn.isSelected()); - this.switchEastL.setDrawRoute(this.eastTileBtn.isSelected()); + this.switchEastR.setShowRoute(this.eastTileBtn.isSelected()); + this.switchEastL.setShowRoute(this.eastTileBtn.isSelected()); }//GEN-LAST:event_eastTileBtnActionPerformed private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed - this.switchWestR.setDrawRoute(this.westTileBtn.isSelected()); - this.switchWestL.setDrawRoute(this.westTileBtn.isSelected()); + this.switchWestR.setShowRoute(this.westTileBtn.isSelected()); + this.switchWestL.setShowRoute(this.westTileBtn.isSelected()); }//GEN-LAST:event_westTileBtnActionPerformed private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed - this.switchSouthR.setDrawRoute(this.southTileBtn.isSelected()); - this.switchSouthL.setDrawRoute(this.southTileBtn.isSelected()); + this.switchSouthR.setShowRoute(this.southTileBtn.isSelected()); + this.switchSouthL.setShowRoute(this.southTileBtn.isSelected()); }//GEN-LAST:event_southTileBtnActionPerformed private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed diff --git a/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java b/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java index f8881283..8d11d4ec 100644 --- a/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java +++ b/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java @@ -1 +1 @@ -/* * Copyright 2024 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.Color; import java.awt.Point; import javax.swing.ComboBoxModel; import javax.swing.DefaultComboBoxModel; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.AccessoryValue; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; import jcs.ui.layout.LayoutUtil; import jcs.ui.layout.events.TileEvent; import org.tinylog.Logger; public class TileTesterFrame extends javax.swing.JFrame { private Tile tile; public TileTesterFrame() { initComponents(); this.tileCB.setModel(createTileTypeComboBoxModel()); this.orientationCB.setModel(createOrientationComboBoxModel()); this.incomingSideCB.setModel(createOrientationComboBoxModel()); this.directionCB.setModel(createDirectionComboBoxModel(true)); createTile(); pack(); setVisible(true); } private ComboBoxModel createTileTypeComboBoxModel() { DefaultComboBoxModel tileTypeModel = new DefaultComboBoxModel(); tileTypeModel.addElement(TileBean.TileType.STRAIGHT); tileTypeModel.addElement(TileBean.TileType.STRAIGHT_DIR); tileTypeModel.addElement(TileBean.TileType.SENSOR); tileTypeModel.addElement(TileBean.TileType.SIGNAL); tileTypeModel.addElement(TileBean.TileType.END); tileTypeModel.addElement(TileBean.TileType.CROSSING); tileTypeModel.addElement(TileBean.TileType.CURVED); tileTypeModel.addElement(TileBean.TileType.SWITCH); tileTypeModel.addElement(TileBean.TileType.CROSS); return tileTypeModel; } private ComboBoxModel createOrientationComboBoxModel() { DefaultComboBoxModel orientationModel = new DefaultComboBoxModel(); orientationModel.addElement(Orientation.EAST); orientationModel.addElement(Orientation.SOUTH); orientationModel.addElement(Orientation.WEST); orientationModel.addElement(Orientation.NORTH); return orientationModel; } private ComboBoxModel createDirectionComboBoxModel(boolean dontCare) { DefaultComboBoxModel directionModel = new DefaultComboBoxModel(); if (dontCare) { directionModel.addElement(Direction.CENTER); } else { directionModel.addElement(Direction.LEFT); directionModel.addElement(Direction.RIGHT); } return directionModel; } private void createTile() { if (tile != null) { Logger.trace("Removing tile " + tile.getId()); canvas.remove(tile); tile = null; } TileType tileType = (TileType) tileCB.getSelectedItem(); Orientation orientation = (Orientation) orientationCB.getSelectedItem(); if (TileType.SWITCH == tileType || TileType.CROSS == tileType) { directionCB.setModel(createDirectionComboBoxModel(false)); } else { directionCB.setModel(createDirectionComboBoxModel(true)); } Direction direction = (Direction) this.directionCB.getSelectedItem(); boolean scale = !scaleCB.isSelected(); boolean showCenter = showCenterCB.isSelected(); int w = canvas.getWidth(); int h = canvas.getHeight(); int x = w / 2; int y = h / 2; Point tileCenter = new Point(x, y); tileCenter = LayoutUtil.snapToGrid(tileCenter); // if (TileType.CROSS == tileType) { // switch (orientation) { // case SOUTH -> { // x = w / 2 + 200; // y = h / 2 - 150; // } // case WEST -> { // x = w / 2 + 400; // y = h / 2 + 50; // } // case NORTH -> { // x = w / 2 + 200; // y = h / 2 + 250; // } // default -> { // x = w / 2; // y = h / 2 + 50; // } // } // } else { // x = w / 2 - 200; // y = h / 2 - 200; // } // Point center; // if (TileType.CROSS.equals(tileType)) { // center = new Point(x - 200, y); // } else { // center = new Point(x, y); // } Tile newTile = TileFactory.createTile(tileType, orientation, direction, tileCenter); newTile.setScaleImage(scale); newTile.setDrawCenterPoint(showCenter); //tile.setPropertyChangeListener(this); Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); newTile.setIncomingSide(incomingSide); newTile.setDrawRoute(displayRouteCB.isSelected()); newTile.setTrackRouteColor(Color.blue); Logger.trace("Adding tile " + newTile.getId() + " " + newTile.xyToString()); //this.cPanel.add((JComponent) newTile); this.canvas.add(newTile); this.tile = newTile; } private AccessoryValue getAccessoryState() { AccessoryValue value; if (greenRB.isSelected()) { value = AccessoryValue.GREEN; } else if (redRB.isSelected()) { value = AccessoryValue.RED; } else { value = AccessoryValue.OFF; } return value; } private void changeAccesoryState() { if(tile instanceof Sensor) { tile.setActive(this.redRB.isSelected()); } if (tile instanceof Switch aSwitch) { if (this.displayRouteCB.isSelected()) { aSwitch.setRouteValue(getAccessoryState()); } else { aSwitch.setAccessoryValue(getAccessoryState()); } } if (tile instanceof Signal aSignal) { if (this.greenRB.isSelected()) { aSignal.setSignalValue(AccessoryBean.SignalValue.Hp1); } else if (this.redRB.isSelected()) { aSignal.setSignalValue(AccessoryBean.SignalValue.Hp0); } else { aSignal.setSignalValue(AccessoryBean.SignalValue.OFF); } } //this.tile.repaint(); } // @Override // public void propertyChange(PropertyChangeEvent evt) { // if ("repaintTile".equals(evt.getPropertyName())) { // Tile t = (Tile) evt.getNewValue(); // Logger.trace("Tile: " + t); // //this.repaint(); // } // } // @Override // public void paint(Graphics g) { // super.paint(g); // Graphics2D g2d = (Graphics2D) g; // boolean outline = this.drawOutlineCB.isSelected(); // boolean showRoute = this.displayRouteCB.isSelected(); // tile.setDrawRoute(showRoute); // // tile.drawTile(g2d, outline); // // if (outline) { // tile.drawBounds(g2d); // tile.drawCenterPoint(g2d, Color.red); // } // } // @Override // public void paint(Graphics g) { // long started = System.currentTimeMillis(); // super.paint(g); // // long now = System.currentTimeMillis(); // Logger.trace("Duration: " + (now - started) + " ms."); // } private void changeDirection() { Direction direction = (Direction) this.directionCB.getSelectedItem(); this.tile.setDirection(direction); //if (TileType.CROSS == tile.getTileType()) { // ((Cross) tile).setWidthHeightAndOffsets(); //} //this.repaint(); } private void rotateTile() { Orientation newOrientation = tile.rotate(); orientationCB.setSelectedItem(newOrientation); // if (TileType.CROSS == tile.getTileType()) { // int x = tile.getCenterX(); // int y = tile.getCenterY(); // int w = tile.getWidth() * 10; // int h = tile.getHeight() * 10; // // //calculate a new centerpoint for cross // switch (tile.getOrientation()) { // case SOUTH -> { // x = x + w / 2; // y = y - h / 4; // } // case WEST -> { // x = x + w / 4; // y = y + h / 2; // } // case NORTH -> { // x = x - w / 2; // y = y + h / 4; // } // default -> { // x = x - w / 4; // y = y - h / 2; // } // } // tile.setCenter(new Point(x, y)); // } //this.canvas.repaint(this.tile.getTileBounds()); //tile.repaint(); } private void changeOrientation() { Orientation orientation = (Orientation) this.orientationCB.getSelectedItem(); tile.setOrientation(orientation); // if (TileType.CROSS == tile.getTileType()) { // //((Cross) tile).setWidthHeightAndOffsets(); // // int x = tile.getCenterX(); // int y = tile.getCenterY(); // int w = tile.getWidth() * 10; // int h = tile.getHeight() * 10; // // //calculate a new centerpoint for cross // switch (tile.getOrientation()) { // case SOUTH -> { // x = x + w / 2; // y = y - h / 4; // } // case WEST -> { // x = x + w / 4; // y = y + h / 2; // } // case NORTH -> { // x = x - w / 2; // y = y + h / 4; // } // default -> { // x = x - w / 4; // y = y - h / 2; // } // } // tile.setCenter(new Point(x, y)); // } //this.repaint(); } private void showRoute() { Logger.trace("Show route on tile " + tile.getId()); String tileId = tile.getId(); Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); //TileEvent tileEvent; if (tile.isJunction()) { AccessoryValue routeState = getAccessoryState(); //tileEvent = new TileEvent(tileId, true, incomingSide, routeState); } else { //tileEvent = new TileEvent(tileId, true, incomingSide); } //TileCache.fireTileEventListener(tileEvent); // ((JComponent) this.tile).repaint(); tile.setDrawRoute(displayRouteCB.isSelected()); //repaint(); } // private void showOutline() { // //repaint(); // } private void changeIncomingSide() { Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); tile.setIncomingSide(incomingSide); //this.repaint(); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { accessoryBG = new javax.swing.ButtonGroup(); nPanel = new javax.swing.JPanel(); tileCB = new javax.swing.JComboBox<>(); orientationCB = new javax.swing.JComboBox<>(); inComingLbl = new javax.swing.JLabel(); incomingSideCB = new javax.swing.JComboBox<>(); directionCB = new javax.swing.JComboBox<>(); rotateButton = new javax.swing.JButton(); offRB = new javax.swing.JRadioButton(); greenRB = new javax.swing.JRadioButton(); redRB = new javax.swing.JRadioButton(); displayRouteCB = new javax.swing.JCheckBox(); scaleCB = new javax.swing.JCheckBox(); showCenterCB = new javax.swing.JCheckBox(); canvas = new jcs.ui.layout.tiles.DotGridCanvas(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); nPanel.setMinimumSize(new java.awt.Dimension(860, 36)); nPanel.setPreferredSize(new java.awt.Dimension(1020, 36)); java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); flowLayout1.setAlignOnBaseline(true); nPanel.setLayout(flowLayout1); tileCB.setPreferredSize(new java.awt.Dimension(150, 23)); tileCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { tileCBActionPerformed(evt); } }); nPanel.add(tileCB); orientationCB.setPreferredSize(new java.awt.Dimension(100, 23)); orientationCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { orientationCBActionPerformed(evt); } }); nPanel.add(orientationCB); inComingLbl.setText("Incoming Orientation"); nPanel.add(inComingLbl); incomingSideCB.setPreferredSize(new java.awt.Dimension(100, 23)); incomingSideCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { incomingSideCBActionPerformed(evt); } }); nPanel.add(incomingSideCB); directionCB.setPreferredSize(new java.awt.Dimension(100, 23)); directionCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { directionCBActionPerformed(evt); } }); nPanel.add(directionCB); rotateButton.setText("Rotate"); rotateButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { rotateButtonActionPerformed(evt); } }); nPanel.add(rotateButton); accessoryBG.add(offRB); offRB.setForeground(new java.awt.Color(153, 153, 153)); offRB.setSelected(true); offRB.setText("Off"); offRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { offRBActionPerformed(evt); } }); nPanel.add(offRB); accessoryBG.add(greenRB); greenRB.setForeground(new java.awt.Color(102, 255, 0)); greenRB.setText("Green"); greenRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { greenRBActionPerformed(evt); } }); nPanel.add(greenRB); accessoryBG.add(redRB); redRB.setForeground(new java.awt.Color(255, 0, 51)); redRB.setText("Red"); redRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { redRBActionPerformed(evt); } }); nPanel.add(redRB); displayRouteCB.setText("Route"); displayRouteCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { displayRouteCBActionPerformed(evt); } }); nPanel.add(displayRouteCB); scaleCB.setText("Scale"); scaleCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { scaleCBActionPerformed(evt); } }); nPanel.add(scaleCB); showCenterCB.setText("Center"); showCenterCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { showCenterCBActionPerformed(evt); } }); nPanel.add(showCenterCB); getContentPane().add(nPanel, java.awt.BorderLayout.NORTH); canvas.setPreferredSize(new java.awt.Dimension(600, 600)); getContentPane().add(canvas, java.awt.BorderLayout.CENTER); pack(); }// //GEN-END:initComponents private void rotateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rotateButtonActionPerformed rotateTile(); }//GEN-LAST:event_rotateButtonActionPerformed private void tileCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tileCBActionPerformed createTile(); }//GEN-LAST:event_tileCBActionPerformed private void orientationCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_orientationCBActionPerformed changeOrientation(); }//GEN-LAST:event_orientationCBActionPerformed private void directionCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_directionCBActionPerformed changeDirection(); }//GEN-LAST:event_directionCBActionPerformed private void offRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_offRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_offRBActionPerformed private void greenRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_greenRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_greenRBActionPerformed private void redRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_redRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_redRBActionPerformed private void displayRouteCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_displayRouteCBActionPerformed showRoute(); }//GEN-LAST:event_displayRouteCBActionPerformed private void scaleCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_scaleCBActionPerformed this.tile.setScaleImage(!this.scaleCB.isSelected()); this.tile.setBounds(this.tile.getTileBounds()); }//GEN-LAST:event_scaleCBActionPerformed private void incomingSideCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_incomingSideCBActionPerformed changeIncomingSide(); }//GEN-LAST:event_incomingSideCBActionPerformed private void showCenterCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showCenterCBActionPerformed this.tile.setDrawCenterPoint(this.showCenterCB.isSelected()); }//GEN-LAST:event_showCenterCBActionPerformed /** * @param args the command line arguments */ public static void main(String args[]) { try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { Logger.error(ex); } /* Create and display the form */ java.awt.EventQueue.invokeLater(() -> { TileTesterFrame app = new TileTesterFrame(); app.setTitle("Tile Tester"); app.setLocationRelativeTo(null); }); } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.ButtonGroup accessoryBG; private jcs.ui.layout.tiles.DotGridCanvas canvas; private javax.swing.JComboBox directionCB; private javax.swing.JCheckBox displayRouteCB; private javax.swing.JRadioButton greenRB; private javax.swing.JLabel inComingLbl; private javax.swing.JComboBox incomingSideCB; private javax.swing.JPanel nPanel; private javax.swing.JRadioButton offRB; private javax.swing.JComboBox orientationCB; private javax.swing.JRadioButton redRB; private javax.swing.JButton rotateButton; private javax.swing.JCheckBox scaleCB; private javax.swing.JCheckBox showCenterCB; private javax.swing.JComboBox tileCB; // End of variables declaration//GEN-END:variables } \ No newline at end of file +/* * Copyright 2024 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.Color; import java.awt.Point; import javax.swing.ComboBoxModel; import javax.swing.DefaultComboBoxModel; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.AccessoryValue; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; import jcs.ui.layout.LayoutUtil; import jcs.ui.layout.events.TileEvent; import org.tinylog.Logger; public class TileTesterFrame extends javax.swing.JFrame { private Tile tile; public TileTesterFrame() { initComponents(); this.tileCB.setModel(createTileTypeComboBoxModel()); this.orientationCB.setModel(createOrientationComboBoxModel()); this.incomingSideCB.setModel(createOrientationComboBoxModel()); this.directionCB.setModel(createDirectionComboBoxModel(true)); createTile(); pack(); setVisible(true); } private ComboBoxModel createTileTypeComboBoxModel() { DefaultComboBoxModel tileTypeModel = new DefaultComboBoxModel(); tileTypeModel.addElement(TileBean.TileType.STRAIGHT); tileTypeModel.addElement(TileBean.TileType.STRAIGHT_DIR); tileTypeModel.addElement(TileBean.TileType.SENSOR); tileTypeModel.addElement(TileBean.TileType.SIGNAL); tileTypeModel.addElement(TileBean.TileType.END); tileTypeModel.addElement(TileBean.TileType.CROSSING); tileTypeModel.addElement(TileBean.TileType.CURVED); tileTypeModel.addElement(TileBean.TileType.SWITCH); tileTypeModel.addElement(TileBean.TileType.CROSS); return tileTypeModel; } private ComboBoxModel createOrientationComboBoxModel() { DefaultComboBoxModel orientationModel = new DefaultComboBoxModel(); orientationModel.addElement(Orientation.EAST); orientationModel.addElement(Orientation.SOUTH); orientationModel.addElement(Orientation.WEST); orientationModel.addElement(Orientation.NORTH); return orientationModel; } private ComboBoxModel createDirectionComboBoxModel(boolean dontCare) { DefaultComboBoxModel directionModel = new DefaultComboBoxModel(); if (dontCare) { directionModel.addElement(Direction.CENTER); } else { directionModel.addElement(Direction.LEFT); directionModel.addElement(Direction.RIGHT); } return directionModel; } private void createTile() { if (tile != null) { Logger.trace("Removing tile " + tile.getId()); canvas.remove(tile); tile = null; } TileType tileType = (TileType) tileCB.getSelectedItem(); Orientation orientation = (Orientation) orientationCB.getSelectedItem(); if (TileType.SWITCH == tileType || TileType.CROSS == tileType) { directionCB.setModel(createDirectionComboBoxModel(false)); } else { directionCB.setModel(createDirectionComboBoxModel(true)); } Direction direction = (Direction) this.directionCB.getSelectedItem(); boolean scale = !scaleCB.isSelected(); boolean showCenter = showCenterCB.isSelected(); int w = canvas.getWidth(); int h = canvas.getHeight(); int x = w / 2; int y = h / 2; Point tileCenter = new Point(x, y); tileCenter = LayoutUtil.snapToGrid(tileCenter); // if (TileType.CROSS == tileType) { // switch (orientation) { // case SOUTH -> { // x = w / 2 + 200; // y = h / 2 - 150; // } // case WEST -> { // x = w / 2 + 400; // y = h / 2 + 50; // } // case NORTH -> { // x = w / 2 + 200; // y = h / 2 + 250; // } // default -> { // x = w / 2; // y = h / 2 + 50; // } // } // } else { // x = w / 2 - 200; // y = h / 2 - 200; // } // Point center; // if (TileType.CROSS.equals(tileType)) { // center = new Point(x - 200, y); // } else { // center = new Point(x, y); // } Tile newTile = TileFactory.createTile(tileType, orientation, direction, tileCenter); newTile.setScaleImage(scale); newTile.setDrawCenterPoint(showCenter); //tile.setPropertyChangeListener(this); Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); newTile.setIncomingSide(incomingSide); newTile.setShowRoute(displayRouteCB.isSelected()); newTile.setTrackRouteColor(Color.blue); Logger.trace("Adding tile " + newTile.getId() + " " + newTile.xyToString()); //this.cPanel.add((JComponent) newTile); this.canvas.add(newTile); this.tile = newTile; } private AccessoryValue getAccessoryState() { AccessoryValue value; if (greenRB.isSelected()) { value = AccessoryValue.GREEN; } else if (redRB.isSelected()) { value = AccessoryValue.RED; } else { value = AccessoryValue.OFF; } return value; } private void changeAccesoryState() { if(tile instanceof Sensor) { tile.setActive(this.redRB.isSelected()); } if (tile instanceof Switch aSwitch) { if (this.displayRouteCB.isSelected()) { aSwitch.setRouteValue(getAccessoryState()); } else { aSwitch.setAccessoryValue(getAccessoryState()); } } if (tile instanceof Signal aSignal) { if (this.greenRB.isSelected()) { aSignal.setSignalValue(AccessoryBean.SignalValue.Hp1); } else if (this.redRB.isSelected()) { aSignal.setSignalValue(AccessoryBean.SignalValue.Hp0); } else { aSignal.setSignalValue(AccessoryBean.SignalValue.OFF); } } //this.tile.repaint(); } // @Override // public void propertyChange(PropertyChangeEvent evt) { // if ("repaintTile".equals(evt.getPropertyName())) { // Tile t = (Tile) evt.getNewValue(); // Logger.trace("Tile: " + t); // //this.repaint(); // } // } // @Override // public void paint(Graphics g) { // super.paint(g); // Graphics2D g2d = (Graphics2D) g; // boolean outline = this.drawOutlineCB.isSelected(); // boolean showRoute = this.displayRouteCB.isSelected(); // tile.setShowRoute(showRoute); // // tile.drawTile(g2d, outline); // // if (outline) { // tile.drawBounds(g2d); // tile.drawCenterPoint(g2d, Color.red); // } // } // @Override // public void paint(Graphics g) { // long started = System.currentTimeMillis(); // super.paint(g); // // long now = System.currentTimeMillis(); // Logger.trace("Duration: " + (now - started) + " ms."); // } private void changeDirection() { Direction direction = (Direction) this.directionCB.getSelectedItem(); this.tile.setDirection(direction); //if (TileType.CROSS == tile.getTileType()) { // ((Cross) tile).setWidthHeightAndOffsets(); //} //this.repaint(); } private void rotateTile() { Orientation newOrientation = tile.rotate(); orientationCB.setSelectedItem(newOrientation); // if (TileType.CROSS == tile.getTileType()) { // int x = tile.getCenterX(); // int y = tile.getCenterY(); // int w = tile.getWidth() * 10; // int h = tile.getHeight() * 10; // // //calculate a new centerpoint for cross // switch (tile.getOrientation()) { // case SOUTH -> { // x = x + w / 2; // y = y - h / 4; // } // case WEST -> { // x = x + w / 4; // y = y + h / 2; // } // case NORTH -> { // x = x - w / 2; // y = y + h / 4; // } // default -> { // x = x - w / 4; // y = y - h / 2; // } // } // tile.setCenter(new Point(x, y)); // } //this.canvas.repaint(this.tile.getTileBounds()); //tile.repaint(); } private void changeOrientation() { Orientation orientation = (Orientation) this.orientationCB.getSelectedItem(); tile.setOrientation(orientation); // if (TileType.CROSS == tile.getTileType()) { // //((Cross) tile).setWidthHeightAndOffsets(); // // int x = tile.getCenterX(); // int y = tile.getCenterY(); // int w = tile.getWidth() * 10; // int h = tile.getHeight() * 10; // // //calculate a new centerpoint for cross // switch (tile.getOrientation()) { // case SOUTH -> { // x = x + w / 2; // y = y - h / 4; // } // case WEST -> { // x = x + w / 4; // y = y + h / 2; // } // case NORTH -> { // x = x - w / 2; // y = y + h / 4; // } // default -> { // x = x - w / 4; // y = y - h / 2; // } // } // tile.setCenter(new Point(x, y)); // } //this.repaint(); } private void showRoute() { Logger.trace("Show route on tile " + tile.getId()); String tileId = tile.getId(); Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); //TileEvent tileEvent; if (tile.isJunction()) { AccessoryValue routeState = getAccessoryState(); //tileEvent = new TileEvent(tileId, true, incomingSide, routeState); } else { //tileEvent = new TileEvent(tileId, true, incomingSide); } //TileCache.fireTileEventListener(tileEvent); // ((JComponent) this.tile).repaint(); tile.setShowRoute(displayRouteCB.isSelected()); //repaint(); } // private void showOutline() { // //repaint(); // } private void changeIncomingSide() { Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); tile.setIncomingSide(incomingSide); //this.repaint(); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { accessoryBG = new javax.swing.ButtonGroup(); nPanel = new javax.swing.JPanel(); tileCB = new javax.swing.JComboBox<>(); orientationCB = new javax.swing.JComboBox<>(); inComingLbl = new javax.swing.JLabel(); incomingSideCB = new javax.swing.JComboBox<>(); directionCB = new javax.swing.JComboBox<>(); rotateButton = new javax.swing.JButton(); offRB = new javax.swing.JRadioButton(); greenRB = new javax.swing.JRadioButton(); redRB = new javax.swing.JRadioButton(); displayRouteCB = new javax.swing.JCheckBox(); scaleCB = new javax.swing.JCheckBox(); showCenterCB = new javax.swing.JCheckBox(); canvas = new jcs.ui.layout.tiles.DotGridCanvas(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); nPanel.setMinimumSize(new java.awt.Dimension(860, 36)); nPanel.setPreferredSize(new java.awt.Dimension(1020, 36)); java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); flowLayout1.setAlignOnBaseline(true); nPanel.setLayout(flowLayout1); tileCB.setPreferredSize(new java.awt.Dimension(150, 23)); tileCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { tileCBActionPerformed(evt); } }); nPanel.add(tileCB); orientationCB.setPreferredSize(new java.awt.Dimension(100, 23)); orientationCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { orientationCBActionPerformed(evt); } }); nPanel.add(orientationCB); inComingLbl.setText("Incoming Orientation"); nPanel.add(inComingLbl); incomingSideCB.setPreferredSize(new java.awt.Dimension(100, 23)); incomingSideCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { incomingSideCBActionPerformed(evt); } }); nPanel.add(incomingSideCB); directionCB.setPreferredSize(new java.awt.Dimension(100, 23)); directionCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { directionCBActionPerformed(evt); } }); nPanel.add(directionCB); rotateButton.setText("Rotate"); rotateButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { rotateButtonActionPerformed(evt); } }); nPanel.add(rotateButton); accessoryBG.add(offRB); offRB.setForeground(new java.awt.Color(153, 153, 153)); offRB.setSelected(true); offRB.setText("Off"); offRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { offRBActionPerformed(evt); } }); nPanel.add(offRB); accessoryBG.add(greenRB); greenRB.setForeground(new java.awt.Color(102, 255, 0)); greenRB.setText("Green"); greenRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { greenRBActionPerformed(evt); } }); nPanel.add(greenRB); accessoryBG.add(redRB); redRB.setForeground(new java.awt.Color(255, 0, 51)); redRB.setText("Red"); redRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { redRBActionPerformed(evt); } }); nPanel.add(redRB); displayRouteCB.setText("Route"); displayRouteCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { displayRouteCBActionPerformed(evt); } }); nPanel.add(displayRouteCB); scaleCB.setText("Scale"); scaleCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { scaleCBActionPerformed(evt); } }); nPanel.add(scaleCB); showCenterCB.setText("Center"); showCenterCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { showCenterCBActionPerformed(evt); } }); nPanel.add(showCenterCB); getContentPane().add(nPanel, java.awt.BorderLayout.NORTH); canvas.setPreferredSize(new java.awt.Dimension(600, 600)); getContentPane().add(canvas, java.awt.BorderLayout.CENTER); pack(); }// //GEN-END:initComponents private void rotateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rotateButtonActionPerformed rotateTile(); }//GEN-LAST:event_rotateButtonActionPerformed private void tileCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tileCBActionPerformed createTile(); }//GEN-LAST:event_tileCBActionPerformed private void orientationCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_orientationCBActionPerformed changeOrientation(); }//GEN-LAST:event_orientationCBActionPerformed private void directionCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_directionCBActionPerformed changeDirection(); }//GEN-LAST:event_directionCBActionPerformed private void offRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_offRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_offRBActionPerformed private void greenRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_greenRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_greenRBActionPerformed private void redRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_redRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_redRBActionPerformed private void displayRouteCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_displayRouteCBActionPerformed showRoute(); }//GEN-LAST:event_displayRouteCBActionPerformed private void scaleCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_scaleCBActionPerformed this.tile.setScaleImage(!this.scaleCB.isSelected()); this.tile.setBounds(this.tile.getTileBounds()); }//GEN-LAST:event_scaleCBActionPerformed private void incomingSideCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_incomingSideCBActionPerformed changeIncomingSide(); }//GEN-LAST:event_incomingSideCBActionPerformed private void showCenterCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showCenterCBActionPerformed this.tile.setDrawCenterPoint(this.showCenterCB.isSelected()); }//GEN-LAST:event_showCenterCBActionPerformed /** * @param args the command line arguments */ public static void main(String args[]) { try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { Logger.error(ex); } /* Create and display the form */ java.awt.EventQueue.invokeLater(() -> { TileTesterFrame app = new TileTesterFrame(); app.setTitle("Tile Tester"); app.setLocationRelativeTo(null); }); } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.ButtonGroup accessoryBG; private jcs.ui.layout.tiles.DotGridCanvas canvas; private javax.swing.JComboBox directionCB; private javax.swing.JCheckBox displayRouteCB; private javax.swing.JRadioButton greenRB; private javax.swing.JLabel inComingLbl; private javax.swing.JComboBox incomingSideCB; private javax.swing.JPanel nPanel; private javax.swing.JRadioButton offRB; private javax.swing.JComboBox orientationCB; private javax.swing.JRadioButton redRB; private javax.swing.JButton rotateButton; private javax.swing.JCheckBox scaleCB; private javax.swing.JCheckBox showCenterCB; private javax.swing.JComboBox tileCB; // End of variables declaration//GEN-END:variables } \ No newline at end of file From 93ecce40d2dc9ffcb6e310f7c138a1c2a16f3fad Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Fri, 7 Feb 2025 17:08:03 +0100 Subject: [PATCH 14/70] Refactored the UI code to make each tile following the MVC pattern. The Tile which are extended from JComponent now follow the MVC patter, as echt tile has it own UI delegate. Next step is to add the mouse listeners in the Sensor and switched so that these components can be controlled --- src/main/java/jcs/ui/layout/tiles/Block.java | 805 +++++++++++++++++- src/main/java/jcs/ui/layout/tiles/Cross.java | 698 ++++++++++++++- .../java/jcs/ui/layout/tiles/Crossing.java | 148 +++- src/main/java/jcs/ui/layout/tiles/Curved.java | 134 ++- .../jcs/ui/layout/tiles/DefaultTileModel.java | 73 +- src/main/java/jcs/ui/layout/tiles/End.java | 109 ++- src/main/java/jcs/ui/layout/tiles/Sensor.java | 38 +- src/main/java/jcs/ui/layout/tiles/Signal.java | 566 ++++++------ .../java/jcs/ui/layout/tiles/Straight.java | 105 ++- .../ui/layout/tiles/StraightDirection.java | 48 +- src/main/java/jcs/ui/layout/tiles/Switch.java | 346 +++++++- src/main/java/jcs/ui/layout/tiles/Tile.java | 502 ++++++----- src/main/java/jcs/ui/layout/tiles/Tile1.java | 221 ----- .../java/jcs/ui/layout/tiles/TileModel.java | 6 +- .../jcs/ui/layout/tiles/enums/Rotation.java | 50 -- .../java/jcs/ui/layout/tiles/ui/BlockUI.java | 506 +++++++++++ .../java/jcs/ui/layout/tiles/ui/CrossUI.java | 362 ++++++++ .../jcs/ui/layout/tiles/ui/CrossingUI.java | 94 ++ .../java/jcs/ui/layout/tiles/ui/CurvedUI.java | 62 ++ .../java/jcs/ui/layout/tiles/ui/EndUI.java | 66 ++ .../java/jcs/ui/layout/tiles/ui/SensorUI.java | 69 ++ .../java/jcs/ui/layout/tiles/ui/SignalUI.java | 325 +++++++ .../layout/tiles/ui/StraightDirectionUI.java | 49 ++ .../jcs/ui/layout/tiles/ui/StraightUI.java | 75 ++ .../java/jcs/ui/layout/tiles/ui/SwitchUI.java | 146 ++++ .../java/jcs/ui/layout/tiles/ui/TileUI.java | 272 ++++++ .../jcs/ui/layout/tiles/TileTesterFrame.form | 455 +++++++++- .../jcs/ui/layout/tiles/TileTesterFrame.java | 2 +- 28 files changed, 5406 insertions(+), 926 deletions(-) delete mode 100644 src/main/java/jcs/ui/layout/tiles/Tile1.java delete mode 100755 src/main/java/jcs/ui/layout/tiles/enums/Rotation.java create mode 100644 src/main/java/jcs/ui/layout/tiles/ui/BlockUI.java create mode 100644 src/main/java/jcs/ui/layout/tiles/ui/CrossUI.java create mode 100644 src/main/java/jcs/ui/layout/tiles/ui/CrossingUI.java create mode 100644 src/main/java/jcs/ui/layout/tiles/ui/CurvedUI.java create mode 100644 src/main/java/jcs/ui/layout/tiles/ui/EndUI.java create mode 100644 src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java create mode 100644 src/main/java/jcs/ui/layout/tiles/ui/SignalUI.java create mode 100644 src/main/java/jcs/ui/layout/tiles/ui/StraightDirectionUI.java create mode 100644 src/main/java/jcs/ui/layout/tiles/ui/StraightUI.java create mode 100644 src/main/java/jcs/ui/layout/tiles/ui/SwitchUI.java create mode 100644 src/main/java/jcs/ui/layout/tiles/ui/TileUI.java diff --git a/src/main/java/jcs/ui/layout/tiles/Block.java b/src/main/java/jcs/ui/layout/tiles/Block.java index c9f36962..faa77ea3 100755 --- a/src/main/java/jcs/ui/layout/tiles/Block.java +++ b/src/main/java/jcs/ui/layout/tiles/Block.java @@ -1 +1,804 @@ -/* * Copyright 2024 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; 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.Image; import java.awt.Point; import java.awt.Rectangle; import java.awt.geom.Ellipse2D; import java.awt.image.BufferedImage; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import jcs.entities.BlockBean; import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.EAST; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; import static jcs.ui.layout.tiles.Tile.GRID; import static jcs.ui.layout.tiles.Tile.RENDER_HEIGHT; import static jcs.ui.layout.tiles.Tile.RENDER_WIDTH; import jcs.ui.util.ImageUtil; import org.tinylog.Logger; public class Block extends Tile { public static final int BLOCK_WIDTH = DEFAULT_WIDTH * 3; public static final int BLOCK_HEIGHT = DEFAULT_HEIGHT * 3; public Block(TileBean tileBean) { super(tileBean); setModel(new DefaultTileModel(tileBean.getOrientation())); changeRenderSize(); populateModel(); } public Block(Orientation orientation, Point center) { this(orientation, center.x, center.y); } public Block(Orientation orientation, int x, int y) { this(orientation, x, y, tileWidth(orientation, TileType.BLOCK), tileHeight(orientation, TileType.BLOCK)); } public Block(Orientation orientation, int x, int y, int width, int height) { super(TileType.BLOCK, orientation, x, y, width, height); setModel(new DefaultTileModel(orientation)); changeRenderSize(); } private void changeRenderSize() { Orientation tileOrientation = model.getTileOrienation(); if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { this.renderWidth = RENDER_WIDTH * 3; this.renderHeight = RENDER_HEIGHT; } else { this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT * 3; } } @Override public Set getAltPoints() { int xx = this.tileX; int yy = this.tileY; Set alternatives = new HashSet<>(); if (Orientation.EAST.equals(getOrientation()) || Orientation.WEST.equals(getOrientation())) { // West Point wp = new Point((xx - DEFAULT_WIDTH), yy); Point ep = new Point((xx + DEFAULT_WIDTH), yy); alternatives.add(wp); alternatives.add(ep); } else { Point np = new Point(xx, (yy - DEFAULT_HEIGHT)); Point sp = new Point(xx, (yy + DEFAULT_HEIGHT)); alternatives.add(np); alternatives.add(sp); } return alternatives; } @Override public Set getAllPoints() { Set aps = new HashSet<>(); aps.add(getCenter()); aps.addAll(getAltPoints()); return aps; } @Override Set getAllPoints(Point center) { Set points = getAltPoints(center); points.add(center); return points; } @Override Set getAltPoints(Point center) { Set alts = new HashSet<>(); if (Orientation.EAST == model.getTileOrienation() || Orientation.WEST == model.getTileOrienation()) { // West Point wp = new Point((center.x - DEFAULT_WIDTH), center.y); Point ep = new Point((center.x + DEFAULT_WIDTH), center.y); alts.add(wp); alts.add(ep); } else { Point np = new Point(center.x, (center.y - DEFAULT_HEIGHT)); Point sp = new Point(center.x, (center.y + DEFAULT_HEIGHT)); alts.add(np); alts.add(sp); } return alts; } public Point getAltPoint(String suffix) { int cx = this.getCenterX(); int cy = this.getCenterY(); if ("+".equals(suffix)) { return switch (this.getOrientation()) { case WEST -> new Point(cx - Tile.GRID * 2, cy); case NORTH -> new Point(cx, cy - Tile.GRID * 2); case SOUTH -> new Point(cx, cy + Tile.GRID * 2); default -> new Point(cx + Tile.GRID * 2, cy); }; } else { return switch (this.getOrientation()) { case EAST -> new Point(cx - Tile.GRID * 2, cy); case SOUTH -> new Point(cx, cy - Tile.GRID * 2); case NORTH -> new Point(cx, cy + Tile.GRID * 2); default -> new Point(cx + Tile.GRID * 2, cy); }; } } @Override public boolean isBlock() { return true; } @Override public Map getNeighborPoints() { Map neighbors = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); // Horizontal if (Orientation.EAST == orientation || Orientation.WEST == orientation) { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 4, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 4, cy)); } else { // Vertical neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 4)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 4)); } return neighbors; } @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); // Horizontal if (Orientation.EAST == orientation || Orientation.WEST == orientation) { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID * 3, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID * 3, cy)); } else { // Vertical edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 3)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 3)); } return edgeConnections; } public Point getNeighborPoint(String suffix) { int cx = getCenterX(); int cy = getCenterY(); if ("+".equals(suffix)) { return switch (getOrientation()) { case WEST -> new Point(cx - Tile.GRID * 4, cy); case NORTH -> new Point(cx, cy - Tile.GRID * 4); case SOUTH -> new Point(cx, cy + Tile.GRID * 4); default -> new Point(cx + Tile.GRID * 4, cy); }; } else { return switch (getOrientation()) { case EAST -> new Point(cx - Tile.GRID * 4, cy); case SOUTH -> new Point(cx, cy - Tile.GRID * 4); case NORTH -> new Point(cx, cy + Tile.GRID * 4); default -> new Point(cx + Tile.GRID * 4, cy); }; } } public Orientation getTravelDirection(String suffix) { if ("+".equals(suffix)) { return getOrientation(); } else { return switch (getOrientation()) { case EAST -> Orientation.WEST; case SOUTH -> Orientation.NORTH; case NORTH -> Orientation.SOUTH; default -> Orientation.EAST; }; } } @Override public String getIdSuffix(Tile other) { String suffix = null; Orientation match = null; if (isAdjacent(other)) { Map blockSides = this.getEdgePoints(); Map otherSides = other.getEdgePoints(); for (Orientation bo : Orientation.values()) { Point bp = blockSides.get(bo); if (bp != null) { for (Orientation oo : Orientation.values()) { Point op = otherSides.get(oo); if (op != null) { if (op.equals(bp)) { match = bo; break; } } } } } } Orientation tileOrientation = model.getTileOrienation(); if (match != null) { if (Orientation.EAST == tileOrientation && Orientation.EAST == match) { suffix = "+"; } if (Orientation.WEST == tileOrientation && Orientation.WEST == match) { suffix = "+"; } if (Orientation.EAST == tileOrientation && Orientation.WEST == match) { suffix = "-"; } if (Orientation.WEST == tileOrientation && Orientation.EAST == match) { suffix = "-"; } if (Orientation.NORTH == tileOrientation && Orientation.NORTH == match) { suffix = "+"; } if (Orientation.NORTH == tileOrientation && Orientation.SOUTH == match) { suffix = "-"; } if (Orientation.SOUTH == tileOrientation && Orientation.SOUTH == match) { suffix = "+"; } if (Orientation.SOUTH == tileOrientation && Orientation.NORTH == match) { suffix = "-"; } } return suffix; } @Override public Orientation rotate() { super.rotate(); Orientation tileOrientation = model.getTileOrienation(); int w = tileWidth(tileOrientation, TileType.BLOCK); int h = tileHeight(tileOrientation, TileType.BLOCK); Dimension d = new Dimension(w, h); setPreferredSize(d); setSize(d); changeRenderSize(); setBounds(getTileBounds()); return model.getTileOrienation(); } /** * Depending on the block status change the background color
* - Red: Occupied
* - Green: Departure
* - Magenta: Arrival / entering
* - Yellow: reserved
* - White: all clear / default
* * @return the Color which belong with the current Block State */ Color getBlockStateColor() { return getBlockStateColor(this.model.getBlockState()); } protected Color getBlockStateColor(BlockState blockState) { return switch (blockState) { case GHOST -> new Color(250, 0, 0); case LOCKED -> new Color(250, 250, 210); case OCCUPIED -> new Color(250, 210, 210); case OUT_OF_ORDER -> new Color(190, 190, 190); case OUTBOUND -> new Color(210, 250, 210); case INBOUND -> new Color(250, 210, 250); default -> new Color(255, 255, 255); }; } public static String getDepartureSuffix(Orientation tileOrientation, boolean reverseArrival, LocomotiveBean.Direction direction) { if (LocomotiveBean.Direction.FORWARDS == direction) { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { if (reverseArrival) { return "-"; } else { return "+"; } } else { if (reverseArrival) { return "+"; } else { return "-"; } } } else { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { if (reverseArrival) { return "+"; } else { return "-"; } } else { if (reverseArrival) { return "-"; } else { return "+"; } } } } @Override public void renderTile(Graphics2D g2) { int xx = 20; int yy = 50; int rw = RENDER_WIDTH * 3 - 40; int rh = 300; g2.setStroke(new BasicStroke(3, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); g2.setPaint(Color.darkGray); g2.drawRoundRect(xx, yy, rw, rh, 15, 15); Color blockStateColor = getBlockStateColor(); //Logger.trace("Block " + this.id + " State: " + this.getBlockBean().getBlockState().getState() + " Color: " + blockStateColor.toString()); g2.setPaint(blockStateColor); g2.fillRoundRect(xx, yy, rw, rh, 15, 15); g2.setStroke(new BasicStroke(20, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); g2.setPaint(Color.darkGray); g2.drawLine(rw + GRID, yy - 0, rw + GRID, yy + 300); //When there is a locomotive in the block mark the direction of travel. //The default, forwards is in the direction of the block orientation, i.e. the + if (model.getLocomotive() != null && model.getLocomotive().getName() != null) { renderDirectionArrow(g2); } drawName(g2); } private void renderDirectionArrow(Graphics2D g2) { //The default, forwards is in the direction of the block orientation, i.e. the + Orientation tileOrientation = model.getTileOrienation(); BlockBean bb = this.getBlockBean(); boolean reverseArrival = model.isReverseArrival(); LocomotiveBean.Direction logicalDirection; if (bb.getLogicalDirection() != null) { logicalDirection = model.getLogicalDirection(); } else { logicalDirection = model.getLocomotive().getDirection(); } String departureSuffix = model.getDepartureSuffix(); if (departureSuffix == null) { departureSuffix = Block.getDepartureSuffix(tileOrientation, reverseArrival, logicalDirection); } //Logger.trace(this.getId()+" LogicalDirection is " + (bb.getLogicalDirection() != null ? "Set" : "Not Set") + " Dir: " + logicalDirection.getDirection() + " Orientation: " + orientation.getOrientation() + " departureSuffix: " + departureSuffix); if ("+".equals(departureSuffix)) { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { switch (logicalDirection) { case LocomotiveBean.Direction.FORWARDS -> { if (reverseArrival) { renderLeftArrow(g2); } else { renderRightArrow(g2); } } case LocomotiveBean.Direction.BACKWARDS -> { if (reverseArrival) { renderRightArrow(g2); } else { renderLeftArrow(g2); } } } } else { switch (logicalDirection) { case LocomotiveBean.Direction.BACKWARDS -> { if (reverseArrival) { renderLeftArrow(g2); } else { renderRightArrow(g2); } } case LocomotiveBean.Direction.FORWARDS -> { if (reverseArrival) { renderRightArrow(g2); } else { renderLeftArrow(g2); } } } } } else { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { switch (logicalDirection) { case LocomotiveBean.Direction.FORWARDS -> { if (reverseArrival) { renderLeftArrow(g2); } else { renderRightArrow(g2); } } case LocomotiveBean.Direction.BACKWARDS -> { if (reverseArrival) { renderRightArrow(g2); } else { renderLeftArrow(g2); } } } } else { switch (logicalDirection) { case LocomotiveBean.Direction.BACKWARDS -> { if (reverseArrival) { renderLeftArrow(g2); } else { renderRightArrow(g2); } } case LocomotiveBean.Direction.FORWARDS -> { if (reverseArrival) { renderRightArrow(g2); } else { renderLeftArrow(g2); } } } } } } private void renderLeftArrow(Graphics2D g2) { //Logger.trace(this.getId()+" LogicalDirection is " + this.getBlockBean().getLogicalDirection() + " Orientation: " + this.getOrientation() + " departureSuffix: " + this.getBlockBean().getDepartureSuffix()); g2.fillPolygon(new int[]{0, 50, 50,}, new int[]{200, 150, 250}, 3); } private void renderRightArrow(Graphics2D g2) { //Logger.trace(this.getId()+" LogicalDirection is " + this.getBlockBean().getLogicalDirection() + " Orientation: " + this.getOrientation() + " departureSuffix: " + this.getBlockBean().getDepartureSuffix()); g2.fillPolygon(new int[]{1180, 1130, 1130,}, new int[]{200, 150, 250}, 3); } @Override public void renderTileRoute(Graphics2D g2d) { if (model.isShowBlockState()) { backgroundColor = getBlockStateColor(model.getBlockState()); } } protected void overlayLocImage() { int ww = tileImage.getWidth(); int hh = tileImage.getHeight(); Orientation tileOrientation = model.getTileOrienation(); BufferedImage overlay = new BufferedImage(ww, hh, BufferedImage.TYPE_INT_ARGB); Graphics2D g2i = overlay.createGraphics(); Image locImage = getLocImage(); if (locImage != null) { String departureSuffix = model.getDepartureSuffix(); boolean reverseImage = model.isReverseArrival(); Logger.trace("LocImage w: " + locImage.getWidth(null) + " h: " + locImage.getHeight(null)); // scale it to max h of 45 int size = 45; float aspect = (float) locImage.getHeight(null) / (float) locImage.getWidth(null); //TODO: Use Scalr? locImage = locImage.getScaledInstance(size, (int) (size * aspect), Image.SCALE_SMOOTH); //Depending on the block orientation the image needs to be rotated and flipped //Incase the departure suffix is NOT set center the locomotive image int w, h, xx, yy; switch (tileOrientation) { case WEST -> { w = locImage.getWidth(null); h = locImage.getHeight(null); if (null == departureSuffix) { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w; } else { switch (departureSuffix) { case "+" -> { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w - 25; } default -> { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w + 10; } } } yy = DEFAULT_HEIGHT / 2 - h / 2; if (reverseImage) { locImage = ImageUtil.flipVertically(locImage); } } case SOUTH -> { locImage = ImageUtil.flipHorizontally(locImage); locImage = ImageUtil.rotate(locImage, 90); w = locImage.getWidth(null); h = locImage.getHeight(null); xx = DEFAULT_WIDTH / 2 - w / 2; if (null == departureSuffix) { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h; } else { switch (departureSuffix) { case "-" -> { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h - 25; } default -> { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h + 10; } } } if (reverseImage) { locImage = ImageUtil.flipHorizontally(locImage); } } case NORTH -> { locImage = ImageUtil.flipHorizontally(locImage); locImage = ImageUtil.rotate(locImage, 90); w = locImage.getWidth(null); h = locImage.getHeight(null); xx = DEFAULT_WIDTH / 2 - w / 2; if (null == departureSuffix) { int minY = BLOCK_HEIGHT / 2 - getHeight() / 2 + h; yy = minY; } else { switch (departureSuffix) { case "+" -> { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h - 25; } default -> { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h + 10; } } } if (reverseImage) { locImage = ImageUtil.flipHorizontally(locImage); } } default -> { w = locImage.getWidth(null); h = locImage.getHeight(null); if (null == departureSuffix) { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w; } else { switch (departureSuffix) { case "-" -> { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w - 25; } default -> { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w + 10; } } } yy = DEFAULT_HEIGHT / 2 - h / 2; if (reverseImage) { locImage = ImageUtil.flipVertically(locImage); } } } g2i.drawImage(tileImage, 0, 0, null); g2i.drawImage(locImage, xx, yy, null); g2i.dispose(); tileImage = overlay; } } private Image getLocImage() { if (model.getLocomotive() != null && model.getLocomotive().getLocIcon() != null) { return model.getLocomotive().getLocIcon(); } else { return null; } } public String getBlockText() { String blockText; if (blockBean != null && blockBean.getDescription() != null) { if (blockBean.getLocomotive() != null && blockBean.getLocomotive().getName() != null && BlockState.GHOST != blockBean.getBlockState()) { blockText = blockBean.getLocomotive().getName(); } else { if (blockBean.getDescription().length() > 0) { blockText = blockBean.getDescription(); } else { blockText = getId(); } } } else { // Design mode show description when available if (blockBean != null && blockBean.getDescription() != null && blockBean.getDescription().length() > 0) { blockText = blockBean.getDescription(); } else { blockText = getId(); } } return blockText; } @Override public void drawName(Graphics2D g2d) { if (!model.isOverlayImage()) { g2d.setPaint(Color.black); Font currentFont = g2d.getFont(); Font newFont = currentFont.deriveFont(currentFont.getSize() * 10.0F); g2d.setFont(newFont); String blockText = getBlockText(); // Scale the text if necessary int textWidth = g2d.getFontMetrics().stringWidth(blockText); double fontscale = 10.0; if (textWidth > 845) { fontscale = fontscale * 847.0 / textWidth; newFont = currentFont.deriveFont(currentFont.getSize() * (float) fontscale); g2d.setFont(newFont); textWidth = g2d.getFontMetrics().stringWidth(blockText); } int textHeight = g2d.getFontMetrics().getHeight(); Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case EAST -> { drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) - textWidth / 2, RENDER_GRID + textHeight / 3, 0, blockText); } case WEST -> { drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) + textWidth / 2, RENDER_GRID - textHeight / 3, 180, blockText); } case NORTH -> { drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) - textWidth / 2, RENDER_GRID + textHeight / 3, 0, blockText); } case SOUTH -> { drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) + textWidth / 2, RENDER_GRID - textHeight / 3, 180, blockText); } } // reset to the original font newFont = currentFont.deriveFont(currentFont.getSize() * 1.0F); g2d.setFont(newFont); } } @Override public Rectangle getTileBounds() { int multiplier = (model.isScaleImage() ? 1 : 10); Orientation tileOrientation = model.getTileOrienation(); int xx, yy; if (tileOrientation == Orientation.EAST || tileOrientation == Orientation.WEST) { xx = tileX - GRID * multiplier - GRID * multiplier * 2; yy = tileY - GRID * multiplier; } else { xx = tileX - GRID * multiplier; yy = tileY - GRID * multiplier - GRID * multiplier * 2; } if (model.isScaleImage()) { return new Rectangle(xx, yy, tileWidth(tileOrientation, TileType.BLOCK), tileHeight(tileOrientation, TileType.BLOCK)); } else { return new Rectangle(xx, yy, renderWidth, renderHeight); } } @Override protected void paintComponent(Graphics g) { long started = System.currentTimeMillis(); Graphics2D g2 = (Graphics2D) g.create(); drawTile(g2); g2.dispose(); if (model.isOverlayImage()) { overlayLocImage(); } g.drawImage(tileImage, 0, 0, null); long now = System.currentTimeMillis(); Logger.trace(id + " Duration: " + (now - started) + " ms."); } @Override protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { //A block has 2 alternate points //1st square //2nd square holds the centerpoint //3rd square Orientation tileOrientation = model.getTileOrienation(); double dX1, dX2, dX3, dY1, dY2, dY3; if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { dX1 = renderWidth / 3 / 2 - size / 2 / 2; dY1 = renderHeight / 2 - size / 2 / 2; dX2 = renderWidth / 2 - size / 2; dY2 = renderHeight / 2 - size / 2; dX3 = renderWidth - renderWidth / 3 / 2 - size / 2 / 2; dY3 = renderHeight / 2 - size / 2 / 2; } else { dX1 = renderWidth / 2 - size / 2 / 2; dY1 = renderHeight / 3 / 2 - size / 2 / 2; dX2 = renderHeight / 2 - size / 2; dY2 = renderWidth / 2 - size / 2; dY3 = renderWidth / 2 - size / 2 / 2; dX3 = renderHeight - renderHeight / 3 / 2 - size / 2 / 2; } g2d.setColor(color); g2d.fill(new Ellipse2D.Double(dX1, dY1, size / 2, size / 2)); g2d.fill(new Ellipse2D.Double(dX2, dY2, size, size)); g2d.fill(new Ellipse2D.Double(dX3, dY3, size / 2, size / 2)); } } \ No newline at end of file +/* + * Copyright 2024 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles; + +import java.awt.Dimension; +import java.awt.Point; +import java.awt.Rectangle; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import javax.swing.UIManager; +import jcs.entities.LocomotiveBean; +import jcs.entities.TileBean; +import jcs.entities.TileBean.Orientation; +import static jcs.entities.TileBean.Orientation.EAST; +import static jcs.entities.TileBean.Orientation.NORTH; +import static jcs.entities.TileBean.Orientation.SOUTH; +import static jcs.entities.TileBean.Orientation.WEST; +import jcs.entities.TileBean.TileType; +import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; +import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; +import static jcs.ui.layout.tiles.Tile.GRID; +import jcs.ui.layout.tiles.ui.StraightUI; +import jcs.ui.layout.tiles.ui.TileUI; + +public class Block extends Tile { + + public static final int BLOCK_WIDTH = DEFAULT_WIDTH * 3; + public static final int BLOCK_HEIGHT = DEFAULT_HEIGHT * 3; + + public Block(TileBean tileBean) { + super(tileBean); + setModel(new DefaultTileModel(tileBean.getOrientation())); + //changeRenderSize(); + + populateModel(); + initUI(); + } + + public Block(Orientation orientation, Point center) { + this(orientation, center.x, center.y); + } + + public Block(Orientation orientation, int x, int y) { + this(orientation, x, y, tileWidth(orientation, TileType.BLOCK), tileHeight(orientation, TileType.BLOCK)); + } + + public Block(Orientation orientation, int x, int y, int width, int height) { + super(TileType.BLOCK, orientation, x, y, width, height); + setModel(new DefaultTileModel(orientation)); + //changeRenderSize(); + initUI(); + } + + private void initUI() { + updateUI(); + } + + @Override + public String getUIClassID() { + return StraightUI.UI_CLASS_ID; + } + + @Override + public void updateUI() { + UIManager.put(TileUI.UI_CLASS_ID, "jcs.ui.layout.tiles.ui.BlockUI"); + setUI((TileUI) UIManager.getUI(this)); + invalidate(); + } + +// private void changeRenderSize() { +// Orientation tileOrientation = model.getTileOrienation(); +// if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { +// this.renderWidth = RENDER_WIDTH * 3; +// this.renderHeight = RENDER_HEIGHT; +// } else { +// this.renderWidth = RENDER_WIDTH; +// this.renderHeight = RENDER_HEIGHT * 3; +// } +// } + @Override + public Set getAltPoints() { + int xx = this.tileX; + int yy = this.tileY; + Set alternatives = new HashSet<>(); + + if (Orientation.EAST.equals(getOrientation()) || Orientation.WEST.equals(getOrientation())) { + // West + Point wp = new Point((xx - DEFAULT_WIDTH), yy); + Point ep = new Point((xx + DEFAULT_WIDTH), yy); + alternatives.add(wp); + alternatives.add(ep); + } else { + Point np = new Point(xx, (yy - DEFAULT_HEIGHT)); + Point sp = new Point(xx, (yy + DEFAULT_HEIGHT)); + alternatives.add(np); + alternatives.add(sp); + } + + return alternatives; + } + + @Override + public Set getAllPoints() { + Set aps = new HashSet<>(); + aps.add(getCenter()); + aps.addAll(getAltPoints()); + return aps; + } + + @Override + Set getAllPoints(Point center) { + Set points = getAltPoints(center); + points.add(center); + return points; + } + + @Override + Set getAltPoints(Point center) { + Set alts = new HashSet<>(); + + if (Orientation.EAST == model.getTileOrienation() || Orientation.WEST == model.getTileOrienation()) { + // West + Point wp = new Point((center.x - DEFAULT_WIDTH), center.y); + Point ep = new Point((center.x + DEFAULT_WIDTH), center.y); + alts.add(wp); + alts.add(ep); + } else { + Point np = new Point(center.x, (center.y - DEFAULT_HEIGHT)); + Point sp = new Point(center.x, (center.y + DEFAULT_HEIGHT)); + alts.add(np); + alts.add(sp); + } + + return alts; + } + + public Point getAltPoint(String suffix) { + int cx = this.getCenterX(); + int cy = this.getCenterY(); + if ("+".equals(suffix)) { + return switch (this.getOrientation()) { + case WEST -> + new Point(cx - Tile.GRID * 2, cy); + case NORTH -> + new Point(cx, cy - Tile.GRID * 2); + case SOUTH -> + new Point(cx, cy + Tile.GRID * 2); + default -> + new Point(cx + Tile.GRID * 2, cy); + }; + } else { + return switch (this.getOrientation()) { + case EAST -> + new Point(cx - Tile.GRID * 2, cy); + case SOUTH -> + new Point(cx, cy - Tile.GRID * 2); + case NORTH -> + new Point(cx, cy + Tile.GRID * 2); + default -> + new Point(cx + Tile.GRID * 2, cy); + }; + } + } + + @Override + public boolean isBlock() { + return true; + } + + @Override + public Map getNeighborPoints() { + Map neighbors = new HashMap<>(); + Orientation orientation = this.getOrientation(); + int cx = this.getCenterX(); + int cy = this.getCenterY(); + + // Horizontal + if (Orientation.EAST == orientation || Orientation.WEST == orientation) { + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 4, cy)); + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 4, cy)); + } else { + // Vertical + neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 4)); + neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 4)); + } + return neighbors; + } + + @Override + public Map getEdgePoints() { + Map edgeConnections = new HashMap<>(); + Orientation orientation = this.getOrientation(); + int cx = this.getCenterX(); + int cy = this.getCenterY(); + + // Horizontal + if (Orientation.EAST == orientation || Orientation.WEST == orientation) { + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID * 3, cy)); + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID * 3, cy)); + } else { + // Vertical + edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 3)); + edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 3)); + } + return edgeConnections; + } + + public Point getNeighborPoint(String suffix) { + int cx = getCenterX(); + int cy = getCenterY(); + if ("+".equals(suffix)) { + return switch (getOrientation()) { + case WEST -> + new Point(cx - Tile.GRID * 4, cy); + case NORTH -> + new Point(cx, cy - Tile.GRID * 4); + case SOUTH -> + new Point(cx, cy + Tile.GRID * 4); + default -> + new Point(cx + Tile.GRID * 4, cy); + }; + } else { + return switch (getOrientation()) { + case EAST -> + new Point(cx - Tile.GRID * 4, cy); + case SOUTH -> + new Point(cx, cy - Tile.GRID * 4); + case NORTH -> + new Point(cx, cy + Tile.GRID * 4); + default -> + new Point(cx + Tile.GRID * 4, cy); + }; + } + } + + public Orientation getTravelDirection(String suffix) { + if ("+".equals(suffix)) { + return getOrientation(); + } else { + return switch (getOrientation()) { + case EAST -> + Orientation.WEST; + case SOUTH -> + Orientation.NORTH; + case NORTH -> + Orientation.SOUTH; + default -> + Orientation.EAST; + }; + } + } + + @Override + public String getIdSuffix(Tile other) { + String suffix = null; + Orientation match = null; + if (isAdjacent(other)) { + Map blockSides = this.getEdgePoints(); + Map otherSides = other.getEdgePoints(); + + for (Orientation bo : Orientation.values()) { + Point bp = blockSides.get(bo); + + if (bp != null) { + for (Orientation oo : Orientation.values()) { + Point op = otherSides.get(oo); + if (op != null) { + if (op.equals(bp)) { + match = bo; + break; + } + } + } + } + } + } + + Orientation tileOrientation = model.getTileOrienation(); + if (match != null) { + if (Orientation.EAST == tileOrientation && Orientation.EAST == match) { + suffix = "+"; + } + if (Orientation.WEST == tileOrientation && Orientation.WEST == match) { + suffix = "+"; + } + if (Orientation.EAST == tileOrientation && Orientation.WEST == match) { + suffix = "-"; + } + if (Orientation.WEST == tileOrientation && Orientation.EAST == match) { + suffix = "-"; + } + if (Orientation.NORTH == tileOrientation && Orientation.NORTH == match) { + suffix = "+"; + } + if (Orientation.NORTH == tileOrientation && Orientation.SOUTH == match) { + suffix = "-"; + } + if (Orientation.SOUTH == tileOrientation && Orientation.SOUTH == match) { + suffix = "+"; + } + if (Orientation.SOUTH == tileOrientation && Orientation.NORTH == match) { + suffix = "-"; + } + } + return suffix; + } + + @Override + public Orientation rotate() { + super.rotate(); + + Orientation tileOrientation = model.getTileOrienation(); + int w = tileWidth(tileOrientation, TileType.BLOCK); + int h = tileHeight(tileOrientation, TileType.BLOCK); + + Dimension d = new Dimension(w, h); + setPreferredSize(d); + setSize(d); + //changeRenderSize(); + + setBounds(getTileBounds()); + return model.getTileOrienation(); + } + + /** + * Depending on the block status change the background color
+ * - Red: Occupied
+ * - Green: Departure
+ * - Magenta: Arrival / entering
+ * - Yellow: reserved
+ * - White: all clear / default
+ * + * @return the Color which belong with the current Block State + */ +// Color getBlockStateColor() { +// return getBlockStateColor(this.model.getBlockState()); +// } +// protected Color getBlockStateColor(BlockState blockState) { +// return switch (blockState) { +// case GHOST -> +// new Color(250, 0, 0); +// case LOCKED -> +// new Color(250, 250, 210); +// case OCCUPIED -> +// new Color(250, 210, 210); +// case OUT_OF_ORDER -> +// new Color(190, 190, 190); +// case OUTBOUND -> +// new Color(210, 250, 210); +// case INBOUND -> +// new Color(250, 210, 250); +// default -> +// new Color(255, 255, 255); +// }; +// } + public static String getDepartureSuffix(Orientation tileOrientation, boolean reverseArrival, LocomotiveBean.Direction direction) { + if (LocomotiveBean.Direction.FORWARDS == direction) { + if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { + if (reverseArrival) { + return "-"; + } else { + return "+"; + } + } else { + if (reverseArrival) { + return "+"; + } else { + return "-"; + } + } + } else { + if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { + if (reverseArrival) { + return "+"; + } else { + return "-"; + } + } else { + if (reverseArrival) { + return "-"; + } else { + return "+"; + } + } + } + } + +// @Override +// public void renderTile(Graphics2D g2) { +// int xx = 20; +// int yy = 50; +// int rw = RENDER_WIDTH * 3 - 40; +// int rh = 300; +// +// g2.setStroke(new BasicStroke(3, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); +// +// g2.setPaint(Color.darkGray); +// g2.drawRoundRect(xx, yy, rw, rh, 15, 15); +// +// Color blockStateColor = getBlockStateColor(); +// //Logger.trace("Block " + this.id + " State: " + this.getBlockBean().getBlockState().getState() + " Color: " + blockStateColor.toString()); +// g2.setPaint(blockStateColor); +// g2.fillRoundRect(xx, yy, rw, rh, 15, 15); +// +// g2.setStroke(new BasicStroke(20, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); +// g2.setPaint(Color.darkGray); +// g2.drawLine(rw + GRID, yy - 0, rw + GRID, yy + 300); +// +// //When there is a locomotive in the block mark the direction of travel. +// //The default, forwards is in the direction of the block orientation, i.e. the + +// if (model.getLocomotive() != null && model.getLocomotive().getName() != null) { +// renderDirectionArrow(g2); +// } +// +// drawName(g2); +// } +// private void renderDirectionArrow(Graphics2D g2) { +// //The default, forwards is in the direction of the block orientation, i.e. the + +// Orientation tileOrientation = model.getTileOrienation(); +// BlockBean bb = this.getBlockBean(); +// boolean reverseArrival = model.isReverseArrival(); +// +// LocomotiveBean.Direction logicalDirection; +// if (bb.getLogicalDirection() != null) { +// logicalDirection = model.getLogicalDirection(); +// } else { +// logicalDirection = model.getLocomotive().getDirection(); +// } +// +// String departureSuffix = model.getDepartureSuffix(); +// if (departureSuffix == null) { +// departureSuffix = Block.getDepartureSuffix(tileOrientation, reverseArrival, logicalDirection); +// } +// +// //Logger.trace(this.getId()+" LogicalDirection is " + (bb.getLogicalDirection() != null ? "Set" : "Not Set") + " Dir: " + logicalDirection.getDirection() + " Orientation: " + orientation.getOrientation() + " departureSuffix: " + departureSuffix); +// if ("+".equals(departureSuffix)) { +// if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { +// switch (logicalDirection) { +// case LocomotiveBean.Direction.FORWARDS -> { +// if (reverseArrival) { +// renderLeftArrow(g2); +// } else { +// renderRightArrow(g2); +// } +// } +// case LocomotiveBean.Direction.BACKWARDS -> { +// if (reverseArrival) { +// renderRightArrow(g2); +// } else { +// renderLeftArrow(g2); +// } +// } +// } +// } else { +// switch (logicalDirection) { +// case LocomotiveBean.Direction.BACKWARDS -> { +// if (reverseArrival) { +// renderLeftArrow(g2); +// } else { +// renderRightArrow(g2); +// } +// } +// case LocomotiveBean.Direction.FORWARDS -> { +// if (reverseArrival) { +// renderRightArrow(g2); +// } else { +// renderLeftArrow(g2); +// } +// } +// } +// } +// } else { +// if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { +// switch (logicalDirection) { +// case LocomotiveBean.Direction.FORWARDS -> { +// if (reverseArrival) { +// renderLeftArrow(g2); +// } else { +// renderRightArrow(g2); +// } +// } +// case LocomotiveBean.Direction.BACKWARDS -> { +// if (reverseArrival) { +// renderRightArrow(g2); +// } else { +// renderLeftArrow(g2); +// } +// } +// } +// } else { +// switch (logicalDirection) { +// case LocomotiveBean.Direction.BACKWARDS -> { +// if (reverseArrival) { +// renderLeftArrow(g2); +// } else { +// renderRightArrow(g2); +// } +// } +// case LocomotiveBean.Direction.FORWARDS -> { +// if (reverseArrival) { +// renderRightArrow(g2); +// } else { +// renderLeftArrow(g2); +// } +// } +// } +// } +// } +// } +// private void renderLeftArrow(Graphics2D g2) { +// //Logger.trace(this.getId()+" LogicalDirection is " + this.getBlockBean().getLogicalDirection() + " Orientation: " + this.getOrientation() + " departureSuffix: " + this.getBlockBean().getDepartureSuffix()); +// g2.fillPolygon(new int[]{0, 50, 50,}, new int[]{200, 150, 250}, 3); +// } +// private void renderRightArrow(Graphics2D g2) { +// //Logger.trace(this.getId()+" LogicalDirection is " + this.getBlockBean().getLogicalDirection() + " Orientation: " + this.getOrientation() + " departureSuffix: " + this.getBlockBean().getDepartureSuffix()); +// g2.fillPolygon(new int[]{1180, 1130, 1130,}, new int[]{200, 150, 250}, 3); +// } +// @Override +// public void renderTileRoute(Graphics2D g2d) { +// if (model.isShowBlockState()) { +// backgroundColor = getBlockStateColor(model.getBlockState()); +// } +// } +// protected void overlayLocImage() { +// int ww = tileImage.getWidth(); +// int hh = tileImage.getHeight(); +// Orientation tileOrientation = model.getTileOrienation(); +// +// BufferedImage overlay = new BufferedImage(ww, hh, BufferedImage.TYPE_INT_ARGB); +// Graphics2D g2i = overlay.createGraphics(); +// +// Image locImage = getLocImage(); +// if (locImage != null) { +// String departureSuffix = model.getDepartureSuffix(); +// boolean reverseImage = model.isReverseArrival(); +// +// Logger.trace("LocImage w: " + locImage.getWidth(null) + " h: " + locImage.getHeight(null)); +// // scale it to max h of 45 +// int size = 45; +// float aspect = (float) locImage.getHeight(null) / (float) locImage.getWidth(null); +// //TODO: Use Scalr? +// locImage = locImage.getScaledInstance(size, (int) (size * aspect), Image.SCALE_SMOOTH); +// +// //Depending on the block orientation the image needs to be rotated and flipped +// //Incase the departure suffix is NOT set center the locomotive image +// int w, h, xx, yy; +// switch (tileOrientation) { +// case WEST -> { +// w = locImage.getWidth(null); +// h = locImage.getHeight(null); +// +// if (null == departureSuffix) { +// xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w; +// } else { +// switch (departureSuffix) { +// case "+" -> { +// xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w - 25; +// } +// default -> { +// xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w + 10; +// } +// } +// } +// yy = DEFAULT_HEIGHT / 2 - h / 2; +// +// if (reverseImage) { +// locImage = ImageUtil.flipVertically(locImage); +// } +// } +// case SOUTH -> { +// locImage = ImageUtil.flipHorizontally(locImage); +// locImage = ImageUtil.rotate(locImage, 90); +// +// w = locImage.getWidth(null); +// h = locImage.getHeight(null); +// xx = DEFAULT_WIDTH / 2 - w / 2; +// +// if (null == departureSuffix) { +// yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h; +// } else { +// switch (departureSuffix) { +// case "-" -> { +// yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h - 25; +// } +// default -> { +// yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h + 10; +// } +// } +// } +// if (reverseImage) { +// locImage = ImageUtil.flipHorizontally(locImage); +// } +// } +// case NORTH -> { +// locImage = ImageUtil.flipHorizontally(locImage); +// locImage = ImageUtil.rotate(locImage, 90); +// +// w = locImage.getWidth(null); +// h = locImage.getHeight(null); +// xx = DEFAULT_WIDTH / 2 - w / 2; +// +// if (null == departureSuffix) { +// int minY = BLOCK_HEIGHT / 2 - getHeight() / 2 + h; +// yy = minY; +// } else { +// switch (departureSuffix) { +// case "+" -> { +// yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h - 25; +// } +// default -> { +// yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h + 10; +// } +// } +// } +// if (reverseImage) { +// locImage = ImageUtil.flipHorizontally(locImage); +// } +// } +// default -> { +// w = locImage.getWidth(null); +// h = locImage.getHeight(null); +// if (null == departureSuffix) { +// xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w; +// } else { +// switch (departureSuffix) { +// case "-" -> { +// xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w - 25; +// } +// default -> { +// xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w + 10; +// } +// } +// } +// yy = DEFAULT_HEIGHT / 2 - h / 2; +// +// if (reverseImage) { +// locImage = ImageUtil.flipVertically(locImage); +// } +// } +// } +// +// g2i.drawImage(tileImage, 0, 0, null); +// g2i.drawImage(locImage, xx, yy, null); +// g2i.dispose(); +// tileImage = overlay; +// } +// } +// private Image getLocImage() { +// if (model.getLocomotive() != null && model.getLocomotive().getLocIcon() != null) { +// return model.getLocomotive().getLocIcon(); +// } else { +// return null; +// } +// } +// public String getBlockText() { +// String blockText; +// if (blockBean != null && blockBean.getDescription() != null) { +// if (blockBean.getLocomotive() != null && blockBean.getLocomotive().getName() != null && BlockState.GHOST != blockBean.getBlockState()) { +// blockText = blockBean.getLocomotive().getName(); +// } else { +// if (blockBean.getDescription().length() > 0) { +// blockText = blockBean.getDescription(); +// } else { +// blockText = getId(); +// } +// } +// } else { +// // Design mode show description when available +// if (blockBean != null && blockBean.getDescription() != null && blockBean.getDescription().length() > 0) { +// blockText = blockBean.getDescription(); +// } else { +// blockText = getId(); +// } +// } +// return blockText; +// } +// @Override +// public void drawName(Graphics2D g2d) { +// if (!model.isOverlayImage()) { +// g2d.setPaint(Color.black); +// +// Font currentFont = g2d.getFont(); +// Font newFont = currentFont.deriveFont(currentFont.getSize() * 10.0F); +// g2d.setFont(newFont); +// +// String blockText = getBlockText(); +// +// // Scale the text if necessary +// int textWidth = g2d.getFontMetrics().stringWidth(blockText); +// double fontscale = 10.0; +// if (textWidth > 845) { +// fontscale = fontscale * 847.0 / textWidth; +// newFont = currentFont.deriveFont(currentFont.getSize() * (float) fontscale); +// g2d.setFont(newFont); +// textWidth = g2d.getFontMetrics().stringWidth(blockText); +// } +// +// int textHeight = g2d.getFontMetrics().getHeight(); +// Orientation tileOrientation = model.getTileOrienation(); +// +// switch (tileOrientation) { +// case EAST -> { +// drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) - textWidth / 2, RENDER_GRID + textHeight / 3, 0, blockText); +// } +// case WEST -> { +// drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) + textWidth / 2, RENDER_GRID - textHeight / 3, 180, blockText); +// } +// case NORTH -> { +// drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) - textWidth / 2, RENDER_GRID + textHeight / 3, 0, blockText); +// } +// case SOUTH -> { +// drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) + textWidth / 2, RENDER_GRID - textHeight / 3, 180, blockText); +// } +// } +// // reset to the original font +// newFont = currentFont.deriveFont(currentFont.getSize() * 1.0F); +// g2d.setFont(newFont); +// } +// } + @Override + public Rectangle getTileBounds() { + int multiplier = (model.isScaleImage() ? 1 : 10); + Orientation tileOrientation = model.getTileOrienation(); + + int xx, yy; + if (tileOrientation == Orientation.EAST || tileOrientation == Orientation.WEST) { + xx = tileX - GRID * multiplier - GRID * multiplier * 2; + yy = tileY - GRID * multiplier; + } else { + xx = tileX - GRID * multiplier; + yy = tileY - GRID * multiplier - GRID * multiplier * 2; + } + + if (model.isScaleImage()) { + return new Rectangle(xx, yy, tileWidth(tileOrientation, TileType.BLOCK), tileHeight(tileOrientation, TileType.BLOCK)); + } else { + int renderWidth = getUI().getRenderWidth(); + int renderHeight = getUI().getRenderHeight(); + + return new Rectangle(xx, yy, renderWidth, renderHeight); + } + } + +// @Override +// protected void paintComponent(Graphics g) { +// long started = System.currentTimeMillis(); +// +// Graphics2D g2 = (Graphics2D) g.create(); +// drawTile(g2); +// g2.dispose(); +// +// if (model.isOverlayImage()) { +// overlayLocImage(); +// } +// +// g.drawImage(tileImage, 0, 0, null); +// long now = System.currentTimeMillis(); +// Logger.trace(id + " Duration: " + (now - started) + " ms."); +// } +// @Override +// protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { +// //A block has 2 alternate points +// //1st square +// //2nd square holds the centerpoint +// //3rd square +// Orientation tileOrientation = model.getTileOrienation(); +// double dX1, dX2, dX3, dY1, dY2, dY3; +// if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { +// dX1 = renderWidth / 3 / 2 - size / 2 / 2; +// dY1 = renderHeight / 2 - size / 2 / 2; +// dX2 = renderWidth / 2 - size / 2; +// dY2 = renderHeight / 2 - size / 2; +// dX3 = renderWidth - renderWidth / 3 / 2 - size / 2 / 2; +// dY3 = renderHeight / 2 - size / 2 / 2; +// } else { +// dX1 = renderWidth / 2 - size / 2 / 2; +// dY1 = renderHeight / 3 / 2 - size / 2 / 2; +// dX2 = renderHeight / 2 - size / 2; +// dY2 = renderWidth / 2 - size / 2; +// dY3 = renderWidth / 2 - size / 2 / 2; +// dX3 = renderHeight - renderHeight / 3 / 2 - size / 2 / 2; +// } +// +// g2d.setColor(color); +// g2d.fill(new Ellipse2D.Double(dX1, dY1, size / 2, size / 2)); +// g2d.fill(new Ellipse2D.Double(dX2, dY2, size, size)); +// g2d.fill(new Ellipse2D.Double(dX3, dY3, size / 2, size / 2)); +// } +} diff --git a/src/main/java/jcs/ui/layout/tiles/Cross.java b/src/main/java/jcs/ui/layout/tiles/Cross.java index 419a693f..33b902f0 100644 --- a/src/main/java/jcs/ui/layout/tiles/Cross.java +++ b/src/main/java/jcs/ui/layout/tiles/Cross.java @@ -1 +1,697 @@ -/* * Copyright 2023 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.geom.Ellipse2D; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import jcs.entities.AccessoryBean.AccessoryValue; import static jcs.entities.AccessoryBean.AccessoryValue.GREEN; import static jcs.entities.AccessoryBean.AccessoryValue.RED; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; import static jcs.ui.layout.tiles.Tile.GRID; import static jcs.ui.layout.tiles.Tile.tileHeight; import static jcs.ui.layout.tiles.Tile.tileWidth; public class Cross extends Switch { public static final int CROSS_WIDTH = DEFAULT_WIDTH * 2; public static final int CROSS_HEIGHT = DEFAULT_HEIGHT * 2; public static final Color VERY_LIGHT_RED = new Color(255, 102, 102); public static final Color LIGHT_RED = new Color(255, 51, 51); public static final Color DARK_RED = new Color(204, 0, 0); public static final Color VERY_LIGHT_GREEN = new Color(102, 255, 102); public static final Color LIGHT_GREEN = new Color(0, 255, 51); public static final Color DARK_GREEN = new Color(0, 153, 0); public Cross(Orientation orientation, Direction direction, Point center) { this(orientation, direction, center.x, center.y); } public Cross(Orientation orientation, Direction direction, int x, int y) { this(orientation, direction, x, y, tileWidth(orientation, TileType.CROSS), tileHeight(orientation, TileType.CROSS)); } public Cross(Orientation orientation, Direction direction, int x, int y, int width, int height) { super(TileType.CROSS, orientation, direction, x, y, width, height); changeRenderSizeAndOffsets(); } public Cross(TileBean tileBean) { super(tileBean, tileWidth(tileBean.getOrientation(), TileType.CROSS), tileHeight(tileBean.getOrientation(), TileType.CROSS)); changeRenderSizeAndOffsets(); } /** * A Cross has a width in horizontal position of 2 tiles and a height of 1 tile in Vertical position.
* * @return the Set of points which mark the position of the Cross */ @Override public Set getAltPoints() { return getAltPoints(getCenter()); } @Override public Set getAllPoints() { return getAllPoints(getCenter()); } @Override public Set getAllPoints(Point center) { Set aps = getAltPoints(center); aps.add(center); return aps; } @Override Set getAltPoints(Point center) { Set alts = new HashSet<>(); switch (getOrientation()) { case SOUTH -> { Point sp = new Point(center.x, (center.y + DEFAULT_HEIGHT)); alts.add(sp); } case WEST -> { Point wp = new Point((center.x - DEFAULT_WIDTH), center.y); alts.add(wp); } case NORTH -> { Point np = new Point(center.x, (center.y - DEFAULT_HEIGHT)); alts.add(np); } default -> { //East so default Point ep = new Point((center.x + DEFAULT_WIDTH), center.y); alts.add(ep); } } return alts; } @Override public Map getNeighborPoints() { Map neighbors = new HashMap<>(); Orientation orientation = this.getOrientation(); Direction direction = this.getDirection(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 4)); if (Direction.LEFT == direction) { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy + Tile.GRID * 2)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); } else { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy + Tile.GRID * 2)); } } case WEST -> { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 4, cy)); if (Direction.LEFT == direction) { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx - Tile.GRID * 2, cy + Tile.GRID * 2)); } else { neighbors.put(Orientation.NORTH, new Point(cx - Tile.GRID * 2, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); } } case NORTH -> { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 4)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); if (Direction.LEFT == direction) { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy - Tile.GRID * 2)); } else { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy - Tile.GRID * 2)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); } } default -> { //EAST neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 4, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); if (Direction.LEFT == direction) { neighbors.put(Orientation.NORTH, new Point(cx + Tile.GRID * 2, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); } else { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx + Tile.GRID * 2, cy + Tile.GRID * 2)); } } } return neighbors; } @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); Orientation orientation = this.getOrientation(); Direction direction = this.getDirection(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 3)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy + Tile.GRID * 2)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); } else { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy + Tile.GRID * 2)); } } case WEST -> { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID * 3, cy)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx - Tile.GRID * 2, cy + Tile.GRID)); } else { edgeConnections.put(Orientation.NORTH, new Point(cx - Tile.GRID * 2, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); } } case NORTH -> { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 3)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy - Tile.GRID * 2)); } else { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy - Tile.GRID * 2)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); } } default -> { //EAST edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID * 3, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.NORTH, new Point(cx + Tile.GRID * 2, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); } else { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx + Tile.GRID * 2, cy + Tile.GRID)); } } } return edgeConnections; } @Override protected void renderStraight(Graphics2D g2, Color color) { int xx, yy, w, h; xx = 0; yy = 170; w = RENDER_WIDTH; h = 60; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } @Override protected void renderRouteStraight(Graphics2D g2, Color color) { int xx, yy, w, h; xx = 0; yy = 190; w = RENDER_WIDTH; h = 20; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } protected void renderStraight2(Graphics2D g2, Color color) { int xx, yy, w, h; xx = RENDER_WIDTH; yy = 170; w = RENDER_WIDTH; h = 60; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } protected void renderRouteStraight2(Graphics2D g2, Color color) { int xx, yy, w, h; xx = RENDER_WIDTH; yy = 190; w = RENDER_WIDTH; h = 20; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } @Override protected void renderDiagonal(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{400, 400, 167, 230}; yPoints = new int[]{170, 230, 0, 0}; } else { xPoints = new int[]{400, 400, 170, 230}; yPoints = new int[]{230, 170, 400, 400}; } g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillPolygon(xPoints, yPoints, xPoints.length); } @Override protected void renderRouteDiagonal(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{420, 400, 190, 210}; yPoints = new int[]{210, 210, 0, 0}; } else { xPoints = new int[]{400, 400, 190, 210}; yPoints = new int[]{210, 190, 400, 400}; } g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillPolygon(xPoints, yPoints, xPoints.length); } protected void renderDiagonal2(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{400, 400, 570, 630}; yPoints = new int[]{170, 230, 400, 400}; } else { xPoints = new int[]{400, 400, 570, 630}; yPoints = new int[]{230, 170, 0, 0}; } g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillPolygon(xPoints, yPoints, xPoints.length); } protected void renderRouteDiagonal2(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{400, 380, 590, 610}; yPoints = new int[]{190, 190, 400, 400}; } else { xPoints = new int[]{400, 380, 590, 610}; yPoints = new int[]{210, 210, 0, 0}; } g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.setPaint(Color.cyan); g2.fillPolygon(xPoints, yPoints, xPoints.length); } @Override public void renderTile(Graphics2D g2) { if (accessoryValue == null) { this.accessoryValue = AccessoryValue.OFF; } switch (accessoryValue) { case RED -> { renderStraight2(g2, Cross.LIGHT_RED); renderDiagonal(g2, Cross.LIGHT_RED); renderStraight(g2, Cross.DARK_RED); renderDiagonal2(g2, Cross.DARK_RED); } case GREEN -> { renderDiagonal(g2, Cross.VERY_LIGHT_GREEN); renderDiagonal2(g2, Cross.VERY_LIGHT_GREEN); renderStraight(g2, Cross.DARK_GREEN); renderStraight2(g2, Cross.DARK_GREEN); } default -> { renderStraight(g2, trackColor); renderStraight2(g2, trackColor); renderDiagonal(g2, trackColor); renderDiagonal2(g2, trackColor); } } } @Override public void renderTileRoute(Graphics2D g2) { if (routeValue == null) { routeValue = AccessoryValue.OFF; } if (incomingSide == null) { incomingSide = getOrientation(); } if (isHorizontal()) { if (AccessoryValue.GREEN == routeValue && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteDiagonal(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (AccessoryValue.GREEN == routeValue && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteStraight2(g2, trackRouteColor); } else if (AccessoryValue.RED == routeValue && Orientation.EAST == getOrientation()) { if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight2(g2, trackRouteColor); renderRouteDiagonal(g2, trackRouteColor); } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteDiagonal2(g2, trackRouteColor); renderRouteStraight(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight2(g2, trackRouteColor); renderRouteDiagonal(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight(g2, trackColor); renderRouteDiagonal2(g2, trackColor); } } else if (AccessoryValue.RED == routeValue && Orientation.WEST == getOrientation()) { if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteDiagonal(g2, trackRouteColor); renderRouteStraight2(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight2(g2, trackColor); renderRouteDiagonal(g2, trackColor); } } } else { if (AccessoryValue.GREEN == routeValue && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteStraight2(g2, trackRouteColor); } else if (AccessoryValue.GREEN == routeValue && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { renderRouteDiagonal(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (AccessoryValue.RED == routeValue && Orientation.SOUTH == getOrientation()) { if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight2(g2, trackRouteColor); renderRouteDiagonal(g2, trackRouteColor); } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteDiagonal2(g2, trackRouteColor); renderRouteStraight(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight2(g2, trackColor); renderRouteDiagonal(g2, trackColor); } } else if (AccessoryValue.RED == routeValue && Orientation.NORTH == getOrientation()) { if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteDiagonal(g2, trackRouteColor); renderRouteStraight2(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight2(g2, trackRouteColor); renderRouteDiagonal(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight(g2, trackColor); renderRouteDiagonal2(g2, trackColor); } } } } @Override public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { if (from != null && to != null && this.getDirection() != null) { switch (this.getDirection()) { case LEFT -> { if (this.isHorizontal()) { if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.NORTH)) { return AccessoryValue.RED; } else if ((from == Orientation.EAST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.EAST)) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } else { //Vertical if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if ((from == Orientation.SOUTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.SOUTH)) { return AccessoryValue.RED; } else if ((from == Orientation.EAST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.EAST)) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } } case RIGHT -> { if (this.isHorizontal()) { if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.NORTH)) { return AccessoryValue.RED; } else if ((from == Orientation.WEST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.WEST)) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } else { //Vertical if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if ((from == Orientation.SOUTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.SOUTH)) { return AccessoryValue.RED; } else if ((from == Orientation.WEST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.WEST)) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } } default -> { return AccessoryValue.OFF; } } } else { return AccessoryValue.OFF; } } @Override protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { //A Cross has 1 alternate point //1st square holds the centerpoint //2nd square double dX1, dX2, dY1, dY2; Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case SOUTH -> { dX1 = renderWidth / 2 - size / 2; dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; dX2 = renderWidth / 2 + renderWidth - size / 4; dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; } case WEST -> { dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; dY1 = renderHeight / 2 - size / 2; dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; dY2 = renderHeight / 2 - size / 4; } case NORTH -> { dX1 = renderWidth / 2 - size / 2; dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; dX2 = renderWidth / 2 + renderWidth - size / 4; dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; } default -> { //East dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; dY1 = renderHeight / 2 - size / 2; dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; dY2 = renderHeight / 2 - size / 4; } } g2d.setColor(color); g2d.fill(new Ellipse2D.Double(dX1, dY1, size, size)); g2d.fill(new Ellipse2D.Double(dX2, dY2, size / 2, size / 2)); } @Override public Rectangle getTileBounds() { Orientation tileOrientation = model.getTileOrienation(); int xx, yy, w, h, multiplier; if (model.isScaleImage()) { w = tileWidth(tileOrientation, TileType.CROSS); h = tileHeight(tileOrientation, TileType.CROSS); multiplier = 1; } else { w = renderWidth; h = renderHeight; multiplier = 10; } switch (tileOrientation) { case SOUTH -> { xx = tileX - GRID * multiplier; yy = tileY - GRID * multiplier; } case WEST -> { xx = tileX - GRID * multiplier - GRID * 2 * multiplier; yy = tileY - GRID * multiplier; } case NORTH -> { xx = tileX - GRID * multiplier; yy = tileY - GRID * multiplier - GRID * 2 * multiplier; } default -> { //East xx = tileX - GRID * multiplier; yy = tileY - GRID * multiplier; } } if (model.isScaleImage()) { return new Rectangle(xx, yy, w, h); } else { return new Rectangle(xx, yy, renderWidth, renderHeight); } } private void changeRenderSizeAndOffsets() { //Reset offsets this.offsetY = 0; this.renderOffsetY = 0; this.offsetX = 0; this.renderOffsetX = 0; if (isHorizontal()) { this.renderWidth = RENDER_GRID * 4; this.renderHeight = RENDER_GRID * 2; this.offsetY = 0; this.renderOffsetY = 0; } else { this.renderWidth = RENDER_GRID * 2; this.renderHeight = RENDER_GRID * 4; this.offsetX = 0; this.renderOffsetX = 0; } //Due to the asymetical shape (center is on the left) //the offset has to be changed with the rotation Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case SOUTH -> { this.offsetY = +GRID; this.renderOffsetY = RENDER_GRID; } case WEST -> { this.offsetX = -GRID; this.renderOffsetX = -RENDER_GRID; } case NORTH -> { this.offsetY = -GRID; this.renderOffsetY = -RENDER_GRID; } default -> { //East so default this.offsetX = +GRID; this.renderOffsetX = +RENDER_GRID; } } } @Override public Orientation rotate() { super.rotate(); Orientation tileOrientation = model.getTileOrienation(); int w = tileWidth(tileOrientation, TileType.CROSS); int h = tileHeight(tileOrientation, TileType.CROSS); Dimension d = new Dimension(w, h); setPreferredSize(d); setSize(d); changeRenderSizeAndOffsets(); setBounds(getTileBounds()); return tileOrientation; } } \ No newline at end of file +/* + * Copyright 2023 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Point; +import java.awt.Rectangle; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import javax.swing.UIManager; +import jcs.entities.AccessoryBean.AccessoryValue; +import jcs.entities.TileBean; +import jcs.entities.TileBean.Direction; +import jcs.entities.TileBean.Orientation; +import static jcs.entities.TileBean.Orientation.NORTH; +import static jcs.entities.TileBean.Orientation.SOUTH; +import static jcs.entities.TileBean.Orientation.WEST; +import jcs.entities.TileBean.TileType; +import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; +import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; +import static jcs.ui.layout.tiles.Tile.GRID; +import static jcs.ui.layout.tiles.Tile.tileHeight; +import static jcs.ui.layout.tiles.Tile.tileWidth; +import jcs.ui.layout.tiles.ui.CrossUI; +import jcs.ui.layout.tiles.ui.TileUI; + +public class Cross extends Switch { + + public static final int CROSS_WIDTH = DEFAULT_WIDTH * 2; + public static final int CROSS_HEIGHT = DEFAULT_HEIGHT * 2; + + public static final Color VERY_LIGHT_RED = new Color(255, 102, 102); + public static final Color LIGHT_RED = new Color(255, 51, 51); + public static final Color DARK_RED = new Color(204, 0, 0); + + public static final Color VERY_LIGHT_GREEN = new Color(102, 255, 102); + public static final Color LIGHT_GREEN = new Color(0, 255, 51); + public static final Color DARK_GREEN = new Color(0, 153, 0); + + public Cross(Orientation orientation, Direction direction, Point center) { + this(orientation, direction, center.x, center.y); + } + + public Cross(Orientation orientation, Direction direction, int x, int y) { + this(orientation, direction, x, y, tileWidth(orientation, TileType.CROSS), tileHeight(orientation, TileType.CROSS)); + } + + public Cross(Orientation orientation, Direction direction, int x, int y, int width, int height) { + super(TileType.CROSS, orientation, direction, x, y, width, height); + changeRenderSizeAndOffsets(); + } + + public Cross(TileBean tileBean) { + super(tileBean, tileWidth(tileBean.getOrientation(), TileType.CROSS), tileHeight(tileBean.getOrientation(), TileType.CROSS)); + changeRenderSizeAndOffsets(); + } + + @Override + public String getUIClassID() { + return CrossUI.UI_CLASS_ID; + } + + @Override + public void updateUI() { + UIManager.put(TileUI.UI_CLASS_ID, "jcs.ui.layout.tiles.ui.CrossUI"); + setUI((TileUI) UIManager.getUI(this)); + invalidate(); + } + + /** + * A Cross has a width in horizontal position of 2 tiles and a height of 1 tile in Vertical position.
+ * + * @return the Set of points which mark the position of the Cross + */ + @Override + public Set getAltPoints() { + return getAltPoints(getCenter()); + } + + @Override + public Set getAllPoints() { + return getAllPoints(getCenter()); + } + + @Override + public Set getAllPoints(Point center) { + Set aps = getAltPoints(center); + aps.add(center); + return aps; + } + + @Override + Set getAltPoints(Point center) { + Set alts = new HashSet<>(); + switch (getOrientation()) { + case SOUTH -> { + Point sp = new Point(center.x, (center.y + DEFAULT_HEIGHT)); + alts.add(sp); + } + case WEST -> { + Point wp = new Point((center.x - DEFAULT_WIDTH), center.y); + alts.add(wp); + } + case NORTH -> { + Point np = new Point(center.x, (center.y - DEFAULT_HEIGHT)); + alts.add(np); + } + default -> { + //East so default + Point ep = new Point((center.x + DEFAULT_WIDTH), center.y); + alts.add(ep); + } + } + return alts; + } + + @Override + public Map getNeighborPoints() { + Map neighbors = new HashMap<>(); + Orientation orientation = this.getOrientation(); + Direction direction = this.getDirection(); + int cx = this.getCenterX(); + int cy = this.getCenterY(); + + switch (orientation) { + case SOUTH -> { + neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); + neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 4)); + + if (Direction.LEFT == direction) { + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy + Tile.GRID * 2)); + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); + } else { + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy + Tile.GRID * 2)); + } + } + case WEST -> { + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 4, cy)); + + if (Direction.LEFT == direction) { + neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); + neighbors.put(Orientation.SOUTH, new Point(cx - Tile.GRID * 2, cy + Tile.GRID * 2)); + } else { + neighbors.put(Orientation.NORTH, new Point(cx - Tile.GRID * 2, cy - Tile.GRID * 2)); + neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); + } + } + case NORTH -> { + neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 4)); + neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); + + if (Direction.LEFT == direction) { + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy - Tile.GRID * 2)); + } else { + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy - Tile.GRID * 2)); + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); + } + } + default -> { + //EAST + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 4, cy)); + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); + + if (Direction.LEFT == direction) { + neighbors.put(Orientation.NORTH, new Point(cx + Tile.GRID * 2, cy - Tile.GRID * 2)); + neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); + } else { + neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); + neighbors.put(Orientation.SOUTH, new Point(cx + Tile.GRID * 2, cy + Tile.GRID * 2)); + } + } + } + return neighbors; + } + + @Override + public Map getEdgePoints() { + Map edgeConnections = new HashMap<>(); + Orientation orientation = getOrientation(); + Direction direction = getDirection(); + int cx = this.getCenterX(); + int cy = this.getCenterY(); + + switch (orientation) { + case SOUTH -> { + edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); + edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 3)); + + if (Direction.LEFT == direction) { + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy + Tile.GRID * 2)); + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); + } else { + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy + Tile.GRID * 2)); + } + } + case WEST -> { + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID * 3, cy)); + + if (Direction.LEFT == direction) { + edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); + edgeConnections.put(Orientation.SOUTH, new Point(cx - Tile.GRID * 2, cy + Tile.GRID)); + } else { + edgeConnections.put(Orientation.NORTH, new Point(cx - Tile.GRID * 2, cy - Tile.GRID)); + edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); + } + } + case NORTH -> { + edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 3)); + edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); + + if (Direction.LEFT == direction) { + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy - Tile.GRID * 2)); + } else { + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy - Tile.GRID * 2)); + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); + } + } + default -> { + //EAST + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID * 3, cy)); + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); + + if (Direction.LEFT == direction) { + edgeConnections.put(Orientation.NORTH, new Point(cx + Tile.GRID * 2, cy - Tile.GRID)); + edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); + } else { + edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); + edgeConnections.put(Orientation.SOUTH, new Point(cx + Tile.GRID * 2, cy + Tile.GRID)); + } + } + } + return edgeConnections; + } + +// @Override +// protected void renderStraight(Graphics2D g2, Color color) { +// int xx, yy, w, h; +// xx = 0; +// yy = 170; +// w = RENDER_WIDTH; +// h = 60; +// +// g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); +// g2.setPaint(color); +// g2.fillRect(xx, yy, w, h); +// } +// @Override +// protected void renderRouteStraight(Graphics2D g2, Color color) { +// int xx, yy, w, h; +// xx = 0; +// yy = 190; +// w = RENDER_WIDTH; +// h = 20; +// +// g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); +// g2.setPaint(color); +// g2.fillRect(xx, yy, w, h); +// } +// protected void renderStraight2(Graphics2D g2, Color color) { +// int xx, yy, w, h; +// xx = RENDER_WIDTH; +// yy = 170; +// w = RENDER_WIDTH; +// h = 60; +// +// g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); +// g2.setPaint(color); +// g2.fillRect(xx, yy, w, h); +// } +// protected void renderRouteStraight2(Graphics2D g2, Color color) { +// int xx, yy, w, h; +// xx = RENDER_WIDTH; +// yy = 190; +// w = RENDER_WIDTH; +// h = 20; +// +// g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); +// g2.setPaint(color); +// g2.fillRect(xx, yy, w, h); +// } +// @Override +// protected void renderDiagonal(Graphics2D g2, Color color) { +// int[] xPoints, yPoints; +// if (Direction.RIGHT.equals(getDirection())) { +// xPoints = new int[]{400, 400, 167, 230}; +// yPoints = new int[]{170, 230, 0, 0}; +// } else { +// xPoints = new int[]{400, 400, 170, 230}; +// yPoints = new int[]{230, 170, 400, 400}; +// } +// +// g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); +// g2.setPaint(color); +// g2.fillPolygon(xPoints, yPoints, xPoints.length); +// } +// @Override +// protected void renderRouteDiagonal(Graphics2D g2, Color color) { +// int[] xPoints, yPoints; +// if (Direction.RIGHT.equals(getDirection())) { +// xPoints = new int[]{420, 400, 190, 210}; +// yPoints = new int[]{210, 210, 0, 0}; +// } else { +// xPoints = new int[]{400, 400, 190, 210}; +// yPoints = new int[]{210, 190, 400, 400}; +// } +// +// g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); +// g2.setPaint(color); +// g2.fillPolygon(xPoints, yPoints, xPoints.length); +// } +// protected void renderDiagonal2(Graphics2D g2, Color color) { +// int[] xPoints, yPoints; +// if (Direction.RIGHT.equals(getDirection())) { +// xPoints = new int[]{400, 400, 570, 630}; +// yPoints = new int[]{170, 230, 400, 400}; +// } else { +// xPoints = new int[]{400, 400, 570, 630}; +// yPoints = new int[]{230, 170, 0, 0}; +// } +// +// g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); +// g2.setPaint(color); +// g2.fillPolygon(xPoints, yPoints, xPoints.length); +// } +// protected void renderRouteDiagonal2(Graphics2D g2, Color color) { +// int[] xPoints, yPoints; +// if (Direction.RIGHT.equals(getDirection())) { +// xPoints = new int[]{400, 380, 590, 610}; +// yPoints = new int[]{190, 190, 400, 400}; +// } else { +// xPoints = new int[]{400, 380, 590, 610}; +// yPoints = new int[]{210, 210, 0, 0}; +// } +// +// g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); +// g2.setPaint(color); +// g2.setPaint(Color.cyan); +// g2.fillPolygon(xPoints, yPoints, xPoints.length); +// } +// @Override +// public void renderTile(Graphics2D g2) { +// if (accessoryValue == null) { +// this.accessoryValue = AccessoryValue.OFF; +// } +// +// switch (accessoryValue) { +// case RED -> { +// renderStraight2(g2, Cross.LIGHT_RED); +// renderDiagonal(g2, Cross.LIGHT_RED); +// renderStraight(g2, Cross.DARK_RED); +// renderDiagonal2(g2, Cross.DARK_RED); +// } +// case GREEN -> { +// renderDiagonal(g2, Cross.VERY_LIGHT_GREEN); +// renderDiagonal2(g2, Cross.VERY_LIGHT_GREEN); +// renderStraight(g2, Cross.DARK_GREEN); +// renderStraight2(g2, Cross.DARK_GREEN); +// } +// default -> { +// renderStraight(g2, trackColor); +// renderStraight2(g2, trackColor); +// renderDiagonal(g2, trackColor); +// renderDiagonal2(g2, trackColor); +// } +// } +// } +// @Override +// public void renderTileRoute(Graphics2D g2) { +// if (routeValue == null) { +// routeValue = AccessoryValue.OFF; +// } +// if (model.getIncomingSide() == null) { +// model.setIncomingSide(model.getTileOrienation()); +// } +// +// Orientation incomingSide = model.getIncomingSide(); +// +// if (isHorizontal()) { +// if (AccessoryValue.GREEN == routeValue && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { +// renderRouteDiagonal(g2, trackRouteColor); +// renderRouteDiagonal2(g2, trackRouteColor); +// } else if (AccessoryValue.GREEN == routeValue && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { +// renderRouteStraight(g2, trackRouteColor); +// renderRouteStraight2(g2, trackRouteColor); +// } else if (AccessoryValue.RED == routeValue && Orientation.EAST == getOrientation()) { +// if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { +// renderRouteStraight2(g2, trackRouteColor); +// renderRouteDiagonal(g2, trackRouteColor); +// } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { +// renderRouteDiagonal2(g2, trackRouteColor); +// renderRouteStraight(g2, trackRouteColor); +// } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { +// renderRouteStraight2(g2, trackRouteColor); +// renderRouteDiagonal(g2, trackRouteColor); +// } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { +// renderRouteStraight(g2, trackColor); +// renderRouteDiagonal2(g2, trackColor); +// } +// } else if (AccessoryValue.RED == routeValue && Orientation.WEST == getOrientation()) { +// if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { +// renderRouteStraight(g2, trackRouteColor); +// renderRouteDiagonal2(g2, trackRouteColor); +// } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { +// renderRouteDiagonal(g2, trackRouteColor); +// renderRouteStraight2(g2, trackRouteColor); +// } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { +// renderRouteStraight(g2, trackRouteColor); +// renderRouteDiagonal2(g2, trackRouteColor); +// } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { +// renderRouteStraight2(g2, trackColor); +// renderRouteDiagonal(g2, trackColor); +// } +// } +// } else { +// if (AccessoryValue.GREEN == routeValue && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { +// renderRouteStraight(g2, trackRouteColor); +// renderRouteStraight2(g2, trackRouteColor); +// } else if (AccessoryValue.GREEN == routeValue && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { +// renderRouteDiagonal(g2, trackRouteColor); +// renderRouteDiagonal2(g2, trackRouteColor); +// } else if (AccessoryValue.RED == routeValue && Orientation.SOUTH == getOrientation()) { +// if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { +// renderRouteStraight2(g2, trackRouteColor); +// renderRouteDiagonal(g2, trackRouteColor); +// } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { +// renderRouteDiagonal2(g2, trackRouteColor); +// renderRouteStraight(g2, trackRouteColor); +// } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { +// renderRouteStraight(g2, trackRouteColor); +// renderRouteDiagonal2(g2, trackRouteColor); +// } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { +// renderRouteStraight2(g2, trackColor); +// renderRouteDiagonal(g2, trackColor); +// } +// } else if (AccessoryValue.RED == routeValue && Orientation.NORTH == getOrientation()) { +// if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { +// renderRouteStraight(g2, trackRouteColor); +// renderRouteDiagonal2(g2, trackRouteColor); +// } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { +// renderRouteDiagonal(g2, trackRouteColor); +// renderRouteStraight2(g2, trackRouteColor); +// } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { +// renderRouteStraight2(g2, trackRouteColor); +// renderRouteDiagonal(g2, trackRouteColor); +// } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { +// renderRouteStraight(g2, trackColor); +// renderRouteDiagonal2(g2, trackColor); +// } +// } +// } +// } + @Override + public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { + if (from != null && to != null && this.getDirection() != null) { + switch (this.getDirection()) { + case LEFT -> { + if (this.isHorizontal()) { + if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { + return AccessoryValue.GREEN; + } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { + return AccessoryValue.GREEN; + } else if ((from == Orientation.NORTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.NORTH)) { + return AccessoryValue.RED; + } else if ((from == Orientation.EAST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.EAST)) { + return AccessoryValue.RED; + } else { + return AccessoryValue.OFF; + } + } else { + //Vertical + if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { + return AccessoryValue.GREEN; + } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { + return AccessoryValue.GREEN; + } else if ((from == Orientation.SOUTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.SOUTH)) { + return AccessoryValue.RED; + } else if ((from == Orientation.EAST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.EAST)) { + return AccessoryValue.RED; + } else { + return AccessoryValue.OFF; + } + } + } + case RIGHT -> { + if (this.isHorizontal()) { + if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { + return AccessoryValue.GREEN; + } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { + return AccessoryValue.GREEN; + } else if ((from == Orientation.NORTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.NORTH)) { + return AccessoryValue.RED; + } else if ((from == Orientation.WEST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.WEST)) { + return AccessoryValue.RED; + } else { + return AccessoryValue.OFF; + } + } else { + //Vertical + if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { + return AccessoryValue.GREEN; + } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { + return AccessoryValue.GREEN; + } else if ((from == Orientation.SOUTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.SOUTH)) { + return AccessoryValue.RED; + } else if ((from == Orientation.WEST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.WEST)) { + return AccessoryValue.RED; + } else { + return AccessoryValue.OFF; + } + } + } + default -> { + return AccessoryValue.OFF; + } + } + } else { + return AccessoryValue.OFF; + } + } + +// @Override +// protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { +// //A Cross has 1 alternate point +// //1st square holds the centerpoint +// //2nd square +// double dX1, dX2, dY1, dY2; +// Orientation tileOrientation = model.getTileOrienation(); +// switch (tileOrientation) { +// case SOUTH -> { +// dX1 = renderWidth / 2 - size / 2; +// dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; +// dX2 = renderWidth / 2 + renderWidth - size / 4; +// dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; +// } +// case WEST -> { +// dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; +// dY1 = renderHeight / 2 - size / 2; +// dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; +// dY2 = renderHeight / 2 - size / 4; +// } +// case NORTH -> { +// dX1 = renderWidth / 2 - size / 2; +// dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; +// dX2 = renderWidth / 2 + renderWidth - size / 4; +// dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; +// } +// default -> { +// //East +// dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; +// dY1 = renderHeight / 2 - size / 2; +// dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; +// dY2 = renderHeight / 2 - size / 4; +// } +// } +// +// g2d.setColor(color); +// g2d.fill(new Ellipse2D.Double(dX1, dY1, size, size)); +// g2d.fill(new Ellipse2D.Double(dX2, dY2, size / 2, size / 2)); +// } + @Override + public Rectangle getTileBounds() { + Orientation tileOrientation = model.getTileOrienation(); + int xx, yy, w, h, multiplier; + if (model.isScaleImage()) { + w = tileWidth(tileOrientation, TileType.CROSS); + h = tileHeight(tileOrientation, TileType.CROSS); + multiplier = 1; + } else { + int renderWidth = getUI().getRenderWidth(); + int renderHeight = getUI().getRenderHeight(); + + w = renderWidth; + h = renderHeight; + multiplier = 10; + } + + switch (tileOrientation) { + case SOUTH -> { + xx = tileX - GRID * multiplier; + yy = tileY - GRID * multiplier; + } + case WEST -> { + xx = tileX - GRID * multiplier - GRID * 2 * multiplier; + yy = tileY - GRID * multiplier; + } + case NORTH -> { + xx = tileX - GRID * multiplier; + yy = tileY - GRID * multiplier - GRID * 2 * multiplier; + } + default -> { + //East + xx = tileX - GRID * multiplier; + yy = tileY - GRID * multiplier; + } + } + + if (model.isScaleImage()) { + return new Rectangle(xx, yy, w, h); + } else { + int renderWidth = getUI().getRenderWidth(); + int renderHeight = getUI().getRenderHeight(); + + return new Rectangle(xx, yy, renderWidth, renderHeight); + } + } + + private void changeRenderSizeAndOffsets() { + +// if (getUI() instanceof CrossUI cui) { +// +// cui.changeRenderSize(this); +// } else { +// Logger.warn("UI is a "+getUI().getClass().getSimpleName()); +// } + //Reset offsets +// this.offsetY = 0; + this.renderOffsetY = 0; +// this.offsetX = 0; + this.renderOffsetX = 0; + if (isHorizontal()) { + //this.renderWidth = RENDER_GRID * 4; + //this.renderHeight = RENDER_GRID * 2; + +// this.offsetY = 0; + this.renderOffsetY = 0; + } else { + //this.renderWidth = RENDER_GRID * 2; + //this.renderHeight = RENDER_GRID * 4; + + /// this.offsetX = 0; + this.renderOffsetX = 0; + } + + //Due to the asymetical shape (center is on the left) + //the offset has to be changed with the rotation +// Orientation tileOrientation = model.getTileOrienation(); +// switch (tileOrientation) { +// case SOUTH -> { +// this.offsetY = +GRID; +// this.renderOffsetY = RENDER_GRID; +// } +// case WEST -> { +// this.offsetX = -GRID; +// this.renderOffsetX = -RENDER_GRID; +// } +// case NORTH -> { +// this.offsetY = -GRID; +// this.renderOffsetY = -RENDER_GRID; +// } +// default -> { +// //East so default +// this.offsetX = +GRID; +// this.renderOffsetX = +RENDER_GRID; +// } +// } + } + + @Override + public Orientation rotate() { + super.rotate(); + + Orientation tileOrientation = model.getTileOrienation(); + int w = tileWidth(tileOrientation, TileType.CROSS); + int h = tileHeight(tileOrientation, TileType.CROSS); + + Dimension d = new Dimension(w, h); + setPreferredSize(d); + setSize(d); + changeRenderSizeAndOffsets(); + + setBounds(getTileBounds()); + return tileOrientation; + } + +} diff --git a/src/main/java/jcs/ui/layout/tiles/Crossing.java b/src/main/java/jcs/ui/layout/tiles/Crossing.java index 59e62085..f9f7cc97 100644 --- a/src/main/java/jcs/ui/layout/tiles/Crossing.java +++ b/src/main/java/jcs/ui/layout/tiles/Crossing.java @@ -1 +1,147 @@ -/* * Copyright 2023 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Point; import java.util.HashMap; import java.util.Map; import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; import jcs.entities.TileBean.TileType; public class Crossing extends Straight { public Crossing(TileBean tileBean) { super(tileBean); } public Crossing(Orientation orientation, Point center) { this(orientation, center.x, center.y); } public Crossing(Orientation orientation, int x, int y) { this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); } public Crossing(Orientation orientation, int x, int y, int width, int height) { super(orientation, x, y, width, height); this.tileType = TileType.CROSSING; } @Override public Map getNeighborPoints() { Map neighbors = new HashMap<>(); int cx = this.getCenterX(); int cy = this.getCenterY(); // Horizontal neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); // Vertical neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); return neighbors; } @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); int cx = this.getCenterX(); int cy = this.getCenterY(); // Horizontal edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); // Vertical edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); return edgeConnections; } protected void renderVerticalAndDividers(Graphics2D g2) { int xxn, yyn, xxs, yys, w, h; xxn = 175; yyn = 0; xxs = 175; yys = 325; w = 50; h = 75; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(trackColor); //North g2.fillRect(xxn, yyn, w, h); //South g2.fillRect(xxs, yys, w, h); //Dividers int[] xNorthPoly = new int[]{85, 115, 285, 315}; int[] yNorthPoly = new int[]{85, 125, 125, 85}; int[] xSouthPoly = new int[]{85, 115, 285, 315}; int[] ySouthPoly = new int[]{315, 275, 275, 315}; g2.setPaint(Color.darkGray); g2.setStroke(new BasicStroke(8, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.drawPolyline(xNorthPoly, yNorthPoly, xNorthPoly.length); g2.drawPolyline(xSouthPoly, ySouthPoly, xSouthPoly.length); } @Override public void renderTile(Graphics2D g2) { renderStraight(g2); renderVerticalAndDividers(g2); } protected void renderRouteVertical(Graphics2D g2) { int xxn, yyn, xxs, yys, w, h; xxn = 190; yyn = 0; xxs = 190; yys = 325; w = 20; h = 75; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(this.trackRouteColor); //North g2.fillRect(xxn, yyn, w, h); //South g2.fillRect(xxs, yys, w, h); } } \ No newline at end of file +/* + * Copyright 2023 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles; + +import java.awt.Point; +import java.util.HashMap; +import java.util.Map; +import javax.swing.UIManager; +import jcs.entities.TileBean; +import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean.TileType; +import jcs.ui.layout.tiles.ui.CrossingUI; +import jcs.ui.layout.tiles.ui.TileUI; + +public class Crossing extends Straight { + + public Crossing(TileBean tileBean) { + super(tileBean); + initUI(); + } + + public Crossing(Orientation orientation, Point center) { + this(orientation, center.x, center.y); + } + + public Crossing(Orientation orientation, int x, int y) { + this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); + } + + public Crossing(Orientation orientation, int x, int y, int width, int height) { + super(orientation, x, y, width, height); + this.tileType = TileType.CROSSING; + initUI(); + } + + private void initUI() { + updateUI(); + } + + @Override + public String getUIClassID() { + return CrossingUI.UI_CLASS_ID; + } + + @Override + public void updateUI() { + UIManager.put(TileUI.UI_CLASS_ID, "jcs.ui.layout.tiles.ui.CrossingUI"); + setUI((TileUI) UIManager.getUI(this)); + invalidate(); + } + + @Override + public Map getNeighborPoints() { + Map neighbors = new HashMap<>(); + int cx = this.getCenterX(); + int cy = this.getCenterY(); + + // Horizontal + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); + // Vertical + neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); + neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); + return neighbors; + } + + @Override + public Map getEdgePoints() { + Map edgeConnections = new HashMap<>(); + int cx = this.getCenterX(); + int cy = this.getCenterY(); + + // Horizontal + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); + // Vertical + edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); + edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); + return edgeConnections; + } + +// protected void renderVerticalAndDividers(Graphics2D g2) { +// int xxn, yyn, xxs, yys, w, h; +// xxn = 175; +// yyn = 0; +// xxs = 175; +// yys = 325; +// w = 50; +// h = 75; +// +// g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); +// g2.setPaint(trackColor); +// +// //North +// g2.fillRect(xxn, yyn, w, h); +// //South +// g2.fillRect(xxs, yys, w, h); +// +// //Dividers +// int[] xNorthPoly = new int[]{85, 115, 285, 315}; +// int[] yNorthPoly = new int[]{85, 125, 125, 85}; +// +// int[] xSouthPoly = new int[]{85, 115, 285, 315}; +// int[] ySouthPoly = new int[]{315, 275, 275, 315}; +// +// g2.setPaint(Color.darkGray); +// g2.setStroke(new BasicStroke(8, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); +// +// g2.drawPolyline(xNorthPoly, yNorthPoly, xNorthPoly.length); +// g2.drawPolyline(xSouthPoly, ySouthPoly, xSouthPoly.length); +// } +// @Override +// public void renderTile(Graphics2D g2) { +// renderStraight(g2); +// renderVerticalAndDividers(g2); +// } +// protected void renderRouteVertical(Graphics2D g2) { +// int xxn, yyn, xxs, yys, w, h; +// xxn = 190; +// yyn = 0; +// xxs = 190; +// yys = 325; +// w = 20; +// h = 75; +// +// g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); +// g2.setPaint(this.trackRouteColor); +// +// //North +// g2.fillRect(xxn, yyn, w, h); +// //South +// g2.fillRect(xxs, yys, w, h); +// } +} diff --git a/src/main/java/jcs/ui/layout/tiles/Curved.java b/src/main/java/jcs/ui/layout/tiles/Curved.java index c16fa01b..d52281e4 100755 --- a/src/main/java/jcs/ui/layout/tiles/Curved.java +++ b/src/main/java/jcs/ui/layout/tiles/Curved.java @@ -1 +1,133 @@ -/* * Copyright 2023 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.BasicStroke; import java.awt.Graphics2D; import java.awt.Point; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; public class Curved extends Tile { public Curved(TileBean tileBean) { super(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); setModel(new DefaultTileModel(tileBean.getOrientation())); } public Curved(Orientation orientation, Point center) { this(orientation, center.x, center.y); } public Curved(Orientation orientation, int x, int y) { this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); } public Curved(Orientation orientation, int x, int y, int width, int height) { super(TileType.CURVED, orientation, x, y, width, height); setModel(new DefaultTileModel(orientation)); } @Override public Map getNeighborPoints() { Map neighbors = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> { neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); } case WEST -> { neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); } case NORTH -> { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); } default -> { //EAST neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); } } return neighbors; } @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> { // | | // b \ |\ | edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); } case WEST -> { // |/ | // t / | | edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); } case NORTH -> { // t \ edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); } default -> { //EAST b / edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); } } return edgeConnections; } @Override public void renderTile(Graphics2D g2) { int[] xPoints = new int[]{400, 400, 170, 230}; int[] yPoints = new int[]{230, 170, 400, 400}; g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(trackColor); g2.fillPolygon(xPoints, yPoints, xPoints.length); } @Override public void renderTileRoute(Graphics2D g2) { int[] xPoints = new int[]{400, 400, 190, 210}; int[] yPoints = new int[]{210, 190, 400, 400}; g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(trackRouteColor); g2.fillPolygon(xPoints, yPoints, xPoints.length); } // @Override // protected void paintComponent(Graphics g) { // long started = System.currentTimeMillis(); // super.paintComponent(g); // // setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); // // Graphics2D g2 = (Graphics2D) g.create(); // drawTile(g2); // g2.dispose(); // // g.drawImage(this.tileImage, 0, 0, null); // // long now = System.currentTimeMillis(); // Logger.trace(this.id + " Duration: " + (now - started) + " ms."); // } } \ No newline at end of file +/* + * Copyright 2023 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles; + +import java.awt.Point; +import java.util.HashMap; +import java.util.Map; +import javax.swing.UIManager; +import jcs.entities.TileBean; +import jcs.entities.TileBean.Orientation; +import static jcs.entities.TileBean.Orientation.NORTH; +import static jcs.entities.TileBean.Orientation.SOUTH; +import static jcs.entities.TileBean.Orientation.WEST; +import jcs.entities.TileBean.TileType; +import jcs.ui.layout.tiles.ui.CurvedUI; +import jcs.ui.layout.tiles.ui.TileUI; + +public class Curved extends Tile { + + public Curved(TileBean tileBean) { + super(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); + setModel(new DefaultTileModel(tileBean.getOrientation())); + initUI(); + } + + public Curved(Orientation orientation, Point center) { + this(orientation, center.x, center.y); + } + + public Curved(Orientation orientation, int x, int y) { + this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); + } + + public Curved(Orientation orientation, int x, int y, int width, int height) { + super(TileType.CURVED, orientation, x, y, width, height); + setModel(new DefaultTileModel(orientation)); + initUI(); + } + + private void initUI() { + updateUI(); + } + + @Override + public String getUIClassID() { + return CurvedUI.UI_CLASS_ID; + } + + @Override + public void updateUI() { + UIManager.put(TileUI.UI_CLASS_ID, "jcs.ui.layout.tiles.ui.CurvedUI"); + setUI((TileUI) UIManager.getUI(this)); + invalidate(); + } + + @Override + public Map getNeighborPoints() { + Map neighbors = new HashMap<>(); + Orientation orientation = this.getOrientation(); + int cx = this.getCenterX(); + int cy = this.getCenterY(); + + switch (orientation) { + case SOUTH -> { + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); + neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); + } + case WEST -> { + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); + neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); + } + case NORTH -> { + neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); + } + default -> { + //EAST + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); + neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); + } + } + return neighbors; + } + + @Override + public Map getEdgePoints() { + Map edgeConnections = new HashMap<>(); + + Orientation orientation = this.getOrientation(); + int cx = this.getCenterX(); + int cy = this.getCenterY(); + + switch (orientation) { + case SOUTH -> { + // | | + // b \ |\ | + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); + edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); + } + case WEST -> { + // |/ | + // t / | | + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); + edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); + } + case NORTH -> { + // t \ + edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); + } + default -> { + //EAST b / + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); + edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); + } + } + return edgeConnections; + } + +} diff --git a/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java b/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java index d9e99fd9..2d97658b 100644 --- a/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java +++ b/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java @@ -18,7 +18,6 @@ import java.awt.Color; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.awt.event.ItemListener; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.EventListenerList; @@ -28,16 +27,11 @@ /** * - * @author fransjacobs */ -@SuppressWarnings("serial") // Same-version serialization only public class DefaultTileModel implements TileModel { protected transient ChangeEvent changeEvent = null; - /** - * Stores the listeners on this model. - */ protected EventListenerList listenerList = new EventListenerList(); protected boolean selected = false; @@ -45,6 +39,8 @@ public class DefaultTileModel implements TileModel { protected boolean scaleImage = true; protected boolean showCenter = false; protected Orientation tileOrienation; + protected Orientation incomingSide; + protected boolean showRoute = false; protected boolean showBlockState = false; protected boolean showLocomotiveImage = false; @@ -93,7 +89,7 @@ public void setSelectedColor(Color selectedColor) { } else { this.selectedColor = Tile.DEFAULT_SELECTED_COLOR; } - + if (!this.selectedColor.equals(prevColor)) { fireStateChanged(); } @@ -131,6 +127,16 @@ public void setTileOrienation(Orientation tileOrienation) { this.tileOrienation = tileOrienation; fireStateChanged(); } + + @Override + public Orientation getIncomingSide() { + return incomingSide; + } + + @Override + public void setIncomingSide(Orientation incomingSide) { + this.incomingSide = incomingSide; + } @Override public boolean isShowRoute() { @@ -310,30 +316,21 @@ public void removeChangeListener(ChangeListener l) { /** * Returns an array of all the change listeners registered on this DefaultButtonModel. * - * @return all of this model's ChangeListeners or an empty array if no change listeners are currently registered - * - * @see #addChangeListener - * @see #removeChangeListener - * - * @since 1.4 + * @return */ public ChangeListener[] getChangeListeners() { return listenerList.getListeners(ChangeListener.class); } /** - * Notifies all listeners that have registered interest for notification on this event type. The event instance is created lazily. - * - * @see EventListenerList + * Notifies all listeners that have registered interest for notification on this event type.br> The event instance is created lazily. */ protected void fireStateChanged() { - // Guaranteed to return a non-null array Object[] listeners = listenerList.getListenerList(); // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == ChangeListener.class) { - // Lazily create the event: if (changeEvent == null) { changeEvent = new ChangeEvent(this); } @@ -342,34 +339,9 @@ protected void fireStateChanged() { } } - /** - * {@inheritDoc} - */ -// @Override -// public void addItemListener(ItemListener l) { -// listenerList.add(ItemListener.class, l); +// public ItemListener[] getItemListeners() { +// return listenerList.getListeners(ItemListener.class); // } - /** - * {@inheritDoc} - */ -// @Override -// public void removeItemListener(ItemListener l) { -// listenerList.remove(ItemListener.class, l); -// } - /** - * Returns an array of all the item listeners registered on this DefaultButtonModel. - * - * @return all of this model's ItemListeners or an empty array if no item listeners are currently registered - * - * @see #addItemListener - * @see #removeItemListener - * - * @since 1.4 - */ - public ItemListener[] getItemListeners() { - return listenerList.getListeners(ItemListener.class); - } - @Override public void addActionListener(ActionListener l) { listenerList.add(ActionListener.class, l); @@ -389,16 +361,14 @@ public ActionListener[] getActionListeners() { * Notifies all listeners that have registered interest for notification on this event type. * * @param e the ActionEvent to deliver to listeners - * @see EventListenerList */ protected void fireActionPerformed(ActionEvent e) { - // Guaranteed to return a non-null array Object[] listeners = listenerList.getListenerList(); // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == ActionListener.class) { - // Lazily create the event: + // if (changeEvent == null) // changeEvent = new ChangeEvent(this); ((ActionListener) listeners[i + 1]).actionPerformed(e); @@ -406,11 +376,4 @@ protected void fireActionPerformed(ActionEvent e) { } } - /** - * Overridden to return null. - */ -// @Override -// public Object[] getSelectedObjects() { -// return null; -// } } diff --git a/src/main/java/jcs/ui/layout/tiles/End.java b/src/main/java/jcs/ui/layout/tiles/End.java index 79b10135..38b2383f 100644 --- a/src/main/java/jcs/ui/layout/tiles/End.java +++ b/src/main/java/jcs/ui/layout/tiles/End.java @@ -1 +1,108 @@ -/* * Copyright 2023 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Point; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; public class End extends Tile { public End(TileBean tileBean) { super(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); setModel(new DefaultTileModel(tileBean.getOrientation())); } public End(Orientation orientation, Point center) { this(orientation, center.x, center.y); } public End(Orientation orientation, int x, int y) { this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); } public End(Orientation orientation, int x, int y, int width, int height) { super(TileType.END, orientation, x, y, width, height); setModel(new DefaultTileModel(orientation)); } @Override public Map getNeighborPoints() { Map neighbors = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> neighbors.put(Orientation.SOUTH, new Point(cx, cy - Tile.GRID * 2)); case WEST -> neighbors.put(Orientation.WEST, new Point(cx + Tile.GRID * 2, cy)); case NORTH -> neighbors.put(Orientation.NORTH, new Point(cx, cy + Tile.GRID * 2)); default -> //EAST neighbors.put(Orientation.EAST, new Point(cx - Tile.GRID * 2, cy)); } return neighbors; } @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> edgeConnections.put(Orientation.SOUTH, new Point(cx, cy - Tile.GRID)); case WEST -> edgeConnections.put(Orientation.WEST, new Point(cx + Tile.GRID, cy)); case NORTH -> edgeConnections.put(Orientation.NORTH, new Point(cx, cy + Tile.GRID)); default -> //EAST edgeConnections.put(Orientation.EAST, new Point(cx - Tile.GRID, cy)); } return edgeConnections; } protected void renderEnd(Graphics2D g2) { int xx, yy, w, h; xx = 0; yy = 175; w = RENDER_GRID; h = 50; g2.setStroke(new BasicStroke(40, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(trackColor); g2.fillRect(xx, yy, w, h); xx = RENDER_GRID; yy = 100; w = 30; h = 200; g2.setPaint(Color.DARK_GRAY); g2.fillRect(xx, yy, w, h); } @Override public void renderTile(Graphics2D g2) { renderEnd(g2); } @Override public void renderTileRoute(Graphics2D g2d) { } // @Override // protected void paintComponent(Graphics g) { // long started = System.currentTimeMillis(); // super.paintComponent(g); // // setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); // // Graphics2D g2 = (Graphics2D) g.create(); // drawTile(g2); // g2.dispose(); // // g.drawImage(this.tileImage, 0, 0, null); // // long now = System.currentTimeMillis(); // Logger.trace(this.id + " Duration: " + (now - started) + " ms."); // } } \ No newline at end of file +/* + * Copyright 2023 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles; + +import java.awt.Point; +import java.util.HashMap; +import java.util.Map; +import javax.swing.UIManager; +import jcs.entities.TileBean; +import jcs.entities.TileBean.Orientation; +import static jcs.entities.TileBean.Orientation.NORTH; +import static jcs.entities.TileBean.Orientation.SOUTH; +import static jcs.entities.TileBean.Orientation.WEST; +import jcs.entities.TileBean.TileType; +import jcs.ui.layout.tiles.ui.EndUI; +import jcs.ui.layout.tiles.ui.TileUI; + +public class End extends Tile { + + public End(TileBean tileBean) { + super(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); + setModel(new DefaultTileModel(tileBean.getOrientation())); + initUI(); + } + + public End(Orientation orientation, Point center) { + this(orientation, center.x, center.y); + } + + public End(Orientation orientation, int x, int y) { + this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); + } + + public End(Orientation orientation, int x, int y, int width, int height) { + super(TileType.END, orientation, x, y, width, height); + setModel(new DefaultTileModel(orientation)); + initUI(); + } + + private void initUI() { + updateUI(); + } + + @Override + public String getUIClassID() { + return EndUI.UI_CLASS_ID; + } + + @Override + public void updateUI() { + UIManager.put(TileUI.UI_CLASS_ID, "jcs.ui.layout.tiles.ui.EndUI"); + setUI((TileUI) UIManager.getUI(this)); + invalidate(); + } + + @Override + public Map getNeighborPoints() { + Map neighbors = new HashMap<>(); + Orientation orientation = this.getOrientation(); + int cx = this.getCenterX(); + int cy = this.getCenterY(); + + switch (orientation) { + case SOUTH -> + neighbors.put(Orientation.SOUTH, new Point(cx, cy - Tile.GRID * 2)); + case WEST -> + neighbors.put(Orientation.WEST, new Point(cx + Tile.GRID * 2, cy)); + case NORTH -> + neighbors.put(Orientation.NORTH, new Point(cx, cy + Tile.GRID * 2)); + default -> //EAST + neighbors.put(Orientation.EAST, new Point(cx - Tile.GRID * 2, cy)); + } + return neighbors; + } + + @Override + public Map getEdgePoints() { + Map edgeConnections = new HashMap<>(); + Orientation orientation = this.getOrientation(); + int cx = this.getCenterX(); + int cy = this.getCenterY(); + + switch (orientation) { + case SOUTH -> + edgeConnections.put(Orientation.SOUTH, new Point(cx, cy - Tile.GRID)); + case WEST -> + edgeConnections.put(Orientation.WEST, new Point(cx + Tile.GRID, cy)); + case NORTH -> + edgeConnections.put(Orientation.NORTH, new Point(cx, cy + Tile.GRID)); + default -> //EAST + edgeConnections.put(Orientation.EAST, new Point(cx - Tile.GRID, cy)); + } + return edgeConnections; + } +} diff --git a/src/main/java/jcs/ui/layout/tiles/Sensor.java b/src/main/java/jcs/ui/layout/tiles/Sensor.java index cb5e9cd0..3b0bcd7d 100644 --- a/src/main/java/jcs/ui/layout/tiles/Sensor.java +++ b/src/main/java/jcs/ui/layout/tiles/Sensor.java @@ -15,18 +15,16 @@ */ package jcs.ui.layout.tiles; -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.MultipleGradientPaint.CycleMethod; import java.awt.Point; -import java.awt.RadialGradientPaint; -import java.awt.geom.Ellipse2D; +import javax.swing.UIManager; import jcs.commandStation.events.SensorEvent; import jcs.commandStation.events.SensorEventListener; import jcs.entities.SensorBean; import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; import jcs.entities.TileBean.TileType; +import jcs.ui.layout.tiles.ui.SensorUI; +import jcs.ui.layout.tiles.ui.TileUI; public class Sensor extends Straight implements SensorEventListener { @@ -47,32 +45,16 @@ public Sensor(Orientation orientation, int x, int y, int width, int height) { this.tileType = TileType.SENSOR; } - private void renderSensor(Graphics2D g2) { - int xx, yy; - xx = RENDER_GRID - 75; - yy = RENDER_GRID - 75; - - Point c = new Point(xx, yy); - float radius = 300; - float[] dist = {0.0f, 0.6f}; - - if (model.isSensorActive()) { - Color[] colors = {Color.red.brighter(), Color.red.darker()}; - RadialGradientPaint foreground = new RadialGradientPaint(c, radius, dist, colors, CycleMethod.REFLECT); - g2.setPaint(foreground); - } else { - Color[] colors = {Color.green.darker(), Color.green.brighter()}; - RadialGradientPaint foreground = new RadialGradientPaint(c, radius, dist, colors, CycleMethod.REFLECT); - g2.setPaint(foreground); - } - - g2.fill(new Ellipse2D.Double(xx, yy, 0.5f * radius, 0.5f * radius)); + @Override + public String getUIClassID() { + return SensorUI.UI_CLASS_ID; } @Override - public void renderTile(Graphics2D g2d) { - renderStraight(g2d); - renderSensor(g2d); + public void updateUI() { + UIManager.put(TileUI.UI_CLASS_ID, "jcs.ui.layout.tiles.ui.SensorUI"); + setUI((TileUI) UIManager.getUI(this)); + invalidate(); } @Override diff --git a/src/main/java/jcs/ui/layout/tiles/Signal.java b/src/main/java/jcs/ui/layout/tiles/Signal.java index 1b7a5b49..982b666d 100644 --- a/src/main/java/jcs/ui/layout/tiles/Signal.java +++ b/src/main/java/jcs/ui/layout/tiles/Signal.java @@ -15,26 +15,17 @@ */ package jcs.ui.layout.tiles; -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Graphics2D; import java.awt.Point; -import java.awt.Polygon; +import javax.swing.UIManager; import jcs.commandStation.events.AccessoryEvent; import jcs.commandStation.events.AccessoryEventListener; import jcs.entities.AccessoryBean.SignalType; -import static jcs.entities.AccessoryBean.SignalType.HP012; -import static jcs.entities.AccessoryBean.SignalType.HP012SH1; -import static jcs.entities.AccessoryBean.SignalType.HP0SH1; import jcs.entities.AccessoryBean.SignalValue; -import static jcs.entities.AccessoryBean.SignalValue.Hp0; -import static jcs.entities.AccessoryBean.SignalValue.Hp0Sh1; -import static jcs.entities.AccessoryBean.SignalValue.Hp1; -import static jcs.entities.AccessoryBean.SignalValue.Hp2; import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; import jcs.entities.TileBean.TileType; -import static jcs.ui.layout.tiles.Tile.RENDER_GRID; +import jcs.ui.layout.tiles.ui.SignalUI; +import jcs.ui.layout.tiles.ui.TileUI; public class Signal extends Straight implements AccessoryEventListener { @@ -57,283 +48,290 @@ public class Signal extends Straight implements AccessoryEventListener { this.signalValue = SignalValue.OFF; } - /** - * Render a Signal with 2 lights - * - * @param g2d the graphics context - */ - protected void renderSignal2(Graphics2D g2d) { - int rx = RENDER_GRID; - int ry = RENDER_GRID + 60; - int rw = 180; - int rh = 100; - int l1x = RENDER_GRID + 20; - int l1y = RENDER_GRID + 80; - int l2x = RENDER_GRID + 100; - int l2y = RENDER_GRID + 80; - - Color color1 = Color.gray; - Color color2 = Color.gray; - - if (this.signalValue == null) { - this.signalValue = SignalValue.OFF; - } - - switch (signalValue) { - case Hp0 -> { - color1 = Color.red; - color2 = Color.gray; - } - case Hp1 -> { - color1 = Color.gray; - color2 = Color.green; - } - default -> { - } - } - - g2d.setStroke(new BasicStroke(10f)); - g2d.setPaint(Color.darkGray); - g2d.fillRoundRect(rx, ry, rw, rh, 30, 30); - - g2d.setPaint(color1); - g2d.fillOval(l1x, l1y, 60, 60); - g2d.setPaint(color2); - g2d.fillOval(l2x, l2y, 60, 60); - } - - protected void renderSignal3(Graphics2D g2d) { - int rx = RENDER_GRID; - int ry = RENDER_GRID + 60; - int rw = 180; - int rh = 100; - - int c1x = RENDER_GRID + 130; - int c1y = RENDER_GRID + 115; - - int c2x = RENDER_GRID + 10; - int c2y = RENDER_GRID + 115; - - int c3x = RENDER_GRID + 10; - int c3y = RENDER_GRID + 65; - - // Initialize all "lights" - Color color1 = Color.gray; - Color color2 = Color.gray; - Color color3 = Color.gray; - - if (this.signalValue == null) { - this.signalValue = SignalValue.OFF; - } - - switch (this.signalValue) { - case Hp0 -> { - color3 = Color.red; - } - case Hp1 -> - color1 = Color.green; - case Hp2 -> { - color1 = Color.green; - color2 = Color.yellow; - } - default -> { - } - } - - g2d.setStroke(new BasicStroke(10f)); - g2d.setPaint(Color.darkGray); - g2d.fillRoundRect(rx, ry, rw, rh, 30, 30); - - g2d.setPaint(color1); - g2d.fillOval(c1x, c1y, 40, 40); - - g2d.setPaint(color2); - g2d.fillOval(c2x, c2y, 40, 40); - - g2d.setPaint(color3); - g2d.fillOval(c3x, c3y, 40, 40); - } - - /** - * Render a entry Signal which can show 4 light images - * - * @param g2d the Graphics context - */ - protected void renderSignal4(Graphics2D g2d) { - int rx = RENDER_GRID - 50; - int ry = RENDER_GRID + 50; - int rw = 240; - int rh = 120; - int c1x = RENDER_GRID + 140; - int c1y = RENDER_GRID + 60; - - int c2x = RENDER_GRID + 90; - int c2y = RENDER_GRID + 60; - - int c3x = RENDER_GRID + 90; - int c3y = RENDER_GRID + 120; - - int c4x = RENDER_GRID + 60; - int c4y = RENDER_GRID + 130; - - int c5x = RENDER_GRID + 10; - int c5y = RENDER_GRID + 70; - - int c6x = RENDER_GRID - 40; - int c6y = RENDER_GRID + 60; - - // Initialize all "lights" - Color color1 = Color.gray; - Color color2 = Color.gray; - Color color3 = Color.gray; - Color color4 = Color.gray; - Color color5 = Color.gray; - Color color6 = Color.gray; - - if (this.signalValue == null) { - this.signalValue = SignalValue.OFF; - } - - switch (this.signalValue) { - case Hp0 -> { - color2 = Color.red; - color3 = Color.red; - } - case Hp1 -> - color1 = Color.green; - case Hp2 -> { - color1 = Color.green; - color6 = Color.yellow; - } - case Hp0Sh1 -> { - color2 = Color.red; - color4 = Color.white; - color5 = Color.white; - } - default -> { - } - } - - g2d.setStroke(new BasicStroke(10f)); - g2d.setPaint(Color.darkGray); - g2d.fillRoundRect(rx, ry, rw, rh, 30, 30); - - g2d.setPaint(color1); - g2d.fillOval(c1x, c1y, 40, 40); - g2d.setPaint(color2); - g2d.fillOval(c2x, c2y, 40, 40); - g2d.setPaint(color3); - g2d.fillOval(c3x, c3y, 40, 40); - g2d.setPaint(color4); - g2d.fillOval(c4x, c4y, 20, 20); - g2d.setPaint(color5); - g2d.fillOval(c5x, c5y, 20, 20); - g2d.setPaint(color6); - g2d.fillOval(c6x, c6y, 40, 40); - } - - /** - * Render a midget Signal - * - * @param g2d the Graphics context - */ - protected void renderSignal2m(Graphics2D g2d) { - int[] xps - = new int[]{ - RENDER_GRID + 80, - +RENDER_GRID + 150, - +RENDER_GRID + 170, - RENDER_GRID + 170, - +RENDER_GRID + 150, - RENDER_GRID + 80 - }; - int[] yps - = new int[]{ - RENDER_GRID + 60, - RENDER_GRID + 60, - RENDER_GRID + 80, - +RENDER_GRID + 160, - +RENDER_GRID + 180, - RENDER_GRID + 180 - }; - - Polygon signalOutline = new Polygon(xps, yps, xps.length); - - int c1x = RENDER_GRID + 130; - int c1y = RENDER_GRID + 70; - - int c2x = RENDER_GRID + 130; - int c2y = RENDER_GRID + 140; - - int c3x = RENDER_GRID + 130; - int c3y = RENDER_GRID + 105; - - int c4x = RENDER_GRID + 85; - int c4y = RENDER_GRID + 70; - - Color color1 = Color.gray; - Color color2 = Color.gray; - Color color3 = Color.gray; - Color color4 = Color.gray; - - if (this.signalValue == null) { - this.signalValue = SignalValue.OFF; - } - - switch (this.signalValue) { - case Hp0 -> { - color1 = Color.red; - color2 = Color.red; - } - case Hp1 -> { - color3 = Color.white; - color4 = Color.white; - } - default -> { - } - } - - g2d.setStroke(new BasicStroke(10f)); - g2d.setPaint(Color.darkGray); - - g2d.fillPolygon(signalOutline); - - g2d.setPaint(color1); - g2d.fillOval(c1x, c1y, 30, 30); - - g2d.setPaint(color2); - g2d.fillOval(c2x, c2y, 30, 30); - - g2d.setPaint(color3); - g2d.fillOval(c3x, c3y, 30, 30); - - g2d.setPaint(color4); - g2d.fillOval(c4x, c4y, 30, 30); + @Override + public String getUIClassID() { + return SignalUI.UI_CLASS_ID; } @Override - public void renderTile(Graphics2D g2) { - Graphics2D g2d = (Graphics2D) g2.create(); - renderStraight(g2d); - - if (signalType == null) { - signalType = SignalType.NONE; - } - - switch (signalType) { - case HP012 -> - renderSignal3(g2d); - case HP012SH1 -> - renderSignal4(g2d); - case HP0SH1 -> - renderSignal2m(g2d); - default -> - renderSignal2(g2d); - } - - g2d.dispose(); + public void updateUI() { + UIManager.put(TileUI.UI_CLASS_ID, "jcs.ui.layout.tiles.ui.SignalUI"); + setUI((TileUI) UIManager.getUI(this)); + invalidate(); } +// /** +// * Render a Signal with 2 lights +// * +// * @param g2d the graphics context +// */ +// protected void renderSignal2(Graphics2D g2d) { +// int rx = RENDER_GRID; +// int ry = RENDER_GRID + 60; +// int rw = 180; +// int rh = 100; +// int l1x = RENDER_GRID + 20; +// int l1y = RENDER_GRID + 80; +// int l2x = RENDER_GRID + 100; +// int l2y = RENDER_GRID + 80; +// +// Color color1 = Color.gray; +// Color color2 = Color.gray; +// +// if (this.signalValue == null) { +// this.signalValue = SignalValue.OFF; +// } +// +// switch (signalValue) { +// case Hp0 -> { +// color1 = Color.red; +// color2 = Color.gray; +// } +// case Hp1 -> { +// color1 = Color.gray; +// color2 = Color.green; +// } +// default -> { +// } +// } +// +// g2d.setStroke(new BasicStroke(10f)); +// g2d.setPaint(Color.darkGray); +// g2d.fillRoundRect(rx, ry, rw, rh, 30, 30); +// +// g2d.setPaint(color1); +// g2d.fillOval(l1x, l1y, 60, 60); +// g2d.setPaint(color2); +// g2d.fillOval(l2x, l2y, 60, 60); +// } +// protected void renderSignal3(Graphics2D g2d) { +// int rx = RENDER_GRID; +// int ry = RENDER_GRID + 60; +// int rw = 180; +// int rh = 100; +// +// int c1x = RENDER_GRID + 130; +// int c1y = RENDER_GRID + 115; +// +// int c2x = RENDER_GRID + 10; +// int c2y = RENDER_GRID + 115; +// +// int c3x = RENDER_GRID + 10; +// int c3y = RENDER_GRID + 65; +// +// // Initialize all "lights" +// Color color1 = Color.gray; +// Color color2 = Color.gray; +// Color color3 = Color.gray; +// +// if (this.signalValue == null) { +// this.signalValue = SignalValue.OFF; +// } +// +// switch (this.signalValue) { +// case Hp0 -> { +// color3 = Color.red; +// } +// case Hp1 -> +// color1 = Color.green; +// case Hp2 -> { +// color1 = Color.green; +// color2 = Color.yellow; +// } +// default -> { +// } +// } +// +// g2d.setStroke(new BasicStroke(10f)); +// g2d.setPaint(Color.darkGray); +// g2d.fillRoundRect(rx, ry, rw, rh, 30, 30); +// +// g2d.setPaint(color1); +// g2d.fillOval(c1x, c1y, 40, 40); +// +// g2d.setPaint(color2); +// g2d.fillOval(c2x, c2y, 40, 40); +// +// g2d.setPaint(color3); +// g2d.fillOval(c3x, c3y, 40, 40); +// } +// /** +// * Render a entry Signal which can show 4 light images +// * +// * @param g2d the Graphics context +// */ +// protected void renderSignal4(Graphics2D g2d) { +// int rx = RENDER_GRID - 50; +// int ry = RENDER_GRID + 50; +// int rw = 240; +// int rh = 120; +// int c1x = RENDER_GRID + 140; +// int c1y = RENDER_GRID + 60; +// +// int c2x = RENDER_GRID + 90; +// int c2y = RENDER_GRID + 60; +// +// int c3x = RENDER_GRID + 90; +// int c3y = RENDER_GRID + 120; +// +// int c4x = RENDER_GRID + 60; +// int c4y = RENDER_GRID + 130; +// +// int c5x = RENDER_GRID + 10; +// int c5y = RENDER_GRID + 70; +// +// int c6x = RENDER_GRID - 40; +// int c6y = RENDER_GRID + 60; +// +// // Initialize all "lights" +// Color color1 = Color.gray; +// Color color2 = Color.gray; +// Color color3 = Color.gray; +// Color color4 = Color.gray; +// Color color5 = Color.gray; +// Color color6 = Color.gray; +// +// if (this.signalValue == null) { +// this.signalValue = SignalValue.OFF; +// } +// +// switch (this.signalValue) { +// case Hp0 -> { +// color2 = Color.red; +// color3 = Color.red; +// } +// case Hp1 -> +// color1 = Color.green; +// case Hp2 -> { +// color1 = Color.green; +// color6 = Color.yellow; +// } +// case Hp0Sh1 -> { +// color2 = Color.red; +// color4 = Color.white; +// color5 = Color.white; +// } +// default -> { +// } +// } +// +// g2d.setStroke(new BasicStroke(10f)); +// g2d.setPaint(Color.darkGray); +// g2d.fillRoundRect(rx, ry, rw, rh, 30, 30); +// +// g2d.setPaint(color1); +// g2d.fillOval(c1x, c1y, 40, 40); +// g2d.setPaint(color2); +// g2d.fillOval(c2x, c2y, 40, 40); +// g2d.setPaint(color3); +// g2d.fillOval(c3x, c3y, 40, 40); +// g2d.setPaint(color4); +// g2d.fillOval(c4x, c4y, 20, 20); +// g2d.setPaint(color5); +// g2d.fillOval(c5x, c5y, 20, 20); +// g2d.setPaint(color6); +// g2d.fillOval(c6x, c6y, 40, 40); +// } +// /** +// * Render a midget Signal +// * +// * @param g2d the Graphics context +// */ +// protected void renderSignal2m(Graphics2D g2d) { +// int[] xps +// = new int[]{ +// RENDER_GRID + 80, +// +RENDER_GRID + 150, +// +RENDER_GRID + 170, +// RENDER_GRID + 170, +// +RENDER_GRID + 150, +// RENDER_GRID + 80 +// }; +// int[] yps +// = new int[]{ +// RENDER_GRID + 60, +// RENDER_GRID + 60, +// RENDER_GRID + 80, +// +RENDER_GRID + 160, +// +RENDER_GRID + 180, +// RENDER_GRID + 180 +// }; +// +// Polygon signalOutline = new Polygon(xps, yps, xps.length); +// +// int c1x = RENDER_GRID + 130; +// int c1y = RENDER_GRID + 70; +// +// int c2x = RENDER_GRID + 130; +// int c2y = RENDER_GRID + 140; +// +// int c3x = RENDER_GRID + 130; +// int c3y = RENDER_GRID + 105; +// +// int c4x = RENDER_GRID + 85; +// int c4y = RENDER_GRID + 70; +// +// Color color1 = Color.gray; +// Color color2 = Color.gray; +// Color color3 = Color.gray; +// Color color4 = Color.gray; +// +// if (this.signalValue == null) { +// this.signalValue = SignalValue.OFF; +// } +// +// switch (this.signalValue) { +// case Hp0 -> { +// color1 = Color.red; +// color2 = Color.red; +// } +// case Hp1 -> { +// color3 = Color.white; +// color4 = Color.white; +// } +// default -> { +// } +// } +// +// g2d.setStroke(new BasicStroke(10f)); +// g2d.setPaint(Color.darkGray); +// +// g2d.fillPolygon(signalOutline); +// +// g2d.setPaint(color1); +// g2d.fillOval(c1x, c1y, 30, 30); +// +// g2d.setPaint(color2); +// g2d.fillOval(c2x, c2y, 30, 30); +// +// g2d.setPaint(color3); +// g2d.fillOval(c3x, c3y, 30, 30); +// +// g2d.setPaint(color4); +// g2d.fillOval(c4x, c4y, 30, 30); +// } +// @Override +// public void renderTile(Graphics2D g2) { +// Graphics2D g2d = (Graphics2D) g2.create(); +// renderStraight(g2d); +// +// if (signalType == null) { +// signalType = SignalType.NONE; +// } +// +// switch (signalType) { +// case HP012 -> +// renderSignal3(g2d); +// case HP012SH1 -> +// renderSignal4(g2d); +// case HP0SH1 -> +// renderSignal2m(g2d); +// default -> +// renderSignal2(g2d); +// } +// +// g2d.dispose(); +// } //TODO move to UI delegate @Override public void onAccessoryChange(AccessoryEvent event) { diff --git a/src/main/java/jcs/ui/layout/tiles/Straight.java b/src/main/java/jcs/ui/layout/tiles/Straight.java index e34552ca..2160a5f1 100755 --- a/src/main/java/jcs/ui/layout/tiles/Straight.java +++ b/src/main/java/jcs/ui/layout/tiles/Straight.java @@ -1 +1,104 @@ -/* * Copyright 2023 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.BasicStroke; import java.awt.Graphics2D; import java.awt.Point; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; import jcs.entities.TileBean.TileType; public class Straight extends Tile { public Straight(TileBean tileBean) { super(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); setModel(new DefaultTileModel(tileBean.getOrientation())); } public Straight(Orientation orientation, Point center) { this(orientation, center.x, center.y); } public Straight(Orientation orientation, int x, int y) { this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); } public Straight(Orientation orientation, int x, int y, int width, int height) { super(TileType.STRAIGHT, orientation, x, y, width, height); setModel(new DefaultTileModel(orientation)); } @Override public Map getNeighborPoints() { Map neighbors = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); if (Orientation.EAST == orientation || Orientation.WEST == orientation) { // Horizontal neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); } else { // Vertical neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); } return neighbors; } @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); if (Orientation.EAST == orientation || Orientation.WEST == orientation) { // Horizontal edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); } else { // Vertical edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); } return edgeConnections; } protected void renderStraight(Graphics2D g2) { int xx, yy, w, h; xx = 0; yy = 170; w = RENDER_WIDTH; h = 60; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(trackColor); g2.fillRect(xx, yy, w, h); } protected void renderRouteStraight(Graphics2D g2) { int xx, yy, w, h; xx = 0; yy = 190; w = RENDER_WIDTH; h = 20; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(trackRouteColor); g2.fillRect(xx, yy, w, h); } @Override public void renderTileRoute(Graphics2D g2) { renderRouteStraight(g2); } @Override public void renderTile(Graphics2D g2) { renderStraight(g2); } } \ No newline at end of file +/* + * Copyright 2023 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles; + +import jcs.ui.layout.tiles.ui.StraightUI; +import jcs.ui.layout.tiles.ui.TileUI; +import java.awt.Point; +import java.util.HashMap; +import java.util.Map; +import javax.swing.UIManager; +import jcs.entities.TileBean; +import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean.TileType; + +public class Straight extends Tile { + + public Straight(TileBean tileBean) { + super(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); + setModel(new DefaultTileModel(tileBean.getOrientation())); + initUI(); + } + + public Straight(Orientation orientation, Point center) { + this(orientation, center.x, center.y); + } + + public Straight(Orientation orientation, int x, int y) { + this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); + } + + public Straight(Orientation orientation, int x, int y, int width, int height) { + super(TileType.STRAIGHT, orientation, x, y, width, height); + setModel(new DefaultTileModel(orientation)); + initUI(); + } + + private void initUI() { + updateUI(); + } + + @Override + public String getUIClassID() { + return StraightUI.UI_CLASS_ID; + } + + @Override + public void updateUI() { + UIManager.put(TileUI.UI_CLASS_ID, "jcs.ui.layout.tiles.ui.StraightUI"); + setUI((TileUI) UIManager.getUI(this)); + invalidate(); + } + + @Override + public Map getNeighborPoints() { + Map neighbors = new HashMap<>(); + Orientation orientation = this.getOrientation(); + int cx = this.getCenterX(); + int cy = this.getCenterY(); + + if (Orientation.EAST == orientation || Orientation.WEST == orientation) { + // Horizontal + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); + } else { + // Vertical + neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); + neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); + } + return neighbors; + } + + @Override + public Map getEdgePoints() { + Map edgeConnections = new HashMap<>(); + Orientation orientation = this.getOrientation(); + int cx = this.getCenterX(); + int cy = this.getCenterY(); + + if (Orientation.EAST == orientation || Orientation.WEST == orientation) { + // Horizontal + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); + } else { + // Vertical + edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); + edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); + } + return edgeConnections; + } + +} diff --git a/src/main/java/jcs/ui/layout/tiles/StraightDirection.java b/src/main/java/jcs/ui/layout/tiles/StraightDirection.java index df3fbd01..df847634 100644 --- a/src/main/java/jcs/ui/layout/tiles/StraightDirection.java +++ b/src/main/java/jcs/ui/layout/tiles/StraightDirection.java @@ -15,14 +15,14 @@ */ package jcs.ui.layout.tiles; -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Graphics2D; import java.awt.Point; import java.util.Collection; +import javax.swing.UIManager; import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; import jcs.entities.TileBean.TileType; +import jcs.ui.layout.tiles.ui.StraightDirectionUI; +import jcs.ui.layout.tiles.ui.TileUI; public class StraightDirection extends Straight { @@ -40,6 +40,18 @@ public StraightDirection(Orientation orientation, Point center) { this.tileType = TileType.STRAIGHT_DIR; } + @Override + public String getUIClassID() { + return StraightDirectionUI.UI_CLASS_ID; + } + + @Override + public void updateUI() { + UIManager.put(TileUI.UI_CLASS_ID, "jcs.ui.layout.tiles.ui.StraightDirectionUI"); + setUI((TileUI) UIManager.getUI(this)); + invalidate(); + } + @Override public boolean isDirectional() { return true; @@ -63,20 +75,18 @@ public boolean isArrowDirection(Tile other) { return arrowDirection && isAdjacent(other); } - private void renderDirectionArrow(Graphics2D g2) { - // |\ - // ==|+=== - // |/ - g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); - g2.setPaint(Color.green.darker()); - - g2.fillPolygon(new int[]{150, 150, 270}, new int[]{130, 270, 200}, 3); - } - - @Override - public void renderTile(Graphics2D g2d) { - renderStraight(g2d); - renderDirectionArrow(g2d); - } - +// private void renderDirectionArrow(Graphics2D g2) { +// // |\ +// // ==|+=== +// // |/ +// g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); +// g2.setPaint(Color.green.darker()); +// +// g2.fillPolygon(new int[]{150, 150, 270}, new int[]{130, 270, 200}, 3); +// } +// @Override +// public void renderTile(Graphics2D g2d) { +// renderStraight(g2d); +// renderDirectionArrow(g2d); +// } } diff --git a/src/main/java/jcs/ui/layout/tiles/Switch.java b/src/main/java/jcs/ui/layout/tiles/Switch.java index 9dd3a651..933583f8 100644 --- a/src/main/java/jcs/ui/layout/tiles/Switch.java +++ b/src/main/java/jcs/ui/layout/tiles/Switch.java @@ -1 +1,345 @@ -/* * Copyright 2023 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Point; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import jcs.commandStation.events.AccessoryEvent; import jcs.commandStation.events.AccessoryEventListener; import jcs.entities.AccessoryBean.AccessoryValue; import static jcs.entities.AccessoryBean.AccessoryValue.GREEN; import static jcs.entities.AccessoryBean.AccessoryValue.RED; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import static jcs.entities.TileBean.Direction.LEFT; import static jcs.entities.TileBean.Direction.RIGHT; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; public class Switch extends Tile implements AccessoryEventListener { public Switch(Orientation orientation, Direction direction, Point center) { this(orientation, direction, center.x, center.y); } public Switch(Orientation orientation, Direction direction, int x, int y) { this(orientation, direction, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); } public Switch(Orientation orientation, Direction direction, int x, int y, int width, int height) { this(TileType.SWITCH, orientation, direction, x, y, width, height); } protected Switch(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { super(tileType, orientation, direction, x, y, width, height); setModel(new DefaultTileModel(orientation)); } public Switch(TileBean tileBean) { this(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); } protected Switch(TileBean tileBean, int width, int height) { super(tileBean, width, height); setModel(new DefaultTileModel(tileBean.getOrientation())); } @Override public Map getNeighborPoints() { Map neighbors = new HashMap<>(); Orientation orientation = this.getOrientation(); Direction direction = this.getDirection(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); if (Direction.LEFT == direction) { neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); } else { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); } } case WEST -> { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); if (Direction.LEFT == direction) { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); } else { neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); } } case NORTH -> { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); if (Direction.LEFT == direction) { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); } else { neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); } } default -> { //EAST neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); if (Direction.LEFT == direction) { neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); } else { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); } } } return neighbors; } @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); Orientation orientation = this.getOrientation(); Direction direction = this.getDirection(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); } else { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); } } case WEST -> { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); } else { edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); } } case NORTH -> { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); } else { edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); } } default -> { //EAST edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); } else { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); } } } return edgeConnections; } protected void renderStraight(Graphics2D g2, Color color) { int xx, yy, w, h; xx = 0; yy = 170; w = RENDER_WIDTH; h = 60; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } protected void renderDiagonal(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{400, 400, 170, 230}; yPoints = new int[]{170, 230, 0, 0}; } else { xPoints = new int[]{400, 400, 170, 230}; yPoints = new int[]{230, 170, 400, 400}; } g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillPolygon(xPoints, yPoints, xPoints.length); } protected void renderRouteStraight(Graphics2D g2, Color color) { int xx, yy, w, h; xx = 0; yy = 190; w = RENDER_WIDTH; h = 20; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } protected void renderRouteDiagonal(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{400, 400, 190, 210}; yPoints = new int[]{190, 210, 0, 0}; } else { xPoints = new int[]{400, 400, 190, 210}; yPoints = new int[]{210, 190, 400, 400}; } g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillPolygon(xPoints, yPoints, xPoints.length); } @Override public void renderTile(Graphics2D g2) { if (accessoryValue == null) { this.accessoryValue = AccessoryValue.OFF; } switch (accessoryValue) { case RED -> { renderStraight(g2, trackColor); renderDiagonal(g2, Color.red); } case GREEN -> { renderDiagonal(g2, trackColor); renderStraight(g2, Color.green); } default -> { renderStraight(g2, trackColor); renderDiagonal(g2, trackColor); } } } @Override public void renderTileRoute(Graphics2D g2) { if (routeValue == null) { routeValue = AccessoryValue.OFF; } switch (routeValue) { case RED -> { renderRouteDiagonal(g2, trackRouteColor); } case GREEN -> { renderRouteStraight(g2, trackRouteColor); } default -> { } } } @Override public void onAccessoryChange(AccessoryEvent event) { if (getAccessoryBean() != null && event.isEventFor(accessoryBean)) { setAccessoryValue(event.getAccessoryBean().getAccessoryValue()); } } @Override public boolean isJunction() { return true; } @Override public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { if (from != null && to != null && this.getDirection() != null) { switch (this.getDirection()) { case LEFT -> { if (this.isHorizontal()) { if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if (((from == Orientation.EAST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.EAST)) && Orientation.EAST == this.getOrientation()) { return AccessoryValue.RED; } else if (((from == Orientation.WEST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.WEST)) && Orientation.WEST == this.getOrientation()) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } else { //Vertical if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if (((from == Orientation.SOUTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.SOUTH)) && Orientation.SOUTH == this.getOrientation()) { return AccessoryValue.RED; } else if (((from == Orientation.NORTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.NORTH)) && Orientation.NORTH == this.getOrientation()) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } } case RIGHT -> { if (this.isHorizontal()) { if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if (((from == Orientation.EAST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.EAST)) && Orientation.EAST == this.getOrientation()) { return AccessoryValue.RED; } else if (((from == Orientation.WEST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.WEST)) && Orientation.WEST == this.getOrientation()) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } else { //Vertical if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if (((from == Orientation.EAST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.EAST)) && Orientation.SOUTH == this.getOrientation()) { return AccessoryValue.RED; } else if (((from == Orientation.WEST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.WEST)) && Orientation.NORTH == this.getOrientation()) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } } default -> { return AccessoryValue.OFF; } } } else { return AccessoryValue.OFF; } } // @Override // protected void paintComponent(Graphics g) { // long started = System.currentTimeMillis(); // super.paintComponent(g); // // setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); // // Graphics2D g2 = (Graphics2D) g.create(); // drawTile(g2); // g2.dispose(); // // g.drawImage(this.tileImage, 0, 0, null); // // long now = System.currentTimeMillis(); // Logger.trace(this.id + " Duration: " + (now - started) + " ms."); // } } \ No newline at end of file +/* + * Copyright 2023 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles; + +import java.awt.Point; +import java.util.HashMap; +import java.util.Map; +import javax.swing.UIManager; +import jcs.commandStation.events.AccessoryEvent; +import jcs.commandStation.events.AccessoryEventListener; +import jcs.entities.AccessoryBean.AccessoryValue; +import jcs.entities.TileBean; +import jcs.entities.TileBean.Direction; +import static jcs.entities.TileBean.Direction.LEFT; +import static jcs.entities.TileBean.Direction.RIGHT; +import jcs.entities.TileBean.Orientation; +import static jcs.entities.TileBean.Orientation.NORTH; +import static jcs.entities.TileBean.Orientation.SOUTH; +import static jcs.entities.TileBean.Orientation.WEST; +import jcs.entities.TileBean.TileType; +import jcs.ui.layout.tiles.ui.SwitchUI; +import jcs.ui.layout.tiles.ui.TileUI; + +public class Switch extends Tile implements AccessoryEventListener { + + public Switch(Orientation orientation, Direction direction, Point center) { + this(orientation, direction, center.x, center.y); + } + + public Switch(Orientation orientation, Direction direction, int x, int y) { + this(orientation, direction, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); + } + + public Switch(Orientation orientation, Direction direction, int x, int y, int width, int height) { + this(TileType.SWITCH, orientation, direction, x, y, width, height); + } + + protected Switch(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { + super(tileType, orientation, direction, x, y, width, height); + setModel(new DefaultTileModel(orientation)); + initUI(); + } + + public Switch(TileBean tileBean) { + this(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); + } + + protected Switch(TileBean tileBean, int width, int height) { + super(tileBean, width, height); + setModel(new DefaultTileModel(tileBean.getOrientation())); + initUI(); + } + + private void initUI() { + updateUI(); + } + + @Override + public String getUIClassID() { + return SwitchUI.UI_CLASS_ID; + } + + @Override + public void updateUI() { + UIManager.put(TileUI.UI_CLASS_ID, "jcs.ui.layout.tiles.ui.SwitchUI"); + setUI((TileUI) UIManager.getUI(this)); + invalidate(); + } + + @Override + public Map getNeighborPoints() { + Map neighbors = new HashMap<>(); + Orientation orientation = this.getOrientation(); + Direction direction = this.getDirection(); + int cx = this.getCenterX(); + int cy = this.getCenterY(); + + switch (orientation) { + case SOUTH -> { + neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); + neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); + if (Direction.LEFT == direction) { + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); + } else { + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); + } + } + case WEST -> { + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); + if (Direction.LEFT == direction) { + neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); + } else { + neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); + } + } + case NORTH -> { + neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); + neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); + if (Direction.LEFT == direction) { + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); + } else { + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); + } + } + default -> { + //EAST + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); + if (Direction.LEFT == direction) { + neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); + } else { + neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); + } + } + } + return neighbors; + } + + @Override + public Map getEdgePoints() { + Map edgeConnections = new HashMap<>(); + Orientation orientation = this.getOrientation(); + Direction direction = this.getDirection(); + int cx = this.getCenterX(); + int cy = this.getCenterY(); + + switch (orientation) { + case SOUTH -> { + edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); + edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); + if (Direction.LEFT == direction) { + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); + } else { + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); + } + } + case WEST -> { + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); + if (Direction.LEFT == direction) { + edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); + } else { + edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); + } + } + case NORTH -> { + edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); + edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); + if (Direction.LEFT == direction) { + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); + } else { + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); + } + } + default -> { + //EAST + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); + if (Direction.LEFT == direction) { + edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); + } else { + edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); + } + } + } + return edgeConnections; + } + +// protected void renderStraight(Graphics2D g2, Color color) { +// int xx, yy, w, h; +// xx = 0; +// yy = 170; +// w = RENDER_WIDTH; +// h = 60; +// +// g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); +// g2.setPaint(color); +// +// g2.fillRect(xx, yy, w, h); +// } +// protected void renderDiagonal(Graphics2D g2, Color color) { +// int[] xPoints, yPoints; +// if (Direction.RIGHT.equals(getDirection())) { +// xPoints = new int[]{400, 400, 170, 230}; +// yPoints = new int[]{170, 230, 0, 0}; +// } else { +// xPoints = new int[]{400, 400, 170, 230}; +// yPoints = new int[]{230, 170, 400, 400}; +// } +// +// g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); +// g2.setPaint(color); +// g2.fillPolygon(xPoints, yPoints, xPoints.length); +// } +// protected void renderRouteStraight(Graphics2D g2, Color color) { +// int xx, yy, w, h; +// xx = 0; +// yy = 190; +// w = RENDER_WIDTH; +// h = 20; +// +// g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); +// g2.setPaint(color); +// +// g2.fillRect(xx, yy, w, h); +// } +// protected void renderRouteDiagonal(Graphics2D g2, Color color) { +// int[] xPoints, yPoints; +// if (Direction.RIGHT.equals(getDirection())) { +// xPoints = new int[]{400, 400, 190, 210}; +// yPoints = new int[]{190, 210, 0, 0}; +// } else { +// xPoints = new int[]{400, 400, 190, 210}; +// yPoints = new int[]{210, 190, 400, 400}; +// } +// +// g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); +// g2.setPaint(color); +// +// g2.fillPolygon(xPoints, yPoints, xPoints.length); +// } +// @Override +// public void renderTile(Graphics2D g2) { +// if (accessoryValue == null) { +// this.accessoryValue = AccessoryValue.OFF; +// } +// +// switch (accessoryValue) { +// case RED -> { +// renderStraight(g2, trackColor); +// renderDiagonal(g2, Color.red); +// } +// case GREEN -> { +// renderDiagonal(g2, trackColor); +// renderStraight(g2, Color.green); +// } +// default -> { +// renderStraight(g2, trackColor); +// renderDiagonal(g2, trackColor); +// } +// } +// } +// @Override +// public void renderTileRoute(Graphics2D g2) { +// if (routeValue == null) { +// routeValue = AccessoryValue.OFF; +// } +// switch (routeValue) { +// case RED -> { +// renderRouteDiagonal(g2, trackRouteColor); +// } +// case GREEN -> { +// renderRouteStraight(g2, trackRouteColor); +// } +// default -> { +// } +// } +// } + @Override + public void onAccessoryChange(AccessoryEvent event) { + if (getAccessoryBean() != null && event.isEventFor(accessoryBean)) { + setAccessoryValue(event.getAccessoryBean().getAccessoryValue()); + } + } + + @Override + public boolean isJunction() { + return true; + } + + @Override + public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { + if (from != null && to != null && this.getDirection() != null) { + switch (this.getDirection()) { + case LEFT -> { + if (this.isHorizontal()) { + if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { + return AccessoryValue.GREEN; + } else if (((from == Orientation.EAST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.EAST)) && Orientation.EAST == this.getOrientation()) { + return AccessoryValue.RED; + } else if (((from == Orientation.WEST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.WEST)) && Orientation.WEST == this.getOrientation()) { + return AccessoryValue.RED; + } else { + return AccessoryValue.OFF; + } + } else { + //Vertical + if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { + return AccessoryValue.GREEN; + } else if (((from == Orientation.SOUTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.SOUTH)) && Orientation.SOUTH == this.getOrientation()) { + return AccessoryValue.RED; + } else if (((from == Orientation.NORTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.NORTH)) && Orientation.NORTH == this.getOrientation()) { + return AccessoryValue.RED; + } else { + return AccessoryValue.OFF; + } + } + } + case RIGHT -> { + if (this.isHorizontal()) { + if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { + return AccessoryValue.GREEN; + } else if (((from == Orientation.EAST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.EAST)) && Orientation.EAST == this.getOrientation()) { + return AccessoryValue.RED; + } else if (((from == Orientation.WEST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.WEST)) && Orientation.WEST == this.getOrientation()) { + return AccessoryValue.RED; + } else { + return AccessoryValue.OFF; + } + } else { + //Vertical + if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { + return AccessoryValue.GREEN; + } else if (((from == Orientation.EAST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.EAST)) && Orientation.SOUTH == this.getOrientation()) { + return AccessoryValue.RED; + } else if (((from == Orientation.WEST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.WEST)) && Orientation.NORTH == this.getOrientation()) { + return AccessoryValue.RED; + } else { + return AccessoryValue.OFF; + } + } + } + default -> { + return AccessoryValue.OFF; + } + } + } else { + return AccessoryValue.OFF; + } + } +} diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java index 44b3636a..688c48f8 100755 --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -15,6 +15,7 @@ */ package jcs.ui.layout.tiles; +import jcs.ui.layout.tiles.ui.TileUI; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; @@ -24,7 +25,6 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.AffineTransform; -import java.awt.geom.Ellipse2D; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; import java.beans.PropertyChangeListener; @@ -53,9 +53,6 @@ import jcs.ui.layout.LayoutUtil; import static jcs.ui.layout.tiles.Block.BLOCK_HEIGHT; import static jcs.ui.layout.tiles.Block.BLOCK_WIDTH; -import org.imgscalr.Scalr; -import org.imgscalr.Scalr.Method; -import org.imgscalr.Scalr.Mode; import org.tinylog.Logger; /** @@ -75,16 +72,15 @@ *

* A Tile is rendered to a Buffered Image to speed up the display */ -public abstract class Tile extends JComponent { //implements TileEventListener { //, ItemSelectable { +public abstract class Tile extends JComponent { // implements ChangeListener public static final int GRID = 20; public static final int DEFAULT_WIDTH = GRID * 2; public static final int DEFAULT_HEIGHT = GRID * 2; - static final int RENDER_GRID = GRID * 10; - static final int RENDER_WIDTH = RENDER_GRID * 2; - static final int RENDER_HEIGHT = RENDER_GRID * 2; - + //static final int RENDER_GRID = GRID * 10; + //static final int RENDER_WIDTH = RENDER_GRID * 2; + //static final int RENDER_HEIGHT = RENDER_GRID * 2; public static final Color DEFAULT_BACKGROUND_COLOR = Color.white; public static final Color DEFAULT_TRACK_COLOR = Color.lightGray; public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.darkGray; @@ -92,7 +88,7 @@ public abstract class Tile extends JComponent { //implements TileEventListener { public static final Color DEFAULT_WARN_COLOR = Color.red; public static final String MODEL_CHANGED_PROPERTY = "model"; - public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled"; +// public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled"; /** * The data model that determines the button's state. @@ -103,10 +99,8 @@ public abstract class Tile extends JComponent { //implements TileEventListener { protected Integer tileX; protected Integer tileY; - protected int renderWidth; - protected int renderHeight; - - //protected Orientation tileOrientation; + //protected int renderWidth; + //protected int renderHeight; protected Direction tileDirection; protected TileType tileType; @@ -126,18 +120,16 @@ public abstract class Tile extends JComponent { //implements TileEventListener { protected List neighbours; - protected int offsetX = 0; - protected int offsetY = 0; +// protected int offsetX = 0; +// protected int offsetY = 0; protected int renderOffsetX = 0; protected int renderOffsetY = 0; - //protected Color selectedColor; - protected Color trackColor; - protected Color trackRouteColor; - protected Orientation incomingSide; - - protected Color backgroundColor; + //protected Color trackColor; + //protected Color trackRouteColor; + //protected Orientation incomingSide; + //protected Color backgroundColor; protected boolean drawName = true; protected BufferedImage tileImage; @@ -148,7 +140,6 @@ public abstract class Tile extends JComponent { //implements TileEventListener { protected ActionListener actionListener = null; protected transient ChangeEvent changeEvent; - private Handler handler; protected Tile(TileType tileType, Orientation orientation, Point center, int width, int height) { @@ -165,8 +156,6 @@ protected Tile(TileType tileType, Orientation orientation, Direction direction, protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height, Color backgroundColor, Color selectedColor) { this.tileType = tileType; - //this.tileOrientation = orientation; - //model.setTileOrienation(orientation); this.tileDirection = direction; this.tileX = x; this.tileY = y; @@ -176,19 +165,13 @@ protected Tile(TileType tileType, Orientation orientation, Direction direction, setSize(d); setPreferredSize(d); - this.renderWidth = RENDER_WIDTH; - this.renderHeight = RENDER_HEIGHT; - - this.trackColor = DEFAULT_TRACK_COLOR; - this.backgroundColor = backgroundColor; - //this.selectedColor = selectedColor; - - if (this.backgroundColor == null) { - this.backgroundColor = DEFAULT_BACKGROUND_COLOR; - } -// if (this.selectedColor == null) { -// this.selectedColor = DEFAULT_SELECTED_COLOR; -// } + //this.renderWidth = RENDER_WIDTH; + //this.renderHeight = RENDER_HEIGHT; + //this.trackColor = DEFAULT_TRACK_COLOR; + //this.backgroundColor = backgroundColor; + //if (this.backgroundColor == null) { + // this.backgroundColor = DEFAULT_BACKGROUND_COLOR; + //} } protected Tile(TileBean tileBean) { @@ -200,8 +183,6 @@ protected Tile(TileBean tileBean, int width, int height) { //Quick properties this.id = tileBean.getId(); this.tileType = tileBean.getTileType(); - //this.tileOrientation = tileBean.getOrientation(); - //this.model.setTileOrienation(tileBean.getOrientation()); this.tileDirection = tileBean.getDirection(); this.tileX = tileBean.getX(); this.tileY = tileBean.getY(); @@ -219,13 +200,70 @@ protected Tile(TileBean tileBean, int width, int height) { setSize(d); setPreferredSize(d); - this.trackColor = DEFAULT_TRACK_COLOR; - this.backgroundColor = DEFAULT_BACKGROUND_COLOR; -// this.selectedColor = DEFAULT_SELECTED_COLOR; - this.renderWidth = RENDER_WIDTH; - this.renderHeight = RENDER_HEIGHT; + //this.trackColor = DEFAULT_TRACK_COLOR; + //this.backgroundColor = DEFAULT_BACKGROUND_COLOR; + //this.renderWidth = RENDER_WIDTH; + //this.renderHeight = RENDER_HEIGHT; + } + + @Override + public String getUIClassID() { + return TileUI.UI_CLASS_ID; } + @Override + public TileUI getUI() { + return (TileUI) ui; + } + + public void setUI(TileUI ui) { + super.setUI(ui); + } + + public TileModel getModel() { + return model; + } + + public void setModel(TileModel newModel) { + TileModel oldModel = getModel(); + + if (oldModel != null) { + oldModel.removeChangeListener(changeListener); + oldModel.removeActionListener(actionListener); + changeListener = null; + actionListener = null; + } + + model = newModel; + + if (newModel != null) { + changeListener = createChangeListener(); + actionListener = createActionListener(); + + newModel.addChangeListener(changeListener); + newModel.addActionListener(actionListener); + } + + firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel); + if (newModel != oldModel) { + revalidate(); + repaint(); + } + } + +// @Override +// public String getUIClassID() { +// return TileUI.UI_CLASS_ID; +// } +// @Override +// public void updateUI() { +// if (UIManager.get(TileUI.UI_CLASS_ID) == null) { +// UIManager.put(TileUI.UI_CLASS_ID, getUIClassID()); +// } +// +// setUI((TileUI) UIManager.getUI(this)); +// invalidate(); +// } protected static int tileWidth(Orientation orientation, TileType tileType) { if (Orientation.EAST == orientation || Orientation.WEST == orientation) { if (null == tileType) { @@ -299,7 +337,6 @@ public boolean isSelected() { } public void setSelected(boolean b) { - //boolean oldValue = isSelected(); model.setSelected(b); } @@ -340,12 +377,10 @@ public void setCenter(Point center) { } public Orientation getOrientation() { - //return tileOrientation; return model.getTileOrienation(); } public void setOrientation(Orientation orientation) { - //this.tileOrientation = orientation; model.setTileOrienation(orientation); if (tileBean != null) { tileBean.setOrientation(orientation); @@ -518,14 +553,12 @@ public void setBlockBean(BlockBean blockBean) { this.blockBean = blockBean; } - public void setRenderWidth(int renderWidth) { - this.renderWidth = renderWidth; - } - - public void setRenderHeight(int renderHeight) { - this.renderHeight = renderHeight; - } - +// public void setRenderWidth(int renderWidth) { +// this.renderWidth = renderWidth; +// } +// public void setRenderHeight(int renderHeight) { +// this.renderHeight = renderHeight; +// } public int getRenderOffsetX() { return renderOffsetX; } @@ -550,20 +583,22 @@ public final void setTileType(TileType tileType) { this.tileType = tileType; } - public Color getTrackColor() { - return trackColor; - } - - public final void setTrackColor(Color trackColor) { - this.trackColor = trackColor; - } - - public Color getTrackRouteColor() { - return trackRouteColor; +// public Color getTrackColor() { +// return trackColor; +// } + public void setTrackColor(Color trackColor) { + if (getUI() != null) { + getUI().setTrackColor(trackColor); + } } +// public Color getTrackRouteColor() { +// return trackRouteColor; +// } public void setTrackRouteColor(Color trackRouteColor) { - this.trackRouteColor = trackRouteColor; + if (getUI() != null) { + getUI().setTrackRouteColor(trackRouteColor); + } } public Color getSelectedColor() { @@ -571,25 +606,23 @@ public Color getSelectedColor() { } public void setSelectedColor(Color selectedColor) { - this.model.setSelectedColor(selectedColor); + model.setSelectedColor(selectedColor); } public Orientation getIncomingSide() { - return incomingSide; + return model.getIncomingSide(); } public void setIncomingSide(Orientation incomingSide) { - this.incomingSide = incomingSide; - } - - public Color getBackgroundColor() { - return backgroundColor; - } - - public void setBackgroundColor(Color backgroundColor) { - this.backgroundColor = backgroundColor; + model.setIncomingSide(incomingSide); } +// public Color getBackgroundColor() { +// return backgroundColor; +// } +// public void setBackgroundColor(Color backgroundColor) { +// this.backgroundColor = backgroundColor; +// } public boolean isShowRoute() { return model.isShowRoute(); } @@ -598,25 +631,18 @@ public void setShowRoute(boolean drawRoute) { this.model.setShowRoute(drawRoute); } - public int getRenderWidth() { - return renderWidth; - } - - public int getRenderHeight() { - return renderHeight; - } - - abstract void renderTile(Graphics2D g2d); - - abstract void renderTileRoute(Graphics2D g2d); - +// public int getRenderWidth() { +// return renderWidth; +// } +// public int getRenderHeight() { +// return renderHeight; +// } +// abstract void renderTile(Graphics2D g2d); +// abstract void renderTileRoute(Graphics2D g2d); public abstract Map getNeighborPoints(); public abstract Map getEdgePoints(); - //public abstract Set getAllPoints(); - //public abstract Set getAllPoints(Point center); - //public abstract Set getAltPoints(Point center); Set getAltPoints(Point center) { return Collections.EMPTY_SET; } @@ -636,102 +662,96 @@ Set getAllPoints(Point center) { * * @param g2d The graphics handle */ - public void drawTile(Graphics2D g2d) { - // by default and image is rendered in the EAST orientation - Orientation tileOrientation = model.getTileOrienation(); - - BufferedImage bf = createImage(); - Graphics2D g2di = bf.createGraphics(); - - //Avoid errors - if (model.isShowRoute() && incomingSide == null) { - incomingSide = getOrientation(); - } - - if (model.isSelected()) { - g2di.setBackground(model.getSelectedColor()); - } else { - g2di.setBackground(backgroundColor); - } - - g2di.clearRect(0, 0, renderWidth, renderHeight); - int ox = 0, oy = 0; - - AffineTransform trans = new AffineTransform(); - switch (tileOrientation) { - case SOUTH -> { - trans.rotate(Math.PI / 2, renderWidth / 2, renderHeight / 2); - ox = (renderHeight - renderWidth) / 2; - oy = (renderWidth - renderHeight) / 2; - trans.translate(-ox, -oy); - } - case WEST -> { - trans.rotate(Math.PI, renderWidth / 2, renderHeight / 2); - trans.translate(ox, oy); - } - case NORTH -> { - trans.rotate(-Math.PI / 2, renderWidth / 2, renderHeight / 2); - ox = (renderHeight - renderWidth) / 2; - oy = (renderWidth - renderHeight) / 2; - trans.translate(-ox, -oy); - } - default -> { - trans.rotate(0.0, this.renderWidth / 2, this.renderHeight / 2); - trans.translate(ox, oy); - } - } - - //Logger.trace(tileOrientation.getOrientation() + " renderWidth: " + renderWidth + " renderHeight: " + renderHeight + " CP: (" + renderWidth / 2 + "," + renderHeight / 2 + ")"); - //Logger.trace(tileOrientation.getOrientation() + " ox: " + ox + " oy: " + oy); - g2di.setTransform(trans); - - renderTile(g2di); - - if (model.isShowRoute()) { - renderTileRoute(g2di); - } - - if (model.isShowCenter()) { - drawCenterPoint(g2di); - } - - // Scale the image back... - if (model.isScaleImage()) { - tileImage = Scalr.resize(bf, Method.AUTOMATIC, Mode.FIT_EXACT, getWidth(), getHeight(), Scalr.OP_ANTIALIAS); - } else { - tileImage = bf; - } - g2di.dispose(); - } - - public BufferedImage getTileImage() { - return tileImage; - } - +// public void drawTile(Graphics2D g2d) { +// // by default and image is rendered in the EAST orientation +// Orientation tileOrientation = model.getTileOrienation(); +// +// BufferedImage bf = createImage(); +// Graphics2D g2di = bf.createGraphics(); +// +// //Avoid errors +// if (model.isShowRoute() && model.getIncomingSide() == null) { +// model.setIncomingSide(tileOrientation); +// } +// +// if (model.isSelected()) { +// g2di.setBackground(model.getSelectedColor()); +// } else { +// g2di.setBackground(backgroundColor); +// } +// +// g2di.clearRect(0, 0, renderWidth, renderHeight); +// int ox = 0, oy = 0; +// +// AffineTransform trans = new AffineTransform(); +// switch (tileOrientation) { +// case SOUTH -> { +// trans.rotate(Math.PI / 2, renderWidth / 2, renderHeight / 2); +// ox = (renderHeight - renderWidth) / 2; +// oy = (renderWidth - renderHeight) / 2; +// trans.translate(-ox, -oy); +// } +// case WEST -> { +// trans.rotate(Math.PI, renderWidth / 2, renderHeight / 2); +// trans.translate(ox, oy); +// } +// case NORTH -> { +// trans.rotate(-Math.PI / 2, renderWidth / 2, renderHeight / 2); +// ox = (renderHeight - renderWidth) / 2; +// oy = (renderWidth - renderHeight) / 2; +// trans.translate(-ox, -oy); +// } +// default -> { +// trans.rotate(0.0, this.renderWidth / 2, this.renderHeight / 2); +// trans.translate(ox, oy); +// } +// } +// +// //Logger.trace(tileOrientation.getOrientation() + " renderWidth: " + renderWidth + " renderHeight: " + renderHeight + " CP: (" + renderWidth / 2 + "," + renderHeight / 2 + ")"); +// //Logger.trace(tileOrientation.getOrientation() + " ox: " + ox + " oy: " + oy); +// g2di.setTransform(trans); +// +// renderTile(g2di); +// +// if (model.isShowRoute()) { +// renderTileRoute(g2di); +// } +// +// if (model.isShowCenter()) { +// drawCenterPoint(g2di); +// } +// +// // Scale the image back... +// if (model.isScaleImage()) { +// tileImage = Scalr.resize(bf, Method.AUTOMATIC, Mode.FIT_EXACT, getWidth(), getHeight(), Scalr.OP_ANTIALIAS); +// } else { +// tileImage = bf; +// } +// g2di.dispose(); +// } +// public BufferedImage getTileImage() { +// return tileImage; +// } /** * Render a tile image Always starts at (0,0) used the default width and height * * @param g2 the Graphic context */ - public void drawName(Graphics2D g2) { - } - - protected void drawCenterPoint(Graphics2D g2d) { - drawCenterPoint(g2d, Color.magenta); - } - - protected void drawCenterPoint(Graphics2D g2, Color color) { - drawCenterPoint(g2, color, 60); - } - - protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { - double dX = (renderWidth / 2 - size / 2); - double dY = (renderHeight / 2 - size / 2); - - g2d.setColor(color); - g2d.fill(new Ellipse2D.Double(dX, dY, size, size)); - } - +// public void drawName(Graphics2D g2) { +// } +// protected void drawCenterPoint(Graphics2D g2d) { +// drawCenterPoint(g2d, Color.magenta); +// } +// protected void drawCenterPoint(Graphics2D g2, Color color) { +// drawCenterPoint(g2, color, 60); +// } +// protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { +// double dX = (renderWidth / 2 - size / 2); +// double dY = (renderHeight / 2 - size / 2); +// +// g2d.setColor(color); +// g2d.fill(new Ellipse2D.Double(dX, dY, size, size)); +// } /** * Rotate the tile clockwise 90 deg * @@ -774,13 +794,13 @@ public void move(int newX, int newY) { setCenter(cs); } - protected static void drawRotate(Graphics2D g2d, double x, double y, int angle, String text) { - g2d.translate((float) x, (float) y); - g2d.rotate(Math.toRadians(angle)); - g2d.drawString(text, 0, 0); - g2d.rotate(-Math.toRadians(angle)); - g2d.translate(-x, -y); - } +// protected static void drawRotate(Graphics2D g2d, double x, double y, int angle, String text) { +// g2d.translate((float) x, (float) y); +// g2d.rotate(Math.toRadians(angle)); +// g2d.drawString(text, 0, 0); +// g2d.rotate(-Math.toRadians(angle)); +// g2d.translate(-x, -y); +// } public static BufferedImage flipHorizontally(BufferedImage source) { BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); @@ -810,26 +830,25 @@ public Set getAltPoints() { return Collections.EMPTY_SET; } - public final int getOffsetX() { - return offsetX; - } - - public void setOffsetX(int offsetX) { - this.offsetX = offsetX; - } - - public final int getOffsetY() { - return offsetY; - } - - public void setOffsetY(int offsetY) { - this.offsetY = offsetY; - } - - protected BufferedImage createImage() { - return new BufferedImage(renderWidth, renderHeight, BufferedImage.TYPE_INT_RGB); - } - +// public final int getOffsetX() { +// return offsetX; +// } +// +// public void setOffsetX(int offsetX) { +// this.offsetX = offsetX; +// } +// +// public final int getOffsetY() { +// return offsetY; +// } +// +// public void setOffsetY(int offsetY) { +// this.offsetY = offsetY; +// } + +// protected BufferedImage createImage() { +// return new BufferedImage(renderWidth, renderHeight, BufferedImage.TYPE_INT_RGB); +// } public int getCenterX() { if (tileX > 0) { return this.tileX; @@ -863,12 +882,14 @@ public void setScaleImage(boolean scaleImage) { if (scaleImage) { d = new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); } else { + int renderWidth = getUI().getRenderWidth(); + int renderHeight = getUI().getRenderHeight(); + d = new Dimension(renderWidth, renderHeight); } setSize(d); setPreferredSize(d); - model.setScaleImage(scaleImage); } @@ -1010,47 +1031,6 @@ public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { return AccessoryValue.OFF; } - public TileModel getModel() { - return model; - } - - public void setModel(TileModel newModel) { - TileModel oldModel = getModel(); - - if (oldModel != null) { - oldModel.removeChangeListener(changeListener); - oldModel.removeActionListener(actionListener); - changeListener = null; - actionListener = null; - } - - model = newModel; - - if (newModel != null) { - changeListener = createChangeListener(); - actionListener = createActionListener(); - - newModel.addChangeListener(changeListener); - newModel.addActionListener(actionListener); - } - - firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel); - if (newModel != oldModel) { - revalidate(); - repaint(); - } - } - -// public TileUI getUI() { -// return (TileUI) ui; -// } -// public void setUI(TileUI ui) { -// super.setUI(ui); -// } - @Override - public void updateUI() { - } - protected ChangeListener createChangeListener() { return getHandler(); } @@ -1119,6 +1099,9 @@ public Rectangle getTileBounds() { if (model.isScaleImage()) { return new Rectangle(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); } else { + int renderWidth = getUI().getRenderWidth(); + int renderHeight = getUI().getRenderHeight(); + return new Rectangle(tileX - renderWidth / 2, tileY - renderHeight / 2, renderWidth, renderHeight); } } @@ -1127,13 +1110,14 @@ public Rectangle getTileBounds() { protected void paintComponent(Graphics g) { long started = System.currentTimeMillis(); - Graphics2D g2 = (Graphics2D) g.create(); - //Graphics2D g2 = (Graphics2D) g.create(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); - drawTile(g2); - g2.dispose(); - - g.drawImage(tileImage, 0, 0, null); + super.paintComponent(g); + //Graphics2D g2 = (Graphics2D) g.create(); + //Graphics2D g2 = (Graphics2D) g.create(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); + //drawTile(g2); + //getUI().drawTile(g2, this); + //g2.dispose(); + //g.drawImage(tileImage, 0, 0, null); long now = System.currentTimeMillis(); Logger.trace(id + " Duration: " + (now - started) + " ms. Cp: " + xyToString() + " O: " + model.getTileOrienation()); } diff --git a/src/main/java/jcs/ui/layout/tiles/Tile1.java b/src/main/java/jcs/ui/layout/tiles/Tile1.java deleted file mode 100644 index b01cb9be..00000000 --- a/src/main/java/jcs/ui/layout/tiles/Tile1.java +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright 2023 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout.tiles; - -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.Point; -import java.awt.Shape; -import java.awt.image.BufferedImage; -import java.beans.PropertyChangeListener; -import java.util.Map; -import java.util.Set; -import jcs.entities.AccessoryBean.AccessoryValue; -import jcs.entities.TileBean; -import jcs.entities.TileBean.Direction; -import jcs.entities.TileBean.Orientation; -import jcs.entities.TileBean.TileType; - -/** - * @author frans - */ -public interface Tile1 extends Shape { - - public static final int GRID = 20; - public static final int DEFAULT_WIDTH = GRID * 2; - public static final int DEFAULT_HEIGHT = GRID * 2; - - static final int RENDER_GRID = GRID * 10; - static final int RENDER_WIDTH = RENDER_GRID * 2; - static final int RENDER_HEIGHT = RENDER_GRID * 2; - - public static final Color DEFAULT_BACKGROUND_COLOR = Color.white; - public static final Color DEFAULT_TRACK_COLOR = Color.lightGray; - public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.blue; - - boolean isDrawRoute(); - - void setDrawRoute(boolean drawRoute); - - Color getTrackColor(); - - void setTrackColor(Color trackColor); - - Color getTrackRouteColor(); - - void setTrackRouteColor(Color trackRouteColor); - - Orientation getIncomingSide(); - - void setIncomingSide(Orientation incomingSide); - - Color getBackgroundColor(); - - void setBackgroundColor(Color backgroundColor); - - String getId(); - - void setId(String id); - - //String getImageKey(); - - BufferedImage getTileImage(); - - void drawTile(Graphics2D g2d, boolean drawOutline); - - void renderTile(Graphics2D g2d); - - void renderTileRoute(Graphics2D g2d); - - void drawName(Graphics2D g2); - - void drawCenterPoint(Graphics2D g2d); - - void drawCenterPoint(Graphics2D g2, Color color); - - void drawCenterPoint(Graphics2D g2d, Color color, double size); - - void drawBounds(Graphics2D g2d); - - void rotate(); - - void flipHorizontal(); - - void flipVertical(); - - void move(int newX, int newY); - - TileBean.Orientation getOrientation(); - - void setOrientation(TileBean.Orientation orientation); - - Direction getDirection(); - - void setDirection(Direction direction); - - Point getCenter(); - - void setCenter(Point center); - - /** - * @return a Set of alternative points in case the tile is not a square - */ - Set getAltPoints(); - - /** - * @return All points relevant for the Object on the Canvas - */ - Set getAllPoints(); - - int getOffsetX(); - - void setOffsetX(int offsetX); - - int getOffsetY(); - - void setOffsetY(int offsetY); - - int getHeight(); - - int getWidth(); - - /** - * @return the X (pixel) coordinate of the center of the tile - */ - int getCenterX(); - - /** - * @return then Y (pixel) coordinate of the center of the tile - */ - int getCenterY(); - - TileBean getTileBean(); - - boolean isDrawOutline(); - - void setDrawOutline(boolean drawOutline); - - TileType getTileType(); - - void setPropertyChangeListener(PropertyChangeListener listener); - - String xyToString(); - - /** - * @return the X number of the grid square (grid is 40 x 40 pix) - */ - int getGridX(); - - /** - * @return the Y number of the grid square (grid is 40 x 40 pix) - */ - int getGridY(); - - /** - * The main route of the tile is horizontal - * - * @return true when main route goes from East to West or vv - */ - boolean isHorizontal(); - - /** - * The main route of the tile is vertical - * - * @return true when main route goes from North to South or vv - */ - boolean isVertical(); - - /** - * The main route of the tile is diagonal - * - * @return true when main route goes from North to East or West to South and vv - */ - boolean isDiagonal(); - - boolean isJunction(); - - boolean isBlock(); - - boolean isDirectional(); - - boolean isCrossing(); - - Map getNeighborPoints(); - - Map getNeighborOrientations(); - - Map getEdgePoints(); - - Map getEdgeOrientations(); - - AccessoryValue accessoryValueForRoute(Orientation from, Orientation to); - - /** - * @param other a tile to check with this tile - * @return true when the other tile is adjacent to this and the "tracks" connect - */ - boolean isAdjacent(Tile1 other); - - String getIdSuffix(Tile1 other); - - /** - * When the tile has a specific direction a train may travel then this method will indicate whether the other tile is in on the side where the arrow is pointing to - * - * @param other A Tile - * @return true where other is on the side of this tile where the arrow points to - */ - boolean isArrowDirection(Tile1 other); -} diff --git a/src/main/java/jcs/ui/layout/tiles/TileModel.java b/src/main/java/jcs/ui/layout/tiles/TileModel.java index 4280d06e..31a4cb28 100644 --- a/src/main/java/jcs/ui/layout/tiles/TileModel.java +++ b/src/main/java/jcs/ui/layout/tiles/TileModel.java @@ -1,5 +1,5 @@ /* - * Copyright 2025 fransjacobs. + * Copyright 2025 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -49,6 +49,10 @@ public interface TileModel extends Serializable { void setTileOrienation(TileBean.Orientation tileOrienation); + public TileBean.Orientation getIncomingSide(); + + void setIncomingSide(TileBean.Orientation incomingSide); + boolean isShowRoute(); public void setShowRoute(boolean showRoute); diff --git a/src/main/java/jcs/ui/layout/tiles/enums/Rotation.java b/src/main/java/jcs/ui/layout/tiles/enums/Rotation.java deleted file mode 100755 index a535050f..00000000 --- a/src/main/java/jcs/ui/layout/tiles/enums/Rotation.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2019 Frans Jacobs. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA - */ -package jcs.ui.layout.tiles.enums; - -import java.util.Collections; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -public enum Rotation { - R0("R0"), R90("R90"), R180("R180"), R270("R270"); - - private final String rotation; - private static final Map ENUM_MAP; - - Rotation(String rotation) { - this.rotation = rotation; - } - - static { - Map map = new ConcurrentHashMap<>(); - for (Rotation instance : Rotation.values()) { - map.put(instance.getRotation(), instance); - } - ENUM_MAP = Collections.unmodifiableMap(map); - } - - public String getRotation() { - return this.rotation; - } - - public static Rotation get(String rotation) { - return ENUM_MAP.get(rotation); - } -} diff --git a/src/main/java/jcs/ui/layout/tiles/ui/BlockUI.java b/src/main/java/jcs/ui/layout/tiles/ui/BlockUI.java new file mode 100644 index 00000000..41ac8b24 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/ui/BlockUI.java @@ -0,0 +1,506 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles.ui; + +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.Insets; +import java.awt.geom.Ellipse2D; +import java.awt.image.BufferedImage; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import jcs.entities.BlockBean; +import static jcs.entities.BlockBean.BlockState.GHOST; +import static jcs.entities.BlockBean.BlockState.INBOUND; +import static jcs.entities.BlockBean.BlockState.LOCKED; +import static jcs.entities.BlockBean.BlockState.OCCUPIED; +import static jcs.entities.BlockBean.BlockState.OUTBOUND; +import static jcs.entities.BlockBean.BlockState.OUT_OF_ORDER; +import jcs.entities.LocomotiveBean; +import jcs.entities.TileBean; +import static jcs.entities.TileBean.Orientation.EAST; +import static jcs.entities.TileBean.Orientation.NORTH; +import static jcs.entities.TileBean.Orientation.SOUTH; +import static jcs.entities.TileBean.Orientation.WEST; +import jcs.ui.layout.tiles.Block; +import static jcs.ui.layout.tiles.Block.BLOCK_HEIGHT; +import static jcs.ui.layout.tiles.Block.BLOCK_WIDTH; +import jcs.ui.layout.tiles.Tile; +import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; +import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; +import static jcs.ui.layout.tiles.Tile.GRID; +import jcs.ui.layout.tiles.TileModel; +import jcs.ui.util.ImageUtil; +import org.tinylog.Logger; + +public class BlockUI extends TileUI { + + public BlockUI() { + } + + public static ComponentUI createUI(JComponent c) { + return new BlockUI(); + } + +// Color getBlockStateColor() { +// return getBlockStateColor(this.model.getBlockState()); +// } + protected Color getBlockStateColor(BlockBean.BlockState blockState) { + return switch (blockState) { + case GHOST -> + new Color(250, 0, 0); + case LOCKED -> + new Color(250, 250, 210); + case OCCUPIED -> + new Color(250, 210, 210); + case OUT_OF_ORDER -> + new Color(190, 190, 190); + case OUTBOUND -> + new Color(210, 250, 210); + case INBOUND -> + new Color(250, 210, 250); + default -> + new Color(255, 255, 255); + }; + } + + @Override + public void renderTile(Graphics2D g2, JComponent c) { + Tile tile = (Tile) c; + TileModel model = tile.getModel(); + + int xx = 20; + int yy = 50; + int rw = RENDER_WIDTH * 3 - 40; + int rh = 300; + + g2.setStroke(new BasicStroke(3, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); + + g2.setPaint(Color.darkGray); + g2.drawRoundRect(xx, yy, rw, rh, 15, 15); + + Color blockStateColor = getBlockStateColor(model.getBlockState()); + //Logger.trace("Block " + this.id + " State: " + this.getBlockBean().getBlockState().getState() + " Color: " + blockStateColor.toString()); + g2.setPaint(blockStateColor); + g2.fillRoundRect(xx, yy, rw, rh, 15, 15); + + g2.setStroke(new BasicStroke(20, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); + g2.setPaint(Color.darkGray); + g2.drawLine(rw + GRID, yy - 0, rw + GRID, yy + 300); + + //When there is a locomotive in the block mark the direction of travel. + //The default, forwards is in the direction of the block orientation, i.e. the + + if (model.getLocomotive() != null && model.getLocomotive().getName() != null) { + renderDirectionArrow(g2, c); + } + + drawName(g2, c); + } + + private void renderDirectionArrow(Graphics2D g2, JComponent c) { + Tile tile = (Tile) c; + TileModel model = tile.getModel(); + + //The default, forwards is in the direction of the block orientation, i.e. the + + TileBean.Orientation tileOrientation = model.getTileOrienation(); + BlockBean bb = tile.getBlockBean(); + boolean reverseArrival = model.isReverseArrival(); + + LocomotiveBean.Direction logicalDirection; + if (bb.getLogicalDirection() != null) { + logicalDirection = model.getLogicalDirection(); + } else { + logicalDirection = model.getLocomotive().getDirection(); + } + + String departureSuffix = model.getDepartureSuffix(); + if (departureSuffix == null) { + departureSuffix = Block.getDepartureSuffix(tileOrientation, reverseArrival, logicalDirection); + } + + //Logger.trace(this.getId()+" LogicalDirection is " + (bb.getLogicalDirection() != null ? "Set" : "Not Set") + " Dir: " + logicalDirection.getDirection() + " Orientation: " + orientation.getOrientation() + " departureSuffix: " + departureSuffix); + if ("+".equals(departureSuffix)) { + if (TileBean.Orientation.EAST == tileOrientation || TileBean.Orientation.SOUTH == tileOrientation) { + switch (logicalDirection) { + case LocomotiveBean.Direction.FORWARDS -> { + if (reverseArrival) { + renderLeftArrow(g2); + } else { + renderRightArrow(g2); + } + } + case LocomotiveBean.Direction.BACKWARDS -> { + if (reverseArrival) { + renderRightArrow(g2); + } else { + renderLeftArrow(g2); + } + } + } + } else { + switch (logicalDirection) { + case LocomotiveBean.Direction.BACKWARDS -> { + if (reverseArrival) { + renderLeftArrow(g2); + } else { + renderRightArrow(g2); + } + } + case LocomotiveBean.Direction.FORWARDS -> { + if (reverseArrival) { + renderRightArrow(g2); + } else { + renderLeftArrow(g2); + } + } + } + } + } else { + if (TileBean.Orientation.EAST == tileOrientation || TileBean.Orientation.SOUTH == tileOrientation) { + switch (logicalDirection) { + case LocomotiveBean.Direction.FORWARDS -> { + if (reverseArrival) { + renderLeftArrow(g2); + } else { + renderRightArrow(g2); + } + } + case LocomotiveBean.Direction.BACKWARDS -> { + if (reverseArrival) { + renderRightArrow(g2); + } else { + renderLeftArrow(g2); + } + } + } + } else { + switch (logicalDirection) { + case LocomotiveBean.Direction.BACKWARDS -> { + if (reverseArrival) { + renderLeftArrow(g2); + } else { + renderRightArrow(g2); + } + } + case LocomotiveBean.Direction.FORWARDS -> { + if (reverseArrival) { + renderRightArrow(g2); + } else { + renderLeftArrow(g2); + } + } + } + } + } + } + + private void renderLeftArrow(Graphics2D g2) { + //Logger.trace(this.getId()+" LogicalDirection is " + this.getBlockBean().getLogicalDirection() + " Orientation: " + this.getOrientation() + " departureSuffix: " + this.getBlockBean().getDepartureSuffix()); + g2.fillPolygon(new int[]{0, 50, 50,}, new int[]{200, 150, 250}, 3); + } + + private void renderRightArrow(Graphics2D g2) { + //Logger.trace(this.getId()+" LogicalDirection is " + this.getBlockBean().getLogicalDirection() + " Orientation: " + this.getOrientation() + " departureSuffix: " + this.getBlockBean().getDepartureSuffix()); + g2.fillPolygon(new int[]{1180, 1130, 1130,}, new int[]{200, 150, 250}, 3); + } + + @Override + public void renderTileRoute(Graphics2D g2d, JComponent c) { + Tile tile = (Tile) c; + TileModel model = tile.getModel(); + + if (model.isShowBlockState()) { + backgroundColor = getBlockStateColor(model.getBlockState()); + } + } + + protected void overlayLocImage(JComponent c) { + Tile tile = (Tile) c; + TileModel model = tile.getModel(); + + int ww = tileImage.getWidth(); + int hh = tileImage.getHeight(); + TileBean.Orientation tileOrientation = model.getTileOrienation(); + + BufferedImage overlay = new BufferedImage(ww, hh, BufferedImage.TYPE_INT_ARGB); + Graphics2D g2i = overlay.createGraphics(); + + Image locImage; + if (model.getLocomotive() != null && model.getLocomotive().getLocIcon() != null) { + locImage = model.getLocomotive().getLocIcon(); + } else { + locImage = null; + } + + if (locImage != null) { + String departureSuffix = model.getDepartureSuffix(); + boolean reverseImage = model.isReverseArrival(); + + Logger.trace("LocImage w: " + locImage.getWidth(null) + " h: " + locImage.getHeight(null)); + // scale it to max h of 45 + int size = 45; + float aspect = (float) locImage.getHeight(null) / (float) locImage.getWidth(null); + //TODO: Use Scalr? + locImage = locImage.getScaledInstance(size, (int) (size * aspect), Image.SCALE_SMOOTH); + + //Depending on the block orientation the image needs to be rotated and flipped + //Incase the departure suffix is NOT set center the locomotive image + int w, h, xx, yy; + switch (tileOrientation) { + case WEST -> { + w = locImage.getWidth(null); + h = locImage.getHeight(null); + + if (null == departureSuffix) { + xx = BLOCK_WIDTH / 2 - tile.getWidth() / 2 + w; + } else { + switch (departureSuffix) { + case "+" -> { + xx = BLOCK_WIDTH / 2 - tile.getWidth() / 2 + w - 25; + } + default -> { + xx = BLOCK_WIDTH / 2 - tile.getWidth() / 2 + w + 10; + } + } + } + yy = DEFAULT_HEIGHT / 2 - h / 2; + + if (reverseImage) { + locImage = ImageUtil.flipVertically(locImage); + } + } + case SOUTH -> { + locImage = ImageUtil.flipHorizontally(locImage); + locImage = ImageUtil.rotate(locImage, 90); + + w = locImage.getWidth(null); + h = locImage.getHeight(null); + xx = DEFAULT_WIDTH / 2 - w / 2; + + if (null == departureSuffix) { + yy = BLOCK_HEIGHT / 2 - tile.getHeight() / 2 + h; + } else { + switch (departureSuffix) { + case "-" -> { + yy = BLOCK_HEIGHT / 2 - tile.getHeight() / 2 + h - 25; + } + default -> { + yy = BLOCK_HEIGHT / 2 - tile.getHeight() / 2 + h + 10; + } + } + } + if (reverseImage) { + locImage = ImageUtil.flipHorizontally(locImage); + } + } + case NORTH -> { + locImage = ImageUtil.flipHorizontally(locImage); + locImage = ImageUtil.rotate(locImage, 90); + + w = locImage.getWidth(null); + h = locImage.getHeight(null); + xx = DEFAULT_WIDTH / 2 - w / 2; + + if (null == departureSuffix) { + int minY = BLOCK_HEIGHT / 2 - tile.getHeight() / 2 + h; + yy = minY; + } else { + switch (departureSuffix) { + case "+" -> { + yy = BLOCK_HEIGHT / 2 - tile.getHeight() / 2 + h - 25; + } + default -> { + yy = BLOCK_HEIGHT / 2 - tile.getHeight() / 2 + h + 10; + } + } + } + if (reverseImage) { + locImage = ImageUtil.flipHorizontally(locImage); + } + } + default -> { + w = locImage.getWidth(null); + h = locImage.getHeight(null); + if (null == departureSuffix) { + xx = BLOCK_WIDTH / 2 - tile.getWidth() / 2 + w; + } else { + switch (departureSuffix) { + case "-" -> { + xx = BLOCK_WIDTH / 2 - tile.getWidth() / 2 + w - 25; + } + default -> { + xx = BLOCK_WIDTH / 2 - tile.getWidth() / 2 + w + 10; + } + } + } + yy = DEFAULT_HEIGHT / 2 - h / 2; + + if (reverseImage) { + locImage = ImageUtil.flipVertically(locImage); + } + } + } + + g2i.drawImage(tileImage, 0, 0, null); + g2i.drawImage(locImage, xx, yy, null); + g2i.dispose(); + tileImage = overlay; + } + } + +// private Image getLocImage() { +// if (model.getLocomotive() != null && model.getLocomotive().getLocIcon() != null) { +// return model.getLocomotive().getLocIcon(); +// } else { +// return null; +// } +// } + public String getBlockText(Tile tile) { + BlockBean blockBean = tile.getBlockBean(); + String blockText; + if (blockBean != null && blockBean.getDescription() != null) { + if (blockBean.getLocomotive() != null && blockBean.getLocomotive().getName() != null && BlockBean.BlockState.GHOST != blockBean.getBlockState()) { + blockText = blockBean.getLocomotive().getName(); + } else { + if (blockBean.getDescription().length() > 0) { + blockText = blockBean.getDescription(); + } else { + blockText = tile.getId(); + } + } + } else { + // Design mode show description when available + if (blockBean != null && blockBean.getDescription() != null && blockBean.getDescription().length() > 0) { + blockText = blockBean.getDescription(); + } else { + blockText = tile.getId(); + } + } + return blockText; + } + + @Override + public void drawName(Graphics2D g2d, JComponent c) { + Tile tile = (Tile) c; + TileModel model = tile.getModel(); + + if (!model.isOverlayImage()) { + g2d.setPaint(Color.black); + + Font currentFont = g2d.getFont(); + Font newFont = currentFont.deriveFont(currentFont.getSize() * 10.0F); + g2d.setFont(newFont); + + String blockText = getBlockText(tile); + + // Scale the text if necessary + int textWidth = g2d.getFontMetrics().stringWidth(blockText); + double fontscale = 10.0; + if (textWidth > 845) { + fontscale = fontscale * 847.0 / textWidth; + newFont = currentFont.deriveFont(currentFont.getSize() * (float) fontscale); + g2d.setFont(newFont); + textWidth = g2d.getFontMetrics().stringWidth(blockText); + } + + int textHeight = g2d.getFontMetrics().getHeight(); + TileBean.Orientation tileOrientation = model.getTileOrienation(); + + switch (tileOrientation) { + case EAST -> { + drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) - textWidth / 2, RENDER_GRID + textHeight / 3, 0, blockText); + } + case WEST -> { + drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) + textWidth / 2, RENDER_GRID - textHeight / 3, 180, blockText); + } + case NORTH -> { + drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) - textWidth / 2, RENDER_GRID + textHeight / 3, 0, blockText); + } + case SOUTH -> { + drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) + textWidth / 2, RENDER_GRID - textHeight / 3, 180, blockText); + } + } + // reset to the original font + newFont = currentFont.deriveFont(currentFont.getSize() * 1.0F); + g2d.setFont(newFont); + } + } + + @Override + protected void drawCenterPoint(Graphics2D g2d, Color color, double size, JComponent c) { + Tile tile = (Tile) c; + TileModel model = tile.getModel(); + //A block has 2 alternate points + //1st square + //2nd square holds the centerpoint + //3rd square + TileBean.Orientation tileOrientation = model.getTileOrienation(); + double dX1, dX2, dX3, dY1, dY2, dY3; + if (TileBean.Orientation.EAST == tileOrientation || TileBean.Orientation.WEST == tileOrientation) { + dX1 = renderWidth / 3 / 2 - size / 2 / 2; + dY1 = renderHeight / 2 - size / 2 / 2; + dX2 = renderWidth / 2 - size / 2; + dY2 = renderHeight / 2 - size / 2; + dX3 = renderWidth - renderWidth / 3 / 2 - size / 2 / 2; + dY3 = renderHeight / 2 - size / 2 / 2; + } else { + dX1 = renderWidth / 2 - size / 2 / 2; + dY1 = renderHeight / 3 / 2 - size / 2 / 2; + dX2 = renderHeight / 2 - size / 2; + dY2 = renderWidth / 2 - size / 2; + dY3 = renderWidth / 2 - size / 2 / 2; + dX3 = renderHeight - renderHeight / 3 / 2 - size / 2 / 2; + } + + g2d.setColor(color); + g2d.fill(new Ellipse2D.Double(dX1, dY1, size / 2, size / 2)); + g2d.fill(new Ellipse2D.Double(dX2, dY2, size, size)); + g2d.fill(new Ellipse2D.Double(dX3, dY3, size / 2, size / 2)); + } + + @Override + public void paint(Graphics g, JComponent c) { + Tile tile = (Tile) c; + TileModel model = tile.getModel(); + + long started = System.currentTimeMillis(); + // We don't want to paint inside the insets or borders. + Insets insets = c.getInsets(); + g.translate(insets.left, insets.top); + + Graphics2D g2 = (Graphics2D) g.create(); + drawTile(g2, c); + if (model.isOverlayImage()) { + overlayLocImage(c); + } + + g2.dispose(); + + g.drawImage(tileImage, 0, 0, null); + + g.translate(-insets.left, -insets.top); + + if (Logger.isTraceEnabled()) { + long now = System.currentTimeMillis(); + Logger.trace(tile.getId() + " Duration: " + (now - started) + " ms. Cp: " + tile.xyToString() + " O: " + model.getTileOrienation()); + } + } + +} diff --git a/src/main/java/jcs/ui/layout/tiles/ui/CrossUI.java b/src/main/java/jcs/ui/layout/tiles/ui/CrossUI.java new file mode 100644 index 00000000..a592b60d --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/ui/CrossUI.java @@ -0,0 +1,362 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles.ui; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.geom.Ellipse2D; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import jcs.entities.AccessoryBean; +import static jcs.entities.AccessoryBean.AccessoryValue.GREEN; +import static jcs.entities.AccessoryBean.AccessoryValue.RED; +import jcs.entities.TileBean; +import static jcs.entities.TileBean.Orientation.NORTH; +import static jcs.entities.TileBean.Orientation.SOUTH; +import static jcs.entities.TileBean.Orientation.WEST; +import jcs.ui.layout.tiles.Cross; +import jcs.ui.layout.tiles.Tile; +import jcs.ui.layout.tiles.TileModel; + +public class CrossUI extends TileUI { + + public CrossUI() { + super(); + //Default is east +// this.renderWidth = RENDER_GRID * 4; +// this.renderHeight = RENDER_GRID * 2; + } + + public static ComponentUI createUI(JComponent c) { + return new CrossUI(); + } + +// public void changeRenderSize(Tile tile) { +// //Reset offsets +// //this.offsetY = 0; +// //this.renderOffsetY = 0; +// //this.offsetX = 0; +// //this.renderOffsetX = 0; +// +// if (tile.isHorizontal()) { +// this.renderWidth = RENDER_GRID * 4; +// this.renderHeight = RENDER_GRID * 2; +// +// //this.offsetY = 0; +// //this.renderOffsetY = 0; +// } else { +// this.renderWidth = RENDER_GRID * 2; +// this.renderHeight = RENDER_GRID * 4; +// +// //this.offsetX = 0; +// //this.renderOffsetX = 0; +// } +// +// //Due to the asymetical shape (center is on the left) +// //the offset has to be changed with the rotation +//// } +// } + + protected void renderStraight(Graphics2D g2, Color color) { + int xx = 0; + int yy = 170; + int w = RENDER_WIDTH; + int h = 60; + + g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + g2.fillRect(xx, yy, w, h); + } + + protected void renderRouteStraight(Graphics2D g2, Color color) { + int xx = 0; + int yy = 190; + int w = RENDER_WIDTH; + int h = 20; + + g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + g2.fillRect(xx, yy, w, h); + } + + protected void renderStraight2(Graphics2D g2, Color color) { + int xx = RENDER_WIDTH; + int yy = 170; + int w = RENDER_WIDTH; + int h = 60; + + g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + g2.fillRect(xx, yy, w, h); + } + + protected void renderRouteStraight2(Graphics2D g2, Color color) { + int xx = RENDER_WIDTH; + int yy = 190; + int w = RENDER_WIDTH; + int h = 20; + + g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + g2.fillRect(xx, yy, w, h); + } + + protected void renderDiagonal(Graphics2D g2, Color color, JComponent c) { + Tile tile = (Tile) c; + TileBean.Direction direction = tile.getDirection(); + + int[] xPoints, yPoints; + if (TileBean.Direction.RIGHT.equals(direction)) { + xPoints = new int[]{400, 400, 167, 230}; + yPoints = new int[]{170, 230, 0, 0}; + } else { + xPoints = new int[]{400, 400, 170, 230}; + yPoints = new int[]{230, 170, 400, 400}; + } + + g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + g2.fillPolygon(xPoints, yPoints, xPoints.length); + } + + protected void renderRouteDiagonal(Graphics2D g2, Color color, JComponent c) { + Tile tile = (Tile) c; + TileBean.Direction direction = tile.getDirection(); + + int[] xPoints, yPoints; + if (TileBean.Direction.RIGHT.equals(direction)) { + xPoints = new int[]{420, 400, 190, 210}; + yPoints = new int[]{210, 210, 0, 0}; + } else { + xPoints = new int[]{400, 400, 190, 210}; + yPoints = new int[]{210, 190, 400, 400}; + } + + g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + g2.fillPolygon(xPoints, yPoints, xPoints.length); + } + + protected void renderDiagonal2(Graphics2D g2, Color color, JComponent c) { + Tile tile = (Tile) c; + TileBean.Direction direction = tile.getDirection(); + + int[] xPoints, yPoints; + if (TileBean.Direction.RIGHT.equals(direction)) { + xPoints = new int[]{400, 400, 570, 630}; + yPoints = new int[]{170, 230, 400, 400}; + } else { + xPoints = new int[]{400, 400, 570, 630}; + yPoints = new int[]{230, 170, 0, 0}; + } + + g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + g2.fillPolygon(xPoints, yPoints, xPoints.length); + } + + protected void renderRouteDiagonal2(Graphics2D g2, Color color, JComponent c) { + Tile tile = (Tile) c; + TileBean.Direction direction = tile.getDirection(); + + int[] xPoints, yPoints; + if (TileBean.Direction.RIGHT.equals(direction)) { + xPoints = new int[]{400, 380, 590, 610}; + yPoints = new int[]{190, 190, 400, 400}; + } else { + xPoints = new int[]{400, 380, 590, 610}; + yPoints = new int[]{210, 210, 0, 0}; + } + + g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + g2.setPaint(Color.cyan); + g2.fillPolygon(xPoints, yPoints, xPoints.length); + } + + @Override + public void renderTile(Graphics2D g2, JComponent c) { + Tile tile = (Tile) c; + AccessoryBean.AccessoryValue accessoryValue = tile.getAccessoryValue(); + //Color trackColor = tile.getTrackColor(); + + if (accessoryValue == null) { + accessoryValue = AccessoryBean.AccessoryValue.OFF; + } + + switch (accessoryValue) { + case RED -> { + renderStraight2(g2, Cross.LIGHT_RED); + renderDiagonal(g2, Cross.LIGHT_RED, c); + renderStraight(g2, Cross.DARK_RED); + renderDiagonal2(g2, Cross.DARK_RED, c); + } + case GREEN -> { + renderDiagonal(g2, Cross.VERY_LIGHT_GREEN, c); + renderDiagonal2(g2, Cross.VERY_LIGHT_GREEN, c); + renderStraight(g2, Cross.DARK_GREEN); + renderStraight2(g2, Cross.DARK_GREEN); + } + default -> { + renderStraight(g2, trackColor); + renderStraight2(g2, trackColor); + renderDiagonal(g2, trackColor, c); + renderDiagonal2(g2, trackColor, c); + } + } + } + + @Override + public void renderTileRoute(Graphics2D g2, JComponent c) { + Tile tile = (Tile) c; + TileModel model = tile.getModel(); + TileBean.Direction direction = tile.getDirection(); + TileBean.Orientation orientation = tile.getOrientation(); + + if (model.getIncomingSide() == null) { + model.setIncomingSide(model.getTileOrienation()); + } + TileBean.Orientation incomingSide = model.getIncomingSide(); + + AccessoryBean.AccessoryValue routeValue = tile.getRouteValue(); + if (routeValue == null) { + routeValue = AccessoryBean.AccessoryValue.OFF; + } + + //Color trackColor = tile.getTrackColor(); + //Color trackRouteColor = tile.getTrackRouteColor(); + if (tile.isHorizontal()) { + if (AccessoryBean.AccessoryValue.GREEN == routeValue && (TileBean.Orientation.NORTH == incomingSide || TileBean.Orientation.SOUTH == incomingSide)) { + renderRouteDiagonal(g2, trackRouteColor, c); + renderRouteDiagonal2(g2, trackRouteColor, c); + } else if (AccessoryBean.AccessoryValue.GREEN == routeValue && (TileBean.Orientation.EAST == incomingSide || TileBean.Orientation.WEST == incomingSide)) { + renderRouteStraight(g2, trackRouteColor); + renderRouteStraight2(g2, trackRouteColor); + } else if (AccessoryBean.AccessoryValue.RED == routeValue && TileBean.Orientation.EAST == orientation) { + if (TileBean.Direction.RIGHT == direction && (TileBean.Orientation.EAST == incomingSide || TileBean.Orientation.NORTH == incomingSide)) { + renderRouteStraight2(g2, trackRouteColor); + renderRouteDiagonal(g2, trackRouteColor, c); + } else if (TileBean.Direction.RIGHT == direction && (TileBean.Orientation.WEST == incomingSide || TileBean.Orientation.SOUTH == incomingSide)) { + renderRouteDiagonal2(g2, trackRouteColor, c); + renderRouteStraight(g2, trackRouteColor); + } else if (TileBean.Direction.LEFT == direction && (TileBean.Orientation.EAST == incomingSide || TileBean.Orientation.SOUTH == incomingSide)) { + renderRouteStraight2(g2, trackRouteColor); + renderRouteDiagonal(g2, trackRouteColor, c); + } else if (TileBean.Direction.LEFT == direction && (TileBean.Orientation.WEST == incomingSide || TileBean.Orientation.NORTH == incomingSide)) { + renderRouteStraight(g2, trackColor); + renderRouteDiagonal2(g2, trackColor, c); + } + } else if (AccessoryBean.AccessoryValue.RED == routeValue && TileBean.Orientation.WEST == orientation) { + if (TileBean.Direction.RIGHT == direction && (TileBean.Orientation.EAST == incomingSide || TileBean.Orientation.NORTH == incomingSide)) { + renderRouteStraight(g2, trackRouteColor); + renderRouteDiagonal2(g2, trackRouteColor, c); + } else if (TileBean.Direction.RIGHT == direction && (TileBean.Orientation.WEST == incomingSide || TileBean.Orientation.SOUTH == incomingSide)) { + renderRouteDiagonal(g2, trackRouteColor, c); + renderRouteStraight2(g2, trackRouteColor); + } else if (TileBean.Direction.LEFT == direction && (TileBean.Orientation.EAST == incomingSide || TileBean.Orientation.SOUTH == incomingSide)) { + renderRouteStraight(g2, trackRouteColor); + renderRouteDiagonal2(g2, trackRouteColor, c); + } else if (TileBean.Direction.LEFT == direction && (TileBean.Orientation.WEST == incomingSide || TileBean.Orientation.NORTH == incomingSide)) { + renderRouteStraight2(g2, trackColor); + renderRouteDiagonal(g2, trackColor, c); + } + } + } else { + if (AccessoryBean.AccessoryValue.GREEN == routeValue && (TileBean.Orientation.NORTH == incomingSide || TileBean.Orientation.SOUTH == incomingSide)) { + renderRouteStraight(g2, trackRouteColor); + renderRouteStraight2(g2, trackRouteColor); + } else if (AccessoryBean.AccessoryValue.GREEN == routeValue && (TileBean.Orientation.EAST == incomingSide || TileBean.Orientation.WEST == incomingSide)) { + renderRouteDiagonal(g2, trackRouteColor, c); + renderRouteDiagonal2(g2, trackRouteColor, c); + } else if (AccessoryBean.AccessoryValue.RED == routeValue && TileBean.Orientation.SOUTH == orientation) { + if (TileBean.Direction.RIGHT == direction && (TileBean.Orientation.EAST == incomingSide || TileBean.Orientation.SOUTH == incomingSide)) { + renderRouteStraight2(g2, trackRouteColor); + renderRouteDiagonal(g2, trackRouteColor, c); + } else if (TileBean.Direction.RIGHT == direction && (TileBean.Orientation.WEST == incomingSide || TileBean.Orientation.NORTH == incomingSide)) { + renderRouteDiagonal2(g2, trackRouteColor, c); + renderRouteStraight(g2, trackRouteColor); + } else if (TileBean.Direction.LEFT == direction && (TileBean.Orientation.EAST == incomingSide || TileBean.Orientation.NORTH == incomingSide)) { + renderRouteStraight(g2, trackRouteColor); + renderRouteDiagonal2(g2, trackRouteColor, c); + } else if (TileBean.Direction.LEFT == direction && (TileBean.Orientation.WEST == incomingSide || TileBean.Orientation.SOUTH == incomingSide)) { + renderRouteStraight2(g2, trackColor); + renderRouteDiagonal(g2, trackColor, c); + } + } else if (AccessoryBean.AccessoryValue.RED == routeValue && TileBean.Orientation.NORTH == orientation) { + if (TileBean.Direction.RIGHT == direction && (TileBean.Orientation.EAST == incomingSide || TileBean.Orientation.SOUTH == incomingSide)) { + renderRouteStraight(g2, trackRouteColor); + renderRouteDiagonal2(g2, trackRouteColor, c); + } else if (TileBean.Direction.RIGHT == direction && (TileBean.Orientation.WEST == incomingSide || TileBean.Orientation.NORTH == incomingSide)) { + renderRouteDiagonal(g2, trackRouteColor, c); + renderRouteStraight2(g2, trackRouteColor); + } else if (TileBean.Direction.LEFT == direction && (TileBean.Orientation.EAST == incomingSide || TileBean.Orientation.NORTH == incomingSide)) { + renderRouteStraight2(g2, trackRouteColor); + renderRouteDiagonal(g2, trackRouteColor, c); + } else if (TileBean.Direction.LEFT == direction && (TileBean.Orientation.WEST == incomingSide || TileBean.Orientation.SOUTH == incomingSide)) { + renderRouteStraight(g2, trackColor); + renderRouteDiagonal2(g2, trackColor, c); + } + } + } + } + + @Override + protected void drawCenterPoint(Graphics2D g2d, Color color, double size, JComponent c) { + Tile tile = (Tile) c; + TileModel model = tile.getModel(); + TileBean.Orientation tileOrientation = model.getTileOrienation(); + //int renderWidth = tile.getRenderWidth(); + //int renderHeight = tile.getRenderHeight(); + + //A Cross has 1 alternate point + //1st square holds the centerpoint + //2nd square + double dX1, dX2, dY1, dY2; + switch (tileOrientation) { + case SOUTH -> { + dX1 = renderWidth / 2 - size / 2; + dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; + dX2 = renderWidth / 2 + renderWidth - size / 4; + dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; + } + case WEST -> { + dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; + dY1 = renderHeight / 2 - size / 2; + dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; + dY2 = renderHeight / 2 - size / 4; + } + case NORTH -> { + dX1 = renderWidth / 2 - size / 2; + dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; + dX2 = renderWidth / 2 + renderWidth - size / 4; + dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; + } + default -> { + //East + dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; + dY1 = renderHeight / 2 - size / 2; + dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; + dY2 = renderHeight / 2 - size / 4; + } + } + + g2d.setColor(color); + g2d.fill(new Ellipse2D.Double(dX1, dY1, size, size)); + g2d.fill(new Ellipse2D.Double(dX2, dY2, size / 2, size / 2)); + } + +} diff --git a/src/main/java/jcs/ui/layout/tiles/ui/CrossingUI.java b/src/main/java/jcs/ui/layout/tiles/ui/CrossingUI.java new file mode 100644 index 00000000..b7fe6b5b --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/ui/CrossingUI.java @@ -0,0 +1,94 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles.ui; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import jcs.ui.layout.tiles.Tile; + +public class CrossingUI extends StraightUI { + + public CrossingUI() { + } + + public static ComponentUI createUI(JComponent c) { + return new CrossingUI(); + } + + protected void renderVerticalAndDividers(Graphics2D g2, JComponent c) { + Tile tile = (Tile) c; + //Color trackColor = tile.getTrackColor(); + + int xxn = 175; + int yyn = 0; + int xxs = 175; + int yys = 325; + int w = 50; + int h = 75; + + g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); + g2.setPaint(trackColor); + + //North + g2.fillRect(xxn, yyn, w, h); + //South + g2.fillRect(xxs, yys, w, h); + + //Dividers + int[] xNorthPoly = new int[]{85, 115, 285, 315}; + int[] yNorthPoly = new int[]{85, 125, 125, 85}; + + int[] xSouthPoly = new int[]{85, 115, 285, 315}; + int[] ySouthPoly = new int[]{315, 275, 275, 315}; + + g2.setPaint(Color.darkGray); + g2.setStroke(new BasicStroke(8, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + + g2.drawPolyline(xNorthPoly, yNorthPoly, xNorthPoly.length); + g2.drawPolyline(xSouthPoly, ySouthPoly, xSouthPoly.length); + } + + protected void renderRouteVertical(Graphics2D g2, JComponent c) { + Tile tile = (Tile) c; + //Color trackRouteColor = tile.getTrackRouteColor(); + + int xxn, yyn, xxs, yys, w, h; + xxn = 190; + yyn = 0; + xxs = 190; + yys = 325; + w = 20; + h = 75; + + g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); + g2.setPaint(trackRouteColor); + + //North + g2.fillRect(xxn, yyn, w, h); + //South + g2.fillRect(xxs, yys, w, h); + } + + @Override + public void renderTile(Graphics2D g2, JComponent c) { + renderStraight(g2, c); + renderVerticalAndDividers(g2, c); + } + +} diff --git a/src/main/java/jcs/ui/layout/tiles/ui/CurvedUI.java b/src/main/java/jcs/ui/layout/tiles/ui/CurvedUI.java new file mode 100644 index 00000000..e9dad0c4 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/ui/CurvedUI.java @@ -0,0 +1,62 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles.ui; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import jcs.ui.layout.tiles.Tile; + +public class CurvedUI extends TileUI { + + public CurvedUI() { + } + + public static ComponentUI createUI(JComponent c) { + return new CurvedUI(); + } + + @Override + public void renderTile(Graphics2D g2, JComponent c) { + Tile tile = (Tile) c; + //Color trackColor = tile.getTrackColor(); + + int[] xPoints = new int[]{400, 400, 170, 230}; + int[] yPoints = new int[]{230, 170, 400, 400}; + + g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + g2.setPaint(trackColor); + + g2.fillPolygon(xPoints, yPoints, xPoints.length); + } + + @Override + public void renderTileRoute(Graphics2D g2, JComponent c) { + Tile tile = (Tile) c; + //Color trackRouteColor = tile.getTrackRouteColor(); + + int[] xPoints = new int[]{400, 400, 190, 210}; + int[] yPoints = new int[]{210, 190, 400, 400}; + + g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + g2.setPaint(trackRouteColor); + + g2.fillPolygon(xPoints, yPoints, xPoints.length); + } + +} diff --git a/src/main/java/jcs/ui/layout/tiles/ui/EndUI.java b/src/main/java/jcs/ui/layout/tiles/ui/EndUI.java new file mode 100644 index 00000000..e49ec7ae --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/ui/EndUI.java @@ -0,0 +1,66 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles.ui; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import jcs.ui.layout.tiles.Tile; + +public class EndUI extends TileUI { + + public EndUI() { + } + + public static ComponentUI createUI(JComponent c) { + return new EndUI(); + } + + protected void renderEnd(Graphics2D g2, JComponent c) { + Tile tile = (Tile) c; + //Color trackColor = tile.getTrackColor(); + + int xx = 0; + int yy = 175; + int w = RENDER_GRID; + int h = 50; + + g2.setStroke(new BasicStroke(40, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); + g2.setPaint(trackColor); + g2.fillRect(xx, yy, w, h); + + xx = RENDER_GRID; + yy = 100; + + w = 30; + h = 200; + + g2.setPaint(Color.DARK_GRAY); + g2.fillRect(xx, yy, w, h); + } + + @Override + public void renderTile(Graphics2D g2, JComponent c) { + renderEnd(g2, c); + } + + @Override + public void renderTileRoute(Graphics2D g2d, JComponent c) { + } + +} diff --git a/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java b/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java new file mode 100644 index 00000000..0e2ce14e --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java @@ -0,0 +1,69 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles.ui; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.MultipleGradientPaint; +import java.awt.Point; +import java.awt.RadialGradientPaint; +import java.awt.geom.Ellipse2D; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import jcs.ui.layout.tiles.Tile; +import jcs.ui.layout.tiles.TileModel; + +public class SensorUI extends StraightUI { + + public SensorUI() { + } + + public static ComponentUI createUI(JComponent c) { + return new SensorUI(); + } + + private void renderSensor(Graphics2D g2, JComponent c) { + Tile tile = (Tile) c; + TileModel model = tile.getModel(); + + int xx = RENDER_GRID - 75; + int yy = RENDER_GRID - 75; + + Point cp = new Point(xx, yy); + float radius = 300; + float[] dist = {0.0f, 0.6f}; + + if (model.isSensorActive()) { + Color[] colors = {Color.red.brighter(), Color.red.darker()}; + RadialGradientPaint foreground = new RadialGradientPaint(cp, radius, dist, colors, MultipleGradientPaint.CycleMethod.REFLECT); + g2.setPaint(foreground); + } else { + Color[] colors = {Color.green.darker(), Color.green.brighter()}; + RadialGradientPaint foreground = new RadialGradientPaint(cp, radius, dist, colors, MultipleGradientPaint.CycleMethod.REFLECT); + g2.setPaint(foreground); + } + + g2.fill(new Ellipse2D.Double(xx, yy, 0.5f * radius, 0.5f * radius)); + } + + + @Override + public void renderTile(Graphics2D g2, JComponent c) { + renderStraight(g2, c); + renderSensor(g2, c); + } + +} diff --git a/src/main/java/jcs/ui/layout/tiles/ui/SignalUI.java b/src/main/java/jcs/ui/layout/tiles/ui/SignalUI.java new file mode 100644 index 00000000..f53462b1 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/ui/SignalUI.java @@ -0,0 +1,325 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles.ui; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Polygon; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import jcs.entities.AccessoryBean; +import jcs.entities.AccessoryBean.SignalType; +import static jcs.entities.AccessoryBean.SignalType.HP012; +import static jcs.entities.AccessoryBean.SignalType.HP012SH1; +import static jcs.entities.AccessoryBean.SignalType.HP0SH1; +import jcs.entities.AccessoryBean.SignalValue; +import static jcs.entities.AccessoryBean.SignalValue.Hp0; +import static jcs.entities.AccessoryBean.SignalValue.Hp0Sh1; +import static jcs.entities.AccessoryBean.SignalValue.Hp1; +import static jcs.entities.AccessoryBean.SignalValue.Hp2; +import jcs.ui.layout.tiles.Tile; + +public class SignalUI extends StraightUI { + + public SignalUI() { + } + + public static ComponentUI createUI(JComponent c) { + return new SignalUI(); + } + + /** + * Render a Signal with 2 lights + * + * @param g2d the graphics context + * @param c + */ + protected void renderSignal2(Graphics2D g2d, JComponent c) { + Tile tile = (Tile) c; + SignalValue signalValue = tile.getSignalValue(); + + int rx = RENDER_GRID; + int ry = RENDER_GRID + 60; + int rw = 180; + int rh = 100; + int l1x = RENDER_GRID + 20; + int l1y = RENDER_GRID + 80; + int l2x = RENDER_GRID + 100; + int l2y = RENDER_GRID + 80; + + Color color1 = Color.gray; + Color color2 = Color.gray; + + if (signalValue == null) { + signalValue = AccessoryBean.SignalValue.OFF; + } + + switch (signalValue) { + case Hp0 -> { + color1 = Color.red; + color2 = Color.gray; + } + case Hp1 -> { + color1 = Color.gray; + color2 = Color.green; + } + default -> { + } + } + + g2d.setStroke(new BasicStroke(10f)); + g2d.setPaint(Color.darkGray); + g2d.fillRoundRect(rx, ry, rw, rh, 30, 30); + + g2d.setPaint(color1); + g2d.fillOval(l1x, l1y, 60, 60); + g2d.setPaint(color2); + g2d.fillOval(l2x, l2y, 60, 60); + } + + protected void renderSignal3(Graphics2D g2d, JComponent c) { + Tile tile = (Tile) c; + SignalValue signalValue = tile.getSignalValue(); + + int rx = RENDER_GRID; + int ry = RENDER_GRID + 60; + int rw = 180; + int rh = 100; + + int c1x = RENDER_GRID + 130; + int c1y = RENDER_GRID + 115; + + int c2x = RENDER_GRID + 10; + int c2y = RENDER_GRID + 115; + + int c3x = RENDER_GRID + 10; + int c3y = RENDER_GRID + 65; + + // Initialize all "lights" + Color color1 = Color.gray; + Color color2 = Color.gray; + Color color3 = Color.gray; + + if (signalValue == null) { + signalValue = AccessoryBean.SignalValue.OFF; + } + + switch (signalValue) { + case Hp0 -> { + color3 = Color.red; + } + case Hp1 -> + color1 = Color.green; + case Hp2 -> { + color1 = Color.green; + color2 = Color.yellow; + } + default -> { + } + } + + g2d.setStroke(new BasicStroke(10f)); + g2d.setPaint(Color.darkGray); + g2d.fillRoundRect(rx, ry, rw, rh, 30, 30); + + g2d.setPaint(color1); + g2d.fillOval(c1x, c1y, 40, 40); + + g2d.setPaint(color2); + g2d.fillOval(c2x, c2y, 40, 40); + + g2d.setPaint(color3); + g2d.fillOval(c3x, c3y, 40, 40); + } + + /** + * Render a entry Signal which can show 4 light images + * + * @param g2d the Graphics context + * @param c + */ + protected void renderSignal4(Graphics2D g2d, JComponent c) { + Tile tile = (Tile) c; + SignalValue signalValue = tile.getSignalValue(); + + int rx = RENDER_GRID - 50; + int ry = RENDER_GRID + 50; + int rw = 240; + int rh = 120; + int c1x = RENDER_GRID + 140; + int c1y = RENDER_GRID + 60; + + int c2x = RENDER_GRID + 90; + int c2y = RENDER_GRID + 60; + + int c3x = RENDER_GRID + 90; + int c3y = RENDER_GRID + 120; + + int c4x = RENDER_GRID + 60; + int c4y = RENDER_GRID + 130; + + int c5x = RENDER_GRID + 10; + int c5y = RENDER_GRID + 70; + + int c6x = RENDER_GRID - 40; + int c6y = RENDER_GRID + 60; + + // Initialize all "lights" + Color color1 = Color.gray; + Color color2 = Color.gray; + Color color3 = Color.gray; + Color color4 = Color.gray; + Color color5 = Color.gray; + Color color6 = Color.gray; + + if (signalValue == null) { + signalValue = AccessoryBean.SignalValue.OFF; + } + + switch (signalValue) { + case Hp0 -> { + color2 = Color.red; + color3 = Color.red; + } + case Hp1 -> + color1 = Color.green; + case Hp2 -> { + color1 = Color.green; + color6 = Color.yellow; + } + case Hp0Sh1 -> { + color2 = Color.red; + color4 = Color.white; + color5 = Color.white; + } + default -> { + } + } + + g2d.setStroke(new BasicStroke(10f)); + g2d.setPaint(Color.darkGray); + g2d.fillRoundRect(rx, ry, rw, rh, 30, 30); + + g2d.setPaint(color1); + g2d.fillOval(c1x, c1y, 40, 40); + g2d.setPaint(color2); + g2d.fillOval(c2x, c2y, 40, 40); + g2d.setPaint(color3); + g2d.fillOval(c3x, c3y, 40, 40); + g2d.setPaint(color4); + g2d.fillOval(c4x, c4y, 20, 20); + g2d.setPaint(color5); + g2d.fillOval(c5x, c5y, 20, 20); + g2d.setPaint(color6); + g2d.fillOval(c6x, c6y, 40, 40); + } + + /** + * Render a midget Signal + * + * @param g2d the Graphics context + * @param c + */ + protected void renderSignal2m(Graphics2D g2d, JComponent c) { + Tile tile = (Tile) c; + SignalValue signalValue = tile.getSignalValue(); + + int[] xps = new int[]{RENDER_GRID + 80, +RENDER_GRID + 150, +RENDER_GRID + 170, RENDER_GRID + 170, +RENDER_GRID + 150, RENDER_GRID + 80}; + + int[] yps = new int[]{RENDER_GRID + 60, RENDER_GRID + 60, RENDER_GRID + 80, +RENDER_GRID + 160, +RENDER_GRID + 180, RENDER_GRID + 180}; + + Polygon signalOutline = new Polygon(xps, yps, xps.length); + + int c1x = RENDER_GRID + 130; + int c1y = RENDER_GRID + 70; + + int c2x = RENDER_GRID + 130; + int c2y = RENDER_GRID + 140; + + int c3x = RENDER_GRID + 130; + int c3y = RENDER_GRID + 105; + + int c4x = RENDER_GRID + 85; + int c4y = RENDER_GRID + 70; + + Color color1 = Color.gray; + Color color2 = Color.gray; + Color color3 = Color.gray; + Color color4 = Color.gray; + + if (signalValue == null) { + signalValue = AccessoryBean.SignalValue.OFF; + } + + switch (signalValue) { + case Hp0 -> { + color1 = Color.red; + color2 = Color.red; + } + case Hp1 -> { + color3 = Color.white; + color4 = Color.white; + } + default -> { + } + } + + g2d.setStroke(new BasicStroke(10f)); + g2d.setPaint(Color.darkGray); + + g2d.fillPolygon(signalOutline); + + g2d.setPaint(color1); + g2d.fillOval(c1x, c1y, 30, 30); + + g2d.setPaint(color2); + g2d.fillOval(c2x, c2y, 30, 30); + + g2d.setPaint(color3); + g2d.fillOval(c3x, c3y, 30, 30); + + g2d.setPaint(color4); + g2d.fillOval(c4x, c4y, 30, 30); + } + + @Override + public void renderTile(Graphics2D g2, JComponent c) { + Tile tile = (Tile) c; + SignalType signalType = tile.getSignalType(); + + Graphics2D g2d = (Graphics2D) g2.create(); + renderStraight(g2d, c); + + if (signalType == null) { + signalType = AccessoryBean.SignalType.NONE; + } + + switch (signalType) { + case HP012 -> + renderSignal3(g2d, c); + case HP012SH1 -> + renderSignal4(g2d, c); + case HP0SH1 -> + renderSignal2m(g2d, c); + default -> + renderSignal2(g2d, c); + } + + g2d.dispose(); + } + +} diff --git a/src/main/java/jcs/ui/layout/tiles/ui/StraightDirectionUI.java b/src/main/java/jcs/ui/layout/tiles/ui/StraightDirectionUI.java new file mode 100644 index 00000000..858b5cce --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/ui/StraightDirectionUI.java @@ -0,0 +1,49 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles.ui; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; + +public class StraightDirectionUI extends StraightUI { + + public StraightDirectionUI() { + } + + public static ComponentUI createUI(JComponent c) { + return new StraightDirectionUI(); + } + + private void renderDirectionArrow(Graphics2D g2, JComponent c) { + // |\ + // ==|+=== + // |/ + g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); + g2.setPaint(Color.green.darker()); + + g2.fillPolygon(new int[]{150, 150, 270}, new int[]{130, 270, 200}, 3); + } + + @Override + public void renderTile(Graphics2D g2, JComponent c) { + renderStraight(g2, c); + renderDirectionArrow(g2, c); + } + +} diff --git a/src/main/java/jcs/ui/layout/tiles/ui/StraightUI.java b/src/main/java/jcs/ui/layout/tiles/ui/StraightUI.java new file mode 100644 index 00000000..31bb053f --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/ui/StraightUI.java @@ -0,0 +1,75 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles.ui; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import jcs.ui.layout.tiles.Tile; + +public class StraightUI extends TileUI { + + public StraightUI() { + } + + public static ComponentUI createUI(JComponent c) { + return new StraightUI(); + } + + protected void renderStraight(Graphics2D g2, JComponent c) { + Tile tile = (Tile) c; + //Color trackColor = tile.getTrackColor(); + + int xx = 0; + int yy = 170; + int w = RENDER_WIDTH; + int h = 60; + + g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); + g2.setPaint(trackColor); + + g2.fillRect(xx, yy, w, h); + } + + protected void renderRouteStraight(Graphics2D g2, JComponent c) { + Tile tile = (Tile) c; + + int xx, yy, w, h; + xx = 0; + yy = 190; + w = RENDER_WIDTH; + h = 20; + + //Color trackRouteColor = tile.getTrackRouteColor(); + g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); + g2.setPaint(trackRouteColor); + + g2.fillRect(xx, yy, w, h); + } + + @Override + public void renderTileRoute(Graphics2D g2, JComponent c) { + renderRouteStraight(g2, c); + } + + @Override + public void renderTile(Graphics2D g2, JComponent c) { + renderStraight(g2, c); + } + +} diff --git a/src/main/java/jcs/ui/layout/tiles/ui/SwitchUI.java b/src/main/java/jcs/ui/layout/tiles/ui/SwitchUI.java new file mode 100644 index 00000000..6b4ae851 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/ui/SwitchUI.java @@ -0,0 +1,146 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles.ui; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import jcs.entities.AccessoryBean; +import jcs.entities.AccessoryBean.AccessoryValue; +import static jcs.entities.AccessoryBean.AccessoryValue.GREEN; +import static jcs.entities.AccessoryBean.AccessoryValue.RED; +import jcs.entities.TileBean; +import jcs.ui.layout.tiles.Tile; + +public class SwitchUI extends TileUI { + + public SwitchUI() { + } + + public static ComponentUI createUI(JComponent c) { + return new SwitchUI(); + } + + protected void renderStraight(Graphics2D g2, Color color, JComponent c) { + int xx = 0; + int yy = 170; + int w = RENDER_WIDTH; + int h = 60; + + g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + + g2.fillRect(xx, yy, w, h); + } + + protected void renderDiagonal(Graphics2D g2, Color color, JComponent c) { + Tile tile = (Tile) c; + TileBean.Direction direction = tile.getDirection(); + + int[] xPoints, yPoints; + if (TileBean.Direction.RIGHT.equals(direction)) { + xPoints = new int[]{400, 400, 170, 230}; + yPoints = new int[]{170, 230, 0, 0}; + } else { + xPoints = new int[]{400, 400, 170, 230}; + yPoints = new int[]{230, 170, 400, 400}; + } + + g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + g2.fillPolygon(xPoints, yPoints, xPoints.length); + } + + protected void renderRouteStraight(Graphics2D g2, Color color, JComponent c) { + int xx = 0; + int yy = 190; + int w = RENDER_WIDTH; + int h = 20; + + g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + + g2.fillRect(xx, yy, w, h); + } + + protected void renderRouteDiagonal(Graphics2D g2, Color color, JComponent c) { + Tile tile = (Tile) c; + TileBean.Direction direction = tile.getDirection(); + + int[] xPoints, yPoints; + if (TileBean.Direction.RIGHT.equals(direction)) { + xPoints = new int[]{400, 400, 190, 210}; + yPoints = new int[]{190, 210, 0, 0}; + } else { + xPoints = new int[]{400, 400, 190, 210}; + yPoints = new int[]{210, 190, 400, 400}; + } + + g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + + g2.fillPolygon(xPoints, yPoints, xPoints.length); + } + + @Override + public void renderTile(Graphics2D g2, JComponent c) { + Tile tile = (Tile) c; + AccessoryValue accessoryValue = tile.getAccessoryValue(); + //Color trackColor = tile.getTrackColor(); + + if (accessoryValue == null) { + accessoryValue = AccessoryBean.AccessoryValue.OFF; + } + + switch (accessoryValue) { + case RED -> { + renderStraight(g2, trackColor, c); + renderDiagonal(g2, Color.red, c); + } + case GREEN -> { + renderDiagonal(g2, trackColor, c); + renderStraight(g2, Color.green, c); + } + default -> { + renderStraight(g2, trackColor, c); + renderDiagonal(g2, trackColor, c); + } + } + } + + @Override + public void renderTileRoute(Graphics2D g2, JComponent c) { + Tile tile = (Tile) c; + AccessoryValue routeValue = tile.getRouteValue(); + //Color trackRouteColor = tile.getTrackRouteColor(); + + if (routeValue == null) { + routeValue = AccessoryBean.AccessoryValue.OFF; + } + switch (routeValue) { + case RED -> { + renderRouteDiagonal(g2, trackRouteColor, c); + } + case GREEN -> { + renderRouteStraight(g2, trackRouteColor, c); + } + default -> { + } + } + } +} diff --git a/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java b/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java new file mode 100644 index 00000000..3d2f7176 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java @@ -0,0 +1,272 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles.ui; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Insets; +import java.awt.geom.AffineTransform; +import java.awt.geom.Ellipse2D; +import java.awt.image.BufferedImage; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import jcs.entities.TileBean; +import static jcs.entities.TileBean.Orientation.NORTH; +import static jcs.entities.TileBean.Orientation.SOUTH; +import static jcs.entities.TileBean.Orientation.WEST; +import jcs.ui.layout.tiles.Tile; +import static jcs.ui.layout.tiles.Tile.DEFAULT_BACKGROUND_COLOR; +import static jcs.ui.layout.tiles.Tile.DEFAULT_TRACK_COLOR; +import static jcs.ui.layout.tiles.Tile.GRID; +import jcs.ui.layout.tiles.TileModel; +import org.imgscalr.Scalr; +import org.tinylog.Logger; + +/** + * + * @author fransjacobs + */ +public abstract class TileUI extends ComponentUI { + + protected static final int RENDER_GRID = GRID * 10; + protected static final int RENDER_WIDTH = RENDER_GRID * 2; + protected static final int RENDER_HEIGHT = RENDER_GRID * 2; + + public static final String UI_CLASS_ID = "jcs.ui.layout.tiles.ui.TileUI"; + + protected int renderWidth; + protected int renderHeight; + + protected Color backgroundColor; + protected Color trackColor; + protected Color trackRouteColor; + + protected BufferedImage tileImage; + + protected TileUI() { + this.backgroundColor = DEFAULT_BACKGROUND_COLOR; + this.trackColor = DEFAULT_TRACK_COLOR; + } + + private void setRenderSize(JComponent c) { + Tile tile = (Tile) c; + + switch (tile.getTileType()) { + case CROSS -> { + if (tile.isHorizontal()) { + this.renderWidth = RENDER_GRID * 4; + this.renderHeight = RENDER_GRID * 2; + } else { + this.renderWidth = RENDER_GRID * 2; + this.renderHeight = RENDER_GRID * 4; + } + } + case BLOCK -> { + if (tile.isHorizontal()) { + this.renderWidth = RENDER_WIDTH * 3; + this.renderHeight = RENDER_HEIGHT; + } else { + this.renderWidth = RENDER_WIDTH; + this.renderHeight = RENDER_HEIGHT * 3; + } + } + default -> { + this.renderWidth = RENDER_WIDTH; + this.renderHeight = RENDER_HEIGHT; + } + } + } + + abstract void renderTile(Graphics2D g2d, JComponent c); + + abstract void renderTileRoute(Graphics2D g2d, JComponent c); + + public int getRenderWidth() { + return renderWidth; + } + + public void setRenderWidth(int renderWidth) { + this.renderWidth = renderWidth; + } + + public int getRenderHeight() { + return renderHeight; + } + + public void setRenderHeight(int renderHeight) { + this.renderHeight = renderHeight; + } + + public Color getBackgroundColor() { + return backgroundColor; + } + + public void setBackgroundColor(Color backgroundColor) { + this.backgroundColor = backgroundColor; + } + + public Color getTrackColor() { + return trackColor; + } + + public void setTrackColor(Color trackColor) { + this.trackColor = trackColor; + } + + public Color getTrackRouteColor() { + return trackRouteColor; + } + + public void setTrackRouteColor(Color trackRouteColor) { + this.trackRouteColor = trackRouteColor; + } + + protected BufferedImage createImage() { + return new BufferedImage(renderWidth, renderHeight, BufferedImage.TYPE_INT_RGB); + } + + public BufferedImage getTileImage() { + return tileImage; + } + + public void drawTile(Graphics2D g2d, JComponent c) { + // by default and image is rendered in the EAST orientation + setRenderSize(c); + + Tile tile = (Tile) c; + TileModel model = ((Tile) c).getModel(); + TileBean.Orientation tileOrientation = model.getTileOrienation(); + + //BufferedImage bf = new BufferedImage(tile.getRenderWidth(), tile.getRenderHeight(), BufferedImage.TYPE_INT_RGB); + BufferedImage bf = createImage(); + Graphics2D g2di = bf.createGraphics(); + + //Avoid errors + if (model.isShowRoute() && model.getIncomingSide() == null) { + model.setIncomingSide(tileOrientation); + } + + if (model.isSelected()) { + g2di.setBackground(model.getSelectedColor()); + } else { + g2di.setBackground(backgroundColor); + } + + g2di.clearRect(0, 0, renderWidth, renderHeight); + int ox = 0, oy = 0; + + AffineTransform trans = new AffineTransform(); + switch (tileOrientation) { + case SOUTH -> { + trans.rotate(Math.PI / 2, renderWidth / 2, renderHeight / 2); + ox = (renderHeight - renderWidth) / 2; + oy = (renderWidth - renderHeight) / 2; + trans.translate(-ox, -oy); + } + case WEST -> { + trans.rotate(Math.PI, renderWidth / 2, renderHeight / 2); + trans.translate(ox, oy); + } + case NORTH -> { + trans.rotate(-Math.PI / 2, renderWidth / 2, renderHeight / 2); + ox = (renderHeight - renderWidth) / 2; + oy = (renderWidth - renderHeight) / 2; + trans.translate(-ox, -oy); + } + default -> { + trans.rotate(0.0, renderWidth / 2, renderHeight / 2); + trans.translate(ox, oy); + } + } + + g2di.setTransform(trans); + + renderTile(g2di, c); + + if (model.isShowRoute()) { + renderTileRoute(g2di, c); + } + + if (model.isShowCenter()) { + drawCenterPoint(g2di, c); + } + + // Scale the image back... + if (model.isScaleImage()) { + tileImage = Scalr.resize(bf, Scalr.Method.AUTOMATIC, Scalr.Mode.FIT_EXACT, tile.getWidth(), tile.getHeight(), Scalr.OP_ANTIALIAS); + } else { + tileImage = bf; + } + g2di.dispose(); + } + + /** + * Render a tile image Always starts at (0,0) used the default width and height + * + * @param g2 the Graphic context + * @param c + */ + protected void drawName(Graphics2D g2, JComponent c) { + } + + protected void drawCenterPoint(Graphics2D g2d, JComponent c) { + drawCenterPoint(g2d, Color.magenta, c); + } + + protected void drawCenterPoint(Graphics2D g2, Color color, JComponent c) { + drawCenterPoint(g2, color, 60, c); + } + + protected void drawCenterPoint(Graphics2D g2d, Color color, double size, JComponent c) { + double dX = (renderWidth / 2 - size / 2); + double dY = (renderHeight / 2 - size / 2); + + g2d.setColor(color); + g2d.fill(new Ellipse2D.Double(dX, dY, size, size)); + } + + protected static void drawRotate(Graphics2D g2d, double x, double y, int angle, String text) { + g2d.translate((float) x, (float) y); + g2d.rotate(Math.toRadians(angle)); + g2d.drawString(text, 0, 0); + g2d.rotate(-Math.toRadians(angle)); + g2d.translate(-x, -y); + } + + @Override + public void paint(Graphics g, JComponent c) { + long started = System.currentTimeMillis(); + // We don't want to paint inside the insets or borders. + Insets insets = c.getInsets(); + g.translate(insets.left, insets.top); + + Graphics2D g2 = (Graphics2D) g.create(); + + drawTile(g2, c); + g2.dispose(); + + g.drawImage(tileImage, 0, 0, null); + g.translate(-insets.left, -insets.top); + + if (Logger.isTraceEnabled()) { + Tile tile = (Tile) c; + TileModel model = tile.getModel(); + long now = System.currentTimeMillis(); + Logger.trace(tile.getId() + " Duration: " + (now - started) + " ms. Cp: " + tile.xyToString() + " O: " + model.getTileOrienation()); + } + } +} diff --git a/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.form b/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.form index 345a66d6..9b77fbc1 100644 --- a/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.form +++ b/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.form @@ -1 +1,454 @@ -

\ No newline at end of file + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java b/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java index 8d11d4ec..3aa327eb 100644 --- a/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java +++ b/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java @@ -1 +1 @@ -/* * Copyright 2024 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.Color; import java.awt.Point; import javax.swing.ComboBoxModel; import javax.swing.DefaultComboBoxModel; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.AccessoryValue; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; import jcs.ui.layout.LayoutUtil; import jcs.ui.layout.events.TileEvent; import org.tinylog.Logger; public class TileTesterFrame extends javax.swing.JFrame { private Tile tile; public TileTesterFrame() { initComponents(); this.tileCB.setModel(createTileTypeComboBoxModel()); this.orientationCB.setModel(createOrientationComboBoxModel()); this.incomingSideCB.setModel(createOrientationComboBoxModel()); this.directionCB.setModel(createDirectionComboBoxModel(true)); createTile(); pack(); setVisible(true); } private ComboBoxModel createTileTypeComboBoxModel() { DefaultComboBoxModel tileTypeModel = new DefaultComboBoxModel(); tileTypeModel.addElement(TileBean.TileType.STRAIGHT); tileTypeModel.addElement(TileBean.TileType.STRAIGHT_DIR); tileTypeModel.addElement(TileBean.TileType.SENSOR); tileTypeModel.addElement(TileBean.TileType.SIGNAL); tileTypeModel.addElement(TileBean.TileType.END); tileTypeModel.addElement(TileBean.TileType.CROSSING); tileTypeModel.addElement(TileBean.TileType.CURVED); tileTypeModel.addElement(TileBean.TileType.SWITCH); tileTypeModel.addElement(TileBean.TileType.CROSS); return tileTypeModel; } private ComboBoxModel createOrientationComboBoxModel() { DefaultComboBoxModel orientationModel = new DefaultComboBoxModel(); orientationModel.addElement(Orientation.EAST); orientationModel.addElement(Orientation.SOUTH); orientationModel.addElement(Orientation.WEST); orientationModel.addElement(Orientation.NORTH); return orientationModel; } private ComboBoxModel createDirectionComboBoxModel(boolean dontCare) { DefaultComboBoxModel directionModel = new DefaultComboBoxModel(); if (dontCare) { directionModel.addElement(Direction.CENTER); } else { directionModel.addElement(Direction.LEFT); directionModel.addElement(Direction.RIGHT); } return directionModel; } private void createTile() { if (tile != null) { Logger.trace("Removing tile " + tile.getId()); canvas.remove(tile); tile = null; } TileType tileType = (TileType) tileCB.getSelectedItem(); Orientation orientation = (Orientation) orientationCB.getSelectedItem(); if (TileType.SWITCH == tileType || TileType.CROSS == tileType) { directionCB.setModel(createDirectionComboBoxModel(false)); } else { directionCB.setModel(createDirectionComboBoxModel(true)); } Direction direction = (Direction) this.directionCB.getSelectedItem(); boolean scale = !scaleCB.isSelected(); boolean showCenter = showCenterCB.isSelected(); int w = canvas.getWidth(); int h = canvas.getHeight(); int x = w / 2; int y = h / 2; Point tileCenter = new Point(x, y); tileCenter = LayoutUtil.snapToGrid(tileCenter); // if (TileType.CROSS == tileType) { // switch (orientation) { // case SOUTH -> { // x = w / 2 + 200; // y = h / 2 - 150; // } // case WEST -> { // x = w / 2 + 400; // y = h / 2 + 50; // } // case NORTH -> { // x = w / 2 + 200; // y = h / 2 + 250; // } // default -> { // x = w / 2; // y = h / 2 + 50; // } // } // } else { // x = w / 2 - 200; // y = h / 2 - 200; // } // Point center; // if (TileType.CROSS.equals(tileType)) { // center = new Point(x - 200, y); // } else { // center = new Point(x, y); // } Tile newTile = TileFactory.createTile(tileType, orientation, direction, tileCenter); newTile.setScaleImage(scale); newTile.setDrawCenterPoint(showCenter); //tile.setPropertyChangeListener(this); Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); newTile.setIncomingSide(incomingSide); newTile.setShowRoute(displayRouteCB.isSelected()); newTile.setTrackRouteColor(Color.blue); Logger.trace("Adding tile " + newTile.getId() + " " + newTile.xyToString()); //this.cPanel.add((JComponent) newTile); this.canvas.add(newTile); this.tile = newTile; } private AccessoryValue getAccessoryState() { AccessoryValue value; if (greenRB.isSelected()) { value = AccessoryValue.GREEN; } else if (redRB.isSelected()) { value = AccessoryValue.RED; } else { value = AccessoryValue.OFF; } return value; } private void changeAccesoryState() { if(tile instanceof Sensor) { tile.setActive(this.redRB.isSelected()); } if (tile instanceof Switch aSwitch) { if (this.displayRouteCB.isSelected()) { aSwitch.setRouteValue(getAccessoryState()); } else { aSwitch.setAccessoryValue(getAccessoryState()); } } if (tile instanceof Signal aSignal) { if (this.greenRB.isSelected()) { aSignal.setSignalValue(AccessoryBean.SignalValue.Hp1); } else if (this.redRB.isSelected()) { aSignal.setSignalValue(AccessoryBean.SignalValue.Hp0); } else { aSignal.setSignalValue(AccessoryBean.SignalValue.OFF); } } //this.tile.repaint(); } // @Override // public void propertyChange(PropertyChangeEvent evt) { // if ("repaintTile".equals(evt.getPropertyName())) { // Tile t = (Tile) evt.getNewValue(); // Logger.trace("Tile: " + t); // //this.repaint(); // } // } // @Override // public void paint(Graphics g) { // super.paint(g); // Graphics2D g2d = (Graphics2D) g; // boolean outline = this.drawOutlineCB.isSelected(); // boolean showRoute = this.displayRouteCB.isSelected(); // tile.setShowRoute(showRoute); // // tile.drawTile(g2d, outline); // // if (outline) { // tile.drawBounds(g2d); // tile.drawCenterPoint(g2d, Color.red); // } // } // @Override // public void paint(Graphics g) { // long started = System.currentTimeMillis(); // super.paint(g); // // long now = System.currentTimeMillis(); // Logger.trace("Duration: " + (now - started) + " ms."); // } private void changeDirection() { Direction direction = (Direction) this.directionCB.getSelectedItem(); this.tile.setDirection(direction); //if (TileType.CROSS == tile.getTileType()) { // ((Cross) tile).setWidthHeightAndOffsets(); //} //this.repaint(); } private void rotateTile() { Orientation newOrientation = tile.rotate(); orientationCB.setSelectedItem(newOrientation); // if (TileType.CROSS == tile.getTileType()) { // int x = tile.getCenterX(); // int y = tile.getCenterY(); // int w = tile.getWidth() * 10; // int h = tile.getHeight() * 10; // // //calculate a new centerpoint for cross // switch (tile.getOrientation()) { // case SOUTH -> { // x = x + w / 2; // y = y - h / 4; // } // case WEST -> { // x = x + w / 4; // y = y + h / 2; // } // case NORTH -> { // x = x - w / 2; // y = y + h / 4; // } // default -> { // x = x - w / 4; // y = y - h / 2; // } // } // tile.setCenter(new Point(x, y)); // } //this.canvas.repaint(this.tile.getTileBounds()); //tile.repaint(); } private void changeOrientation() { Orientation orientation = (Orientation) this.orientationCB.getSelectedItem(); tile.setOrientation(orientation); // if (TileType.CROSS == tile.getTileType()) { // //((Cross) tile).setWidthHeightAndOffsets(); // // int x = tile.getCenterX(); // int y = tile.getCenterY(); // int w = tile.getWidth() * 10; // int h = tile.getHeight() * 10; // // //calculate a new centerpoint for cross // switch (tile.getOrientation()) { // case SOUTH -> { // x = x + w / 2; // y = y - h / 4; // } // case WEST -> { // x = x + w / 4; // y = y + h / 2; // } // case NORTH -> { // x = x - w / 2; // y = y + h / 4; // } // default -> { // x = x - w / 4; // y = y - h / 2; // } // } // tile.setCenter(new Point(x, y)); // } //this.repaint(); } private void showRoute() { Logger.trace("Show route on tile " + tile.getId()); String tileId = tile.getId(); Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); //TileEvent tileEvent; if (tile.isJunction()) { AccessoryValue routeState = getAccessoryState(); //tileEvent = new TileEvent(tileId, true, incomingSide, routeState); } else { //tileEvent = new TileEvent(tileId, true, incomingSide); } //TileCache.fireTileEventListener(tileEvent); // ((JComponent) this.tile).repaint(); tile.setShowRoute(displayRouteCB.isSelected()); //repaint(); } // private void showOutline() { // //repaint(); // } private void changeIncomingSide() { Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); tile.setIncomingSide(incomingSide); //this.repaint(); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { accessoryBG = new javax.swing.ButtonGroup(); nPanel = new javax.swing.JPanel(); tileCB = new javax.swing.JComboBox<>(); orientationCB = new javax.swing.JComboBox<>(); inComingLbl = new javax.swing.JLabel(); incomingSideCB = new javax.swing.JComboBox<>(); directionCB = new javax.swing.JComboBox<>(); rotateButton = new javax.swing.JButton(); offRB = new javax.swing.JRadioButton(); greenRB = new javax.swing.JRadioButton(); redRB = new javax.swing.JRadioButton(); displayRouteCB = new javax.swing.JCheckBox(); scaleCB = new javax.swing.JCheckBox(); showCenterCB = new javax.swing.JCheckBox(); canvas = new jcs.ui.layout.tiles.DotGridCanvas(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); nPanel.setMinimumSize(new java.awt.Dimension(860, 36)); nPanel.setPreferredSize(new java.awt.Dimension(1020, 36)); java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); flowLayout1.setAlignOnBaseline(true); nPanel.setLayout(flowLayout1); tileCB.setPreferredSize(new java.awt.Dimension(150, 23)); tileCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { tileCBActionPerformed(evt); } }); nPanel.add(tileCB); orientationCB.setPreferredSize(new java.awt.Dimension(100, 23)); orientationCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { orientationCBActionPerformed(evt); } }); nPanel.add(orientationCB); inComingLbl.setText("Incoming Orientation"); nPanel.add(inComingLbl); incomingSideCB.setPreferredSize(new java.awt.Dimension(100, 23)); incomingSideCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { incomingSideCBActionPerformed(evt); } }); nPanel.add(incomingSideCB); directionCB.setPreferredSize(new java.awt.Dimension(100, 23)); directionCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { directionCBActionPerformed(evt); } }); nPanel.add(directionCB); rotateButton.setText("Rotate"); rotateButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { rotateButtonActionPerformed(evt); } }); nPanel.add(rotateButton); accessoryBG.add(offRB); offRB.setForeground(new java.awt.Color(153, 153, 153)); offRB.setSelected(true); offRB.setText("Off"); offRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { offRBActionPerformed(evt); } }); nPanel.add(offRB); accessoryBG.add(greenRB); greenRB.setForeground(new java.awt.Color(102, 255, 0)); greenRB.setText("Green"); greenRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { greenRBActionPerformed(evt); } }); nPanel.add(greenRB); accessoryBG.add(redRB); redRB.setForeground(new java.awt.Color(255, 0, 51)); redRB.setText("Red"); redRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { redRBActionPerformed(evt); } }); nPanel.add(redRB); displayRouteCB.setText("Route"); displayRouteCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { displayRouteCBActionPerformed(evt); } }); nPanel.add(displayRouteCB); scaleCB.setText("Scale"); scaleCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { scaleCBActionPerformed(evt); } }); nPanel.add(scaleCB); showCenterCB.setText("Center"); showCenterCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { showCenterCBActionPerformed(evt); } }); nPanel.add(showCenterCB); getContentPane().add(nPanel, java.awt.BorderLayout.NORTH); canvas.setPreferredSize(new java.awt.Dimension(600, 600)); getContentPane().add(canvas, java.awt.BorderLayout.CENTER); pack(); }// //GEN-END:initComponents private void rotateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rotateButtonActionPerformed rotateTile(); }//GEN-LAST:event_rotateButtonActionPerformed private void tileCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tileCBActionPerformed createTile(); }//GEN-LAST:event_tileCBActionPerformed private void orientationCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_orientationCBActionPerformed changeOrientation(); }//GEN-LAST:event_orientationCBActionPerformed private void directionCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_directionCBActionPerformed changeDirection(); }//GEN-LAST:event_directionCBActionPerformed private void offRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_offRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_offRBActionPerformed private void greenRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_greenRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_greenRBActionPerformed private void redRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_redRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_redRBActionPerformed private void displayRouteCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_displayRouteCBActionPerformed showRoute(); }//GEN-LAST:event_displayRouteCBActionPerformed private void scaleCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_scaleCBActionPerformed this.tile.setScaleImage(!this.scaleCB.isSelected()); this.tile.setBounds(this.tile.getTileBounds()); }//GEN-LAST:event_scaleCBActionPerformed private void incomingSideCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_incomingSideCBActionPerformed changeIncomingSide(); }//GEN-LAST:event_incomingSideCBActionPerformed private void showCenterCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showCenterCBActionPerformed this.tile.setDrawCenterPoint(this.showCenterCB.isSelected()); }//GEN-LAST:event_showCenterCBActionPerformed /** * @param args the command line arguments */ public static void main(String args[]) { try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { Logger.error(ex); } /* Create and display the form */ java.awt.EventQueue.invokeLater(() -> { TileTesterFrame app = new TileTesterFrame(); app.setTitle("Tile Tester"); app.setLocationRelativeTo(null); }); } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.ButtonGroup accessoryBG; private jcs.ui.layout.tiles.DotGridCanvas canvas; private javax.swing.JComboBox directionCB; private javax.swing.JCheckBox displayRouteCB; private javax.swing.JRadioButton greenRB; private javax.swing.JLabel inComingLbl; private javax.swing.JComboBox incomingSideCB; private javax.swing.JPanel nPanel; private javax.swing.JRadioButton offRB; private javax.swing.JComboBox orientationCB; private javax.swing.JRadioButton redRB; private javax.swing.JButton rotateButton; private javax.swing.JCheckBox scaleCB; private javax.swing.JCheckBox showCenterCB; private javax.swing.JComboBox tileCB; // End of variables declaration//GEN-END:variables } \ No newline at end of file +/* * Copyright 2024 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.Color; import java.awt.Point; import javax.swing.ComboBoxModel; import javax.swing.DefaultComboBoxModel; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.AccessoryValue; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import jcs.entities.TileBean.TileType; import jcs.ui.layout.LayoutUtil; import org.tinylog.Logger; public class TileTesterFrame extends javax.swing.JFrame { private Tile tile; public TileTesterFrame() { initComponents(); this.tileCB.setModel(createTileTypeComboBoxModel()); this.orientationCB.setModel(createOrientationComboBoxModel()); this.incomingSideCB.setModel(createOrientationComboBoxModel()); this.directionCB.setModel(createDirectionComboBoxModel(true)); createTile(); pack(); setVisible(true); } private ComboBoxModel createTileTypeComboBoxModel() { DefaultComboBoxModel tileTypeModel = new DefaultComboBoxModel(); tileTypeModel.addElement(TileBean.TileType.STRAIGHT); tileTypeModel.addElement(TileBean.TileType.STRAIGHT_DIR); tileTypeModel.addElement(TileBean.TileType.SENSOR); tileTypeModel.addElement(TileBean.TileType.SIGNAL); tileTypeModel.addElement(TileBean.TileType.END); tileTypeModel.addElement(TileBean.TileType.CROSSING); tileTypeModel.addElement(TileBean.TileType.CURVED); tileTypeModel.addElement(TileBean.TileType.SWITCH); tileTypeModel.addElement(TileBean.TileType.CROSS); return tileTypeModel; } private ComboBoxModel createOrientationComboBoxModel() { DefaultComboBoxModel orientationModel = new DefaultComboBoxModel(); orientationModel.addElement(Orientation.EAST); orientationModel.addElement(Orientation.SOUTH); orientationModel.addElement(Orientation.WEST); orientationModel.addElement(Orientation.NORTH); return orientationModel; } private ComboBoxModel createDirectionComboBoxModel(boolean dontCare) { DefaultComboBoxModel directionModel = new DefaultComboBoxModel(); if (dontCare) { directionModel.addElement(Direction.CENTER); } else { directionModel.addElement(Direction.LEFT); directionModel.addElement(Direction.RIGHT); } return directionModel; } private void createTile() { if (tile != null) { Logger.trace("Removing tile " + tile.getId()); canvas.remove(tile); tile = null; } TileType tileType = (TileType) tileCB.getSelectedItem(); Orientation orientation = (Orientation) orientationCB.getSelectedItem(); if (TileType.SWITCH == tileType || TileType.CROSS == tileType) { directionCB.setModel(createDirectionComboBoxModel(false)); } else { directionCB.setModel(createDirectionComboBoxModel(true)); } Direction direction = (Direction) this.directionCB.getSelectedItem(); boolean scale = !scaleCB.isSelected(); boolean showCenter = showCenterCB.isSelected(); int w = canvas.getWidth(); int h = canvas.getHeight(); int x = w / 2; int y = h / 2; Point tileCenter = new Point(x, y); tileCenter = LayoutUtil.snapToGrid(tileCenter); Tile newTile = TileFactory.createTile(tileType, orientation, direction, tileCenter); newTile.setScaleImage(scale); newTile.setDrawCenterPoint(showCenter); //tile.setPropertyChangeListener(this); Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); newTile.setIncomingSide(incomingSide); newTile.setShowRoute(displayRouteCB.isSelected()); newTile.setTrackRouteColor(Color.blue); Logger.trace("Adding tile " + newTile.getId() + " " + newTile.xyToString()); //this.cPanel.add((JComponent) newTile); this.canvas.add(newTile); this.tile = newTile; tile.updateUI(); } private AccessoryValue getAccessoryState() { AccessoryValue value; if (greenRB.isSelected()) { value = AccessoryValue.GREEN; } else if (redRB.isSelected()) { value = AccessoryValue.RED; } else { value = AccessoryValue.OFF; } return value; } private void changeAccesoryState() { if (tile instanceof Sensor) { tile.setActive(this.redRB.isSelected()); } if (tile instanceof Switch aSwitch) { if (this.displayRouteCB.isSelected()) { aSwitch.setRouteValue(getAccessoryState()); } else { aSwitch.setAccessoryValue(getAccessoryState()); } } if (tile instanceof Signal aSignal) { if (this.greenRB.isSelected()) { aSignal.setSignalValue(AccessoryBean.SignalValue.Hp1); } else if (this.redRB.isSelected()) { aSignal.setSignalValue(AccessoryBean.SignalValue.Hp0); } else { aSignal.setSignalValue(AccessoryBean.SignalValue.OFF); } } //this.tile.repaint(); } // @Override // public void propertyChange(PropertyChangeEvent evt) { // if ("repaintTile".equals(evt.getPropertyName())) { // Tile t = (Tile) evt.getNewValue(); // Logger.trace("Tile: " + t); // //this.repaint(); // } // } // @Override // public void paint(Graphics g) { // super.paint(g); // Graphics2D g2d = (Graphics2D) g; // boolean outline = this.drawOutlineCB.isSelected(); // boolean showRoute = this.displayRouteCB.isSelected(); // tile.setShowRoute(showRoute); // // tile.drawTile(g2d, outline); // // if (outline) { // tile.drawBounds(g2d); // tile.drawCenterPoint(g2d, Color.red); // } // } // @Override // public void paint(Graphics g) { // long started = System.currentTimeMillis(); // super.paint(g); // // long now = System.currentTimeMillis(); // Logger.trace("Duration: " + (now - started) + " ms."); // } private void changeDirection() { Direction direction = (Direction) this.directionCB.getSelectedItem(); this.tile.setDirection(direction); //if (TileType.CROSS == tile.getTileType()) { // ((Cross) tile).setWidthHeightAndOffsets(); //} //this.repaint(); } private void rotateTile() { Orientation newOrientation = tile.rotate(); orientationCB.setSelectedItem(newOrientation); // if (TileType.CROSS == tile.getTileType()) { // int x = tile.getCenterX(); // int y = tile.getCenterY(); // int w = tile.getWidth() * 10; // int h = tile.getHeight() * 10; // // //calculate a new centerpoint for cross // switch (tile.getOrientation()) { // case SOUTH -> { // x = x + w / 2; // y = y - h / 4; // } // case WEST -> { // x = x + w / 4; // y = y + h / 2; // } // case NORTH -> { // x = x - w / 2; // y = y + h / 4; // } // default -> { // x = x - w / 4; // y = y - h / 2; // } // } // tile.setCenter(new Point(x, y)); // } //this.canvas.repaint(this.tile.getTileBounds()); //tile.repaint(); } private void changeOrientation() { Orientation orientation = (Orientation) this.orientationCB.getSelectedItem(); tile.setOrientation(orientation); // if (TileType.CROSS == tile.getTileType()) { // //((Cross) tile).setWidthHeightAndOffsets(); // // int x = tile.getCenterX(); // int y = tile.getCenterY(); // int w = tile.getWidth() * 10; // int h = tile.getHeight() * 10; // // //calculate a new centerpoint for cross // switch (tile.getOrientation()) { // case SOUTH -> { // x = x + w / 2; // y = y - h / 4; // } // case WEST -> { // x = x + w / 4; // y = y + h / 2; // } // case NORTH -> { // x = x - w / 2; // y = y + h / 4; // } // default -> { // x = x - w / 4; // y = y - h / 2; // } // } // tile.setCenter(new Point(x, y)); // } //this.repaint(); } private void showRoute() { Logger.trace("Show route on tile " + tile.getId()); String tileId = tile.getId(); Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); //TileEvent tileEvent; if (tile.isJunction()) { AccessoryValue routeState = getAccessoryState(); //tileEvent = new TileEvent(tileId, true, incomingSide, routeState); } else { //tileEvent = new TileEvent(tileId, true, incomingSide); } //TileCache.fireTileEventListener(tileEvent); // ((JComponent) this.tile).repaint(); tile.setShowRoute(displayRouteCB.isSelected()); //repaint(); } // private void showOutline() { // //repaint(); // } private void changeIncomingSide() { Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); tile.setIncomingSide(incomingSide); //this.repaint(); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { accessoryBG = new javax.swing.ButtonGroup(); nPanel = new javax.swing.JPanel(); tileCB = new javax.swing.JComboBox<>(); orientationCB = new javax.swing.JComboBox<>(); inComingLbl = new javax.swing.JLabel(); incomingSideCB = new javax.swing.JComboBox<>(); directionCB = new javax.swing.JComboBox<>(); rotateButton = new javax.swing.JButton(); offRB = new javax.swing.JRadioButton(); greenRB = new javax.swing.JRadioButton(); redRB = new javax.swing.JRadioButton(); displayRouteCB = new javax.swing.JCheckBox(); scaleCB = new javax.swing.JCheckBox(); showCenterCB = new javax.swing.JCheckBox(); canvas = new jcs.ui.layout.tiles.DotGridCanvas(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); nPanel.setMinimumSize(new java.awt.Dimension(860, 36)); nPanel.setPreferredSize(new java.awt.Dimension(1020, 36)); java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); flowLayout1.setAlignOnBaseline(true); nPanel.setLayout(flowLayout1); tileCB.setPreferredSize(new java.awt.Dimension(150, 23)); tileCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { tileCBActionPerformed(evt); } }); nPanel.add(tileCB); orientationCB.setPreferredSize(new java.awt.Dimension(100, 23)); orientationCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { orientationCBActionPerformed(evt); } }); nPanel.add(orientationCB); inComingLbl.setText("Incoming Orientation"); nPanel.add(inComingLbl); incomingSideCB.setPreferredSize(new java.awt.Dimension(100, 23)); incomingSideCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { incomingSideCBActionPerformed(evt); } }); nPanel.add(incomingSideCB); directionCB.setPreferredSize(new java.awt.Dimension(100, 23)); directionCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { directionCBActionPerformed(evt); } }); nPanel.add(directionCB); rotateButton.setText("Rotate"); rotateButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { rotateButtonActionPerformed(evt); } }); nPanel.add(rotateButton); accessoryBG.add(offRB); offRB.setForeground(new java.awt.Color(153, 153, 153)); offRB.setSelected(true); offRB.setText("Off"); offRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { offRBActionPerformed(evt); } }); nPanel.add(offRB); accessoryBG.add(greenRB); greenRB.setForeground(new java.awt.Color(102, 255, 0)); greenRB.setText("Green"); greenRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { greenRBActionPerformed(evt); } }); nPanel.add(greenRB); accessoryBG.add(redRB); redRB.setForeground(new java.awt.Color(255, 0, 51)); redRB.setText("Red"); redRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { redRBActionPerformed(evt); } }); nPanel.add(redRB); displayRouteCB.setText("Route"); displayRouteCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { displayRouteCBActionPerformed(evt); } }); nPanel.add(displayRouteCB); scaleCB.setText("Scale"); scaleCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { scaleCBActionPerformed(evt); } }); nPanel.add(scaleCB); showCenterCB.setText("Center"); showCenterCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { showCenterCBActionPerformed(evt); } }); nPanel.add(showCenterCB); getContentPane().add(nPanel, java.awt.BorderLayout.NORTH); canvas.setPreferredSize(new java.awt.Dimension(600, 600)); getContentPane().add(canvas, java.awt.BorderLayout.CENTER); pack(); }// //GEN-END:initComponents private void rotateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rotateButtonActionPerformed rotateTile(); }//GEN-LAST:event_rotateButtonActionPerformed private void tileCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tileCBActionPerformed createTile(); }//GEN-LAST:event_tileCBActionPerformed private void orientationCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_orientationCBActionPerformed changeOrientation(); }//GEN-LAST:event_orientationCBActionPerformed private void directionCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_directionCBActionPerformed changeDirection(); }//GEN-LAST:event_directionCBActionPerformed private void offRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_offRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_offRBActionPerformed private void greenRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_greenRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_greenRBActionPerformed private void redRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_redRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_redRBActionPerformed private void displayRouteCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_displayRouteCBActionPerformed showRoute(); }//GEN-LAST:event_displayRouteCBActionPerformed private void scaleCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_scaleCBActionPerformed this.tile.setScaleImage(!this.scaleCB.isSelected()); this.tile.setBounds(this.tile.getTileBounds()); }//GEN-LAST:event_scaleCBActionPerformed private void incomingSideCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_incomingSideCBActionPerformed changeIncomingSide(); }//GEN-LAST:event_incomingSideCBActionPerformed private void showCenterCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showCenterCBActionPerformed this.tile.setDrawCenterPoint(this.showCenterCB.isSelected()); }//GEN-LAST:event_showCenterCBActionPerformed /** * @param args the command line arguments */ public static void main(String args[]) { try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { Logger.error(ex); } /* Create and display the form */ java.awt.EventQueue.invokeLater(() -> { TileTesterFrame app = new TileTesterFrame(); app.setTitle("Tile Tester"); app.setLocationRelativeTo(null); }); } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.ButtonGroup accessoryBG; private jcs.ui.layout.tiles.DotGridCanvas canvas; private javax.swing.JComboBox directionCB; private javax.swing.JCheckBox displayRouteCB; private javax.swing.JRadioButton greenRB; private javax.swing.JLabel inComingLbl; private javax.swing.JComboBox incomingSideCB; private javax.swing.JPanel nPanel; private javax.swing.JRadioButton offRB; private javax.swing.JComboBox orientationCB; private javax.swing.JRadioButton redRB; private javax.swing.JButton rotateButton; private javax.swing.JCheckBox scaleCB; private javax.swing.JCheckBox showCenterCB; private javax.swing.JComboBox tileCB; // End of variables declaration//GEN-END:variables } \ No newline at end of file From 80e933d0fe01cf18968c4028bd14dc5738848270 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Sat, 8 Feb 2025 17:07:05 +0100 Subject: [PATCH 15/70] Cleanup code, minor fix in Crossing --- src/main/java/jcs/ui/layout/tiles/Block.java | 426 +----------------- src/main/java/jcs/ui/layout/tiles/Cross.java | 300 +----------- .../java/jcs/ui/layout/tiles/Crossing.java | 3 + src/main/java/jcs/ui/layout/tiles/Curved.java | 3 + src/main/java/jcs/ui/layout/tiles/End.java | 3 + src/main/java/jcs/ui/layout/tiles/Sensor.java | 3 + src/main/java/jcs/ui/layout/tiles/Signal.java | 275 +---------- .../java/jcs/ui/layout/tiles/Straight.java | 3 + .../ui/layout/tiles/StraightDirection.java | 18 +- src/main/java/jcs/ui/layout/tiles/Switch.java | 93 +--- src/main/java/jcs/ui/layout/tiles/Tile.java | 242 ++-------- .../java/jcs/ui/layout/tiles/ui/CrossUI.java | 31 -- .../jcs/ui/layout/tiles/ui/CrossingUI.java | 35 +- .../java/jcs/ui/layout/tiles/ui/CurvedUI.java | 7 - .../java/jcs/ui/layout/tiles/ui/EndUI.java | 3 - .../jcs/ui/layout/tiles/ui/StraightUI.java | 8 - .../java/jcs/ui/layout/tiles/ui/SwitchUI.java | 3 - .../java/jcs/ui/layout/tiles/ui/TileUI.java | 5 +- 18 files changed, 90 insertions(+), 1371 deletions(-) diff --git a/src/main/java/jcs/ui/layout/tiles/Block.java b/src/main/java/jcs/ui/layout/tiles/Block.java index faa77ea3..8a6eb0a7 100755 --- a/src/main/java/jcs/ui/layout/tiles/Block.java +++ b/src/main/java/jcs/ui/layout/tiles/Block.java @@ -37,6 +37,9 @@ import jcs.ui.layout.tiles.ui.StraightUI; import jcs.ui.layout.tiles.ui.TileUI; +/** + * Representation of a Block on the layout + */ public class Block extends Tile { public static final int BLOCK_WIDTH = DEFAULT_WIDTH * 3; @@ -45,8 +48,6 @@ public class Block extends Tile { public Block(TileBean tileBean) { super(tileBean); setModel(new DefaultTileModel(tileBean.getOrientation())); - //changeRenderSize(); - populateModel(); initUI(); } @@ -62,7 +63,6 @@ public Block(Orientation orientation, int x, int y) { public Block(Orientation orientation, int x, int y, int width, int height) { super(TileType.BLOCK, orientation, x, y, width, height); setModel(new DefaultTileModel(orientation)); - //changeRenderSize(); initUI(); } @@ -82,16 +82,6 @@ public void updateUI() { invalidate(); } -// private void changeRenderSize() { -// Orientation tileOrientation = model.getTileOrienation(); -// if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { -// this.renderWidth = RENDER_WIDTH * 3; -// this.renderHeight = RENDER_HEIGHT; -// } else { -// this.renderWidth = RENDER_WIDTH; -// this.renderHeight = RENDER_HEIGHT * 3; -// } -// } @Override public Set getAltPoints() { int xx = this.tileX; @@ -331,43 +321,10 @@ public Orientation rotate() { Dimension d = new Dimension(w, h); setPreferredSize(d); setSize(d); - //changeRenderSize(); - setBounds(getTileBounds()); return model.getTileOrienation(); } - /** - * Depending on the block status change the background color
- * - Red: Occupied
- * - Green: Departure
- * - Magenta: Arrival / entering
- * - Yellow: reserved
- * - White: all clear / default
- * - * @return the Color which belong with the current Block State - */ -// Color getBlockStateColor() { -// return getBlockStateColor(this.model.getBlockState()); -// } -// protected Color getBlockStateColor(BlockState blockState) { -// return switch (blockState) { -// case GHOST -> -// new Color(250, 0, 0); -// case LOCKED -> -// new Color(250, 250, 210); -// case OCCUPIED -> -// new Color(250, 210, 210); -// case OUT_OF_ORDER -> -// new Color(190, 190, 190); -// case OUTBOUND -> -// new Color(210, 250, 210); -// case INBOUND -> -// new Color(250, 210, 250); -// default -> -// new Color(255, 255, 255); -// }; -// } public static String getDepartureSuffix(Orientation tileOrientation, boolean reverseArrival, LocomotiveBean.Direction direction) { if (LocomotiveBean.Direction.FORWARDS == direction) { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { @@ -400,338 +357,6 @@ public static String getDepartureSuffix(Orientation tileOrientation, boolean rev } } -// @Override -// public void renderTile(Graphics2D g2) { -// int xx = 20; -// int yy = 50; -// int rw = RENDER_WIDTH * 3 - 40; -// int rh = 300; -// -// g2.setStroke(new BasicStroke(3, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); -// -// g2.setPaint(Color.darkGray); -// g2.drawRoundRect(xx, yy, rw, rh, 15, 15); -// -// Color blockStateColor = getBlockStateColor(); -// //Logger.trace("Block " + this.id + " State: " + this.getBlockBean().getBlockState().getState() + " Color: " + blockStateColor.toString()); -// g2.setPaint(blockStateColor); -// g2.fillRoundRect(xx, yy, rw, rh, 15, 15); -// -// g2.setStroke(new BasicStroke(20, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); -// g2.setPaint(Color.darkGray); -// g2.drawLine(rw + GRID, yy - 0, rw + GRID, yy + 300); -// -// //When there is a locomotive in the block mark the direction of travel. -// //The default, forwards is in the direction of the block orientation, i.e. the + -// if (model.getLocomotive() != null && model.getLocomotive().getName() != null) { -// renderDirectionArrow(g2); -// } -// -// drawName(g2); -// } -// private void renderDirectionArrow(Graphics2D g2) { -// //The default, forwards is in the direction of the block orientation, i.e. the + -// Orientation tileOrientation = model.getTileOrienation(); -// BlockBean bb = this.getBlockBean(); -// boolean reverseArrival = model.isReverseArrival(); -// -// LocomotiveBean.Direction logicalDirection; -// if (bb.getLogicalDirection() != null) { -// logicalDirection = model.getLogicalDirection(); -// } else { -// logicalDirection = model.getLocomotive().getDirection(); -// } -// -// String departureSuffix = model.getDepartureSuffix(); -// if (departureSuffix == null) { -// departureSuffix = Block.getDepartureSuffix(tileOrientation, reverseArrival, logicalDirection); -// } -// -// //Logger.trace(this.getId()+" LogicalDirection is " + (bb.getLogicalDirection() != null ? "Set" : "Not Set") + " Dir: " + logicalDirection.getDirection() + " Orientation: " + orientation.getOrientation() + " departureSuffix: " + departureSuffix); -// if ("+".equals(departureSuffix)) { -// if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { -// switch (logicalDirection) { -// case LocomotiveBean.Direction.FORWARDS -> { -// if (reverseArrival) { -// renderLeftArrow(g2); -// } else { -// renderRightArrow(g2); -// } -// } -// case LocomotiveBean.Direction.BACKWARDS -> { -// if (reverseArrival) { -// renderRightArrow(g2); -// } else { -// renderLeftArrow(g2); -// } -// } -// } -// } else { -// switch (logicalDirection) { -// case LocomotiveBean.Direction.BACKWARDS -> { -// if (reverseArrival) { -// renderLeftArrow(g2); -// } else { -// renderRightArrow(g2); -// } -// } -// case LocomotiveBean.Direction.FORWARDS -> { -// if (reverseArrival) { -// renderRightArrow(g2); -// } else { -// renderLeftArrow(g2); -// } -// } -// } -// } -// } else { -// if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { -// switch (logicalDirection) { -// case LocomotiveBean.Direction.FORWARDS -> { -// if (reverseArrival) { -// renderLeftArrow(g2); -// } else { -// renderRightArrow(g2); -// } -// } -// case LocomotiveBean.Direction.BACKWARDS -> { -// if (reverseArrival) { -// renderRightArrow(g2); -// } else { -// renderLeftArrow(g2); -// } -// } -// } -// } else { -// switch (logicalDirection) { -// case LocomotiveBean.Direction.BACKWARDS -> { -// if (reverseArrival) { -// renderLeftArrow(g2); -// } else { -// renderRightArrow(g2); -// } -// } -// case LocomotiveBean.Direction.FORWARDS -> { -// if (reverseArrival) { -// renderRightArrow(g2); -// } else { -// renderLeftArrow(g2); -// } -// } -// } -// } -// } -// } -// private void renderLeftArrow(Graphics2D g2) { -// //Logger.trace(this.getId()+" LogicalDirection is " + this.getBlockBean().getLogicalDirection() + " Orientation: " + this.getOrientation() + " departureSuffix: " + this.getBlockBean().getDepartureSuffix()); -// g2.fillPolygon(new int[]{0, 50, 50,}, new int[]{200, 150, 250}, 3); -// } -// private void renderRightArrow(Graphics2D g2) { -// //Logger.trace(this.getId()+" LogicalDirection is " + this.getBlockBean().getLogicalDirection() + " Orientation: " + this.getOrientation() + " departureSuffix: " + this.getBlockBean().getDepartureSuffix()); -// g2.fillPolygon(new int[]{1180, 1130, 1130,}, new int[]{200, 150, 250}, 3); -// } -// @Override -// public void renderTileRoute(Graphics2D g2d) { -// if (model.isShowBlockState()) { -// backgroundColor = getBlockStateColor(model.getBlockState()); -// } -// } -// protected void overlayLocImage() { -// int ww = tileImage.getWidth(); -// int hh = tileImage.getHeight(); -// Orientation tileOrientation = model.getTileOrienation(); -// -// BufferedImage overlay = new BufferedImage(ww, hh, BufferedImage.TYPE_INT_ARGB); -// Graphics2D g2i = overlay.createGraphics(); -// -// Image locImage = getLocImage(); -// if (locImage != null) { -// String departureSuffix = model.getDepartureSuffix(); -// boolean reverseImage = model.isReverseArrival(); -// -// Logger.trace("LocImage w: " + locImage.getWidth(null) + " h: " + locImage.getHeight(null)); -// // scale it to max h of 45 -// int size = 45; -// float aspect = (float) locImage.getHeight(null) / (float) locImage.getWidth(null); -// //TODO: Use Scalr? -// locImage = locImage.getScaledInstance(size, (int) (size * aspect), Image.SCALE_SMOOTH); -// -// //Depending on the block orientation the image needs to be rotated and flipped -// //Incase the departure suffix is NOT set center the locomotive image -// int w, h, xx, yy; -// switch (tileOrientation) { -// case WEST -> { -// w = locImage.getWidth(null); -// h = locImage.getHeight(null); -// -// if (null == departureSuffix) { -// xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w; -// } else { -// switch (departureSuffix) { -// case "+" -> { -// xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w - 25; -// } -// default -> { -// xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w + 10; -// } -// } -// } -// yy = DEFAULT_HEIGHT / 2 - h / 2; -// -// if (reverseImage) { -// locImage = ImageUtil.flipVertically(locImage); -// } -// } -// case SOUTH -> { -// locImage = ImageUtil.flipHorizontally(locImage); -// locImage = ImageUtil.rotate(locImage, 90); -// -// w = locImage.getWidth(null); -// h = locImage.getHeight(null); -// xx = DEFAULT_WIDTH / 2 - w / 2; -// -// if (null == departureSuffix) { -// yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h; -// } else { -// switch (departureSuffix) { -// case "-" -> { -// yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h - 25; -// } -// default -> { -// yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h + 10; -// } -// } -// } -// if (reverseImage) { -// locImage = ImageUtil.flipHorizontally(locImage); -// } -// } -// case NORTH -> { -// locImage = ImageUtil.flipHorizontally(locImage); -// locImage = ImageUtil.rotate(locImage, 90); -// -// w = locImage.getWidth(null); -// h = locImage.getHeight(null); -// xx = DEFAULT_WIDTH / 2 - w / 2; -// -// if (null == departureSuffix) { -// int minY = BLOCK_HEIGHT / 2 - getHeight() / 2 + h; -// yy = minY; -// } else { -// switch (departureSuffix) { -// case "+" -> { -// yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h - 25; -// } -// default -> { -// yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h + 10; -// } -// } -// } -// if (reverseImage) { -// locImage = ImageUtil.flipHorizontally(locImage); -// } -// } -// default -> { -// w = locImage.getWidth(null); -// h = locImage.getHeight(null); -// if (null == departureSuffix) { -// xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w; -// } else { -// switch (departureSuffix) { -// case "-" -> { -// xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w - 25; -// } -// default -> { -// xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w + 10; -// } -// } -// } -// yy = DEFAULT_HEIGHT / 2 - h / 2; -// -// if (reverseImage) { -// locImage = ImageUtil.flipVertically(locImage); -// } -// } -// } -// -// g2i.drawImage(tileImage, 0, 0, null); -// g2i.drawImage(locImage, xx, yy, null); -// g2i.dispose(); -// tileImage = overlay; -// } -// } -// private Image getLocImage() { -// if (model.getLocomotive() != null && model.getLocomotive().getLocIcon() != null) { -// return model.getLocomotive().getLocIcon(); -// } else { -// return null; -// } -// } -// public String getBlockText() { -// String blockText; -// if (blockBean != null && blockBean.getDescription() != null) { -// if (blockBean.getLocomotive() != null && blockBean.getLocomotive().getName() != null && BlockState.GHOST != blockBean.getBlockState()) { -// blockText = blockBean.getLocomotive().getName(); -// } else { -// if (blockBean.getDescription().length() > 0) { -// blockText = blockBean.getDescription(); -// } else { -// blockText = getId(); -// } -// } -// } else { -// // Design mode show description when available -// if (blockBean != null && blockBean.getDescription() != null && blockBean.getDescription().length() > 0) { -// blockText = blockBean.getDescription(); -// } else { -// blockText = getId(); -// } -// } -// return blockText; -// } -// @Override -// public void drawName(Graphics2D g2d) { -// if (!model.isOverlayImage()) { -// g2d.setPaint(Color.black); -// -// Font currentFont = g2d.getFont(); -// Font newFont = currentFont.deriveFont(currentFont.getSize() * 10.0F); -// g2d.setFont(newFont); -// -// String blockText = getBlockText(); -// -// // Scale the text if necessary -// int textWidth = g2d.getFontMetrics().stringWidth(blockText); -// double fontscale = 10.0; -// if (textWidth > 845) { -// fontscale = fontscale * 847.0 / textWidth; -// newFont = currentFont.deriveFont(currentFont.getSize() * (float) fontscale); -// g2d.setFont(newFont); -// textWidth = g2d.getFontMetrics().stringWidth(blockText); -// } -// -// int textHeight = g2d.getFontMetrics().getHeight(); -// Orientation tileOrientation = model.getTileOrienation(); -// -// switch (tileOrientation) { -// case EAST -> { -// drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) - textWidth / 2, RENDER_GRID + textHeight / 3, 0, blockText); -// } -// case WEST -> { -// drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) + textWidth / 2, RENDER_GRID - textHeight / 3, 180, blockText); -// } -// case NORTH -> { -// drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) - textWidth / 2, RENDER_GRID + textHeight / 3, 0, blockText); -// } -// case SOUTH -> { -// drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) + textWidth / 2, RENDER_GRID - textHeight / 3, 180, blockText); -// } -// } -// // reset to the original font -// newFont = currentFont.deriveFont(currentFont.getSize() * 1.0F); -// g2d.setFont(newFont); -// } -// } @Override public Rectangle getTileBounds() { int multiplier = (model.isScaleImage() ? 1 : 10); @@ -756,49 +381,4 @@ public Rectangle getTileBounds() { } } -// @Override -// protected void paintComponent(Graphics g) { -// long started = System.currentTimeMillis(); -// -// Graphics2D g2 = (Graphics2D) g.create(); -// drawTile(g2); -// g2.dispose(); -// -// if (model.isOverlayImage()) { -// overlayLocImage(); -// } -// -// g.drawImage(tileImage, 0, 0, null); -// long now = System.currentTimeMillis(); -// Logger.trace(id + " Duration: " + (now - started) + " ms."); -// } -// @Override -// protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { -// //A block has 2 alternate points -// //1st square -// //2nd square holds the centerpoint -// //3rd square -// Orientation tileOrientation = model.getTileOrienation(); -// double dX1, dX2, dX3, dY1, dY2, dY3; -// if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { -// dX1 = renderWidth / 3 / 2 - size / 2 / 2; -// dY1 = renderHeight / 2 - size / 2 / 2; -// dX2 = renderWidth / 2 - size / 2; -// dY2 = renderHeight / 2 - size / 2; -// dX3 = renderWidth - renderWidth / 3 / 2 - size / 2 / 2; -// dY3 = renderHeight / 2 - size / 2 / 2; -// } else { -// dX1 = renderWidth / 2 - size / 2 / 2; -// dY1 = renderHeight / 3 / 2 - size / 2 / 2; -// dX2 = renderHeight / 2 - size / 2; -// dY2 = renderWidth / 2 - size / 2; -// dY3 = renderWidth / 2 - size / 2 / 2; -// dX3 = renderHeight - renderHeight / 3 / 2 - size / 2 / 2; -// } -// -// g2d.setColor(color); -// g2d.fill(new Ellipse2D.Double(dX1, dY1, size / 2, size / 2)); -// g2d.fill(new Ellipse2D.Double(dX2, dY2, size, size)); -// g2d.fill(new Ellipse2D.Double(dX3, dY3, size / 2, size / 2)); -// } } diff --git a/src/main/java/jcs/ui/layout/tiles/Cross.java b/src/main/java/jcs/ui/layout/tiles/Cross.java index 33b902f0..4fa88889 100644 --- a/src/main/java/jcs/ui/layout/tiles/Cross.java +++ b/src/main/java/jcs/ui/layout/tiles/Cross.java @@ -40,6 +40,9 @@ import jcs.ui.layout.tiles.ui.CrossUI; import jcs.ui.layout.tiles.ui.TileUI; +/** + * Representation of a Cross switch on the layout + */ public class Cross extends Switch { public static final int CROSS_WIDTH = DEFAULT_WIDTH * 2; @@ -254,223 +257,6 @@ public Map getEdgePoints() { return edgeConnections; } -// @Override -// protected void renderStraight(Graphics2D g2, Color color) { -// int xx, yy, w, h; -// xx = 0; -// yy = 170; -// w = RENDER_WIDTH; -// h = 60; -// -// g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); -// g2.setPaint(color); -// g2.fillRect(xx, yy, w, h); -// } -// @Override -// protected void renderRouteStraight(Graphics2D g2, Color color) { -// int xx, yy, w, h; -// xx = 0; -// yy = 190; -// w = RENDER_WIDTH; -// h = 20; -// -// g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); -// g2.setPaint(color); -// g2.fillRect(xx, yy, w, h); -// } -// protected void renderStraight2(Graphics2D g2, Color color) { -// int xx, yy, w, h; -// xx = RENDER_WIDTH; -// yy = 170; -// w = RENDER_WIDTH; -// h = 60; -// -// g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); -// g2.setPaint(color); -// g2.fillRect(xx, yy, w, h); -// } -// protected void renderRouteStraight2(Graphics2D g2, Color color) { -// int xx, yy, w, h; -// xx = RENDER_WIDTH; -// yy = 190; -// w = RENDER_WIDTH; -// h = 20; -// -// g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); -// g2.setPaint(color); -// g2.fillRect(xx, yy, w, h); -// } -// @Override -// protected void renderDiagonal(Graphics2D g2, Color color) { -// int[] xPoints, yPoints; -// if (Direction.RIGHT.equals(getDirection())) { -// xPoints = new int[]{400, 400, 167, 230}; -// yPoints = new int[]{170, 230, 0, 0}; -// } else { -// xPoints = new int[]{400, 400, 170, 230}; -// yPoints = new int[]{230, 170, 400, 400}; -// } -// -// g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); -// g2.setPaint(color); -// g2.fillPolygon(xPoints, yPoints, xPoints.length); -// } -// @Override -// protected void renderRouteDiagonal(Graphics2D g2, Color color) { -// int[] xPoints, yPoints; -// if (Direction.RIGHT.equals(getDirection())) { -// xPoints = new int[]{420, 400, 190, 210}; -// yPoints = new int[]{210, 210, 0, 0}; -// } else { -// xPoints = new int[]{400, 400, 190, 210}; -// yPoints = new int[]{210, 190, 400, 400}; -// } -// -// g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); -// g2.setPaint(color); -// g2.fillPolygon(xPoints, yPoints, xPoints.length); -// } -// protected void renderDiagonal2(Graphics2D g2, Color color) { -// int[] xPoints, yPoints; -// if (Direction.RIGHT.equals(getDirection())) { -// xPoints = new int[]{400, 400, 570, 630}; -// yPoints = new int[]{170, 230, 400, 400}; -// } else { -// xPoints = new int[]{400, 400, 570, 630}; -// yPoints = new int[]{230, 170, 0, 0}; -// } -// -// g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); -// g2.setPaint(color); -// g2.fillPolygon(xPoints, yPoints, xPoints.length); -// } -// protected void renderRouteDiagonal2(Graphics2D g2, Color color) { -// int[] xPoints, yPoints; -// if (Direction.RIGHT.equals(getDirection())) { -// xPoints = new int[]{400, 380, 590, 610}; -// yPoints = new int[]{190, 190, 400, 400}; -// } else { -// xPoints = new int[]{400, 380, 590, 610}; -// yPoints = new int[]{210, 210, 0, 0}; -// } -// -// g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); -// g2.setPaint(color); -// g2.setPaint(Color.cyan); -// g2.fillPolygon(xPoints, yPoints, xPoints.length); -// } -// @Override -// public void renderTile(Graphics2D g2) { -// if (accessoryValue == null) { -// this.accessoryValue = AccessoryValue.OFF; -// } -// -// switch (accessoryValue) { -// case RED -> { -// renderStraight2(g2, Cross.LIGHT_RED); -// renderDiagonal(g2, Cross.LIGHT_RED); -// renderStraight(g2, Cross.DARK_RED); -// renderDiagonal2(g2, Cross.DARK_RED); -// } -// case GREEN -> { -// renderDiagonal(g2, Cross.VERY_LIGHT_GREEN); -// renderDiagonal2(g2, Cross.VERY_LIGHT_GREEN); -// renderStraight(g2, Cross.DARK_GREEN); -// renderStraight2(g2, Cross.DARK_GREEN); -// } -// default -> { -// renderStraight(g2, trackColor); -// renderStraight2(g2, trackColor); -// renderDiagonal(g2, trackColor); -// renderDiagonal2(g2, trackColor); -// } -// } -// } -// @Override -// public void renderTileRoute(Graphics2D g2) { -// if (routeValue == null) { -// routeValue = AccessoryValue.OFF; -// } -// if (model.getIncomingSide() == null) { -// model.setIncomingSide(model.getTileOrienation()); -// } -// -// Orientation incomingSide = model.getIncomingSide(); -// -// if (isHorizontal()) { -// if (AccessoryValue.GREEN == routeValue && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { -// renderRouteDiagonal(g2, trackRouteColor); -// renderRouteDiagonal2(g2, trackRouteColor); -// } else if (AccessoryValue.GREEN == routeValue && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { -// renderRouteStraight(g2, trackRouteColor); -// renderRouteStraight2(g2, trackRouteColor); -// } else if (AccessoryValue.RED == routeValue && Orientation.EAST == getOrientation()) { -// if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { -// renderRouteStraight2(g2, trackRouteColor); -// renderRouteDiagonal(g2, trackRouteColor); -// } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { -// renderRouteDiagonal2(g2, trackRouteColor); -// renderRouteStraight(g2, trackRouteColor); -// } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { -// renderRouteStraight2(g2, trackRouteColor); -// renderRouteDiagonal(g2, trackRouteColor); -// } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { -// renderRouteStraight(g2, trackColor); -// renderRouteDiagonal2(g2, trackColor); -// } -// } else if (AccessoryValue.RED == routeValue && Orientation.WEST == getOrientation()) { -// if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { -// renderRouteStraight(g2, trackRouteColor); -// renderRouteDiagonal2(g2, trackRouteColor); -// } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { -// renderRouteDiagonal(g2, trackRouteColor); -// renderRouteStraight2(g2, trackRouteColor); -// } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { -// renderRouteStraight(g2, trackRouteColor); -// renderRouteDiagonal2(g2, trackRouteColor); -// } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { -// renderRouteStraight2(g2, trackColor); -// renderRouteDiagonal(g2, trackColor); -// } -// } -// } else { -// if (AccessoryValue.GREEN == routeValue && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { -// renderRouteStraight(g2, trackRouteColor); -// renderRouteStraight2(g2, trackRouteColor); -// } else if (AccessoryValue.GREEN == routeValue && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { -// renderRouteDiagonal(g2, trackRouteColor); -// renderRouteDiagonal2(g2, trackRouteColor); -// } else if (AccessoryValue.RED == routeValue && Orientation.SOUTH == getOrientation()) { -// if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { -// renderRouteStraight2(g2, trackRouteColor); -// renderRouteDiagonal(g2, trackRouteColor); -// } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { -// renderRouteDiagonal2(g2, trackRouteColor); -// renderRouteStraight(g2, trackRouteColor); -// } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { -// renderRouteStraight(g2, trackRouteColor); -// renderRouteDiagonal2(g2, trackRouteColor); -// } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { -// renderRouteStraight2(g2, trackColor); -// renderRouteDiagonal(g2, trackColor); -// } -// } else if (AccessoryValue.RED == routeValue && Orientation.NORTH == getOrientation()) { -// if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { -// renderRouteStraight(g2, trackRouteColor); -// renderRouteDiagonal2(g2, trackRouteColor); -// } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { -// renderRouteDiagonal(g2, trackRouteColor); -// renderRouteStraight2(g2, trackRouteColor); -// } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { -// renderRouteStraight2(g2, trackRouteColor); -// renderRouteDiagonal(g2, trackRouteColor); -// } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { -// renderRouteStraight(g2, trackColor); -// renderRouteDiagonal2(g2, trackColor); -// } -// } -// } -// } @Override public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { if (from != null && to != null && this.getDirection() != null) { @@ -540,45 +326,6 @@ public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { } } -// @Override -// protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { -// //A Cross has 1 alternate point -// //1st square holds the centerpoint -// //2nd square -// double dX1, dX2, dY1, dY2; -// Orientation tileOrientation = model.getTileOrienation(); -// switch (tileOrientation) { -// case SOUTH -> { -// dX1 = renderWidth / 2 - size / 2; -// dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; -// dX2 = renderWidth / 2 + renderWidth - size / 4; -// dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; -// } -// case WEST -> { -// dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; -// dY1 = renderHeight / 2 - size / 2; -// dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; -// dY2 = renderHeight / 2 - size / 4; -// } -// case NORTH -> { -// dX1 = renderWidth / 2 - size / 2; -// dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; -// dX2 = renderWidth / 2 + renderWidth - size / 4; -// dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; -// } -// default -> { -// //East -// dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; -// dY1 = renderHeight / 2 - size / 2; -// dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; -// dY2 = renderHeight / 2 - size / 4; -// } -// } -// -// g2d.setColor(color); -// g2d.fill(new Ellipse2D.Double(dX1, dY1, size, size)); -// g2d.fill(new Ellipse2D.Double(dX2, dY2, size / 2, size / 2)); -// } @Override public Rectangle getTileBounds() { Orientation tileOrientation = model.getTileOrienation(); @@ -627,54 +374,13 @@ public Rectangle getTileBounds() { } private void changeRenderSizeAndOffsets() { - -// if (getUI() instanceof CrossUI cui) { -// -// cui.changeRenderSize(this); -// } else { -// Logger.warn("UI is a "+getUI().getClass().getSimpleName()); -// } - //Reset offsets -// this.offsetY = 0; this.renderOffsetY = 0; -// this.offsetX = 0; this.renderOffsetX = 0; if (isHorizontal()) { - //this.renderWidth = RENDER_GRID * 4; - //this.renderHeight = RENDER_GRID * 2; - -// this.offsetY = 0; this.renderOffsetY = 0; } else { - //this.renderWidth = RENDER_GRID * 2; - //this.renderHeight = RENDER_GRID * 4; - - /// this.offsetX = 0; this.renderOffsetX = 0; } - - //Due to the asymetical shape (center is on the left) - //the offset has to be changed with the rotation -// Orientation tileOrientation = model.getTileOrienation(); -// switch (tileOrientation) { -// case SOUTH -> { -// this.offsetY = +GRID; -// this.renderOffsetY = RENDER_GRID; -// } -// case WEST -> { -// this.offsetX = -GRID; -// this.renderOffsetX = -RENDER_GRID; -// } -// case NORTH -> { -// this.offsetY = -GRID; -// this.renderOffsetY = -RENDER_GRID; -// } -// default -> { -// //East so default -// this.offsetX = +GRID; -// this.renderOffsetX = +RENDER_GRID; -// } -// } } @Override diff --git a/src/main/java/jcs/ui/layout/tiles/Crossing.java b/src/main/java/jcs/ui/layout/tiles/Crossing.java index f9f7cc97..1a00e86f 100644 --- a/src/main/java/jcs/ui/layout/tiles/Crossing.java +++ b/src/main/java/jcs/ui/layout/tiles/Crossing.java @@ -25,6 +25,9 @@ import jcs.ui.layout.tiles.ui.CrossingUI; import jcs.ui.layout.tiles.ui.TileUI; +/** + * Representation of a (passive) Crossing the layout + */ public class Crossing extends Straight { public Crossing(TileBean tileBean) { diff --git a/src/main/java/jcs/ui/layout/tiles/Curved.java b/src/main/java/jcs/ui/layout/tiles/Curved.java index d52281e4..124f4a44 100755 --- a/src/main/java/jcs/ui/layout/tiles/Curved.java +++ b/src/main/java/jcs/ui/layout/tiles/Curved.java @@ -28,6 +28,9 @@ import jcs.ui.layout.tiles.ui.CurvedUI; import jcs.ui.layout.tiles.ui.TileUI; +/** + * Representation of a Curved track on the layout + */ public class Curved extends Tile { public Curved(TileBean tileBean) { diff --git a/src/main/java/jcs/ui/layout/tiles/End.java b/src/main/java/jcs/ui/layout/tiles/End.java index 38b2383f..a1c5e6aa 100644 --- a/src/main/java/jcs/ui/layout/tiles/End.java +++ b/src/main/java/jcs/ui/layout/tiles/End.java @@ -28,6 +28,9 @@ import jcs.ui.layout.tiles.ui.EndUI; import jcs.ui.layout.tiles.ui.TileUI; +/** + * Representation of a End track on the layout + */ public class End extends Tile { public End(TileBean tileBean) { diff --git a/src/main/java/jcs/ui/layout/tiles/Sensor.java b/src/main/java/jcs/ui/layout/tiles/Sensor.java index 3b0bcd7d..25ecf42b 100644 --- a/src/main/java/jcs/ui/layout/tiles/Sensor.java +++ b/src/main/java/jcs/ui/layout/tiles/Sensor.java @@ -26,6 +26,9 @@ import jcs.ui.layout.tiles.ui.SensorUI; import jcs.ui.layout.tiles.ui.TileUI; +/** + * Representation of a Sensor in a track on the layout + */ public class Sensor extends Straight implements SensorEventListener { public Sensor(TileBean tileBean) { diff --git a/src/main/java/jcs/ui/layout/tiles/Signal.java b/src/main/java/jcs/ui/layout/tiles/Signal.java index 982b666d..25765a26 100644 --- a/src/main/java/jcs/ui/layout/tiles/Signal.java +++ b/src/main/java/jcs/ui/layout/tiles/Signal.java @@ -27,6 +27,9 @@ import jcs.ui.layout.tiles.ui.SignalUI; import jcs.ui.layout.tiles.ui.TileUI; +/** + * Representation of a Signal besides the track on the layout + */ public class Signal extends Straight implements AccessoryEventListener { Signal(TileBean tileBean) { @@ -60,278 +63,6 @@ public void updateUI() { invalidate(); } -// /** -// * Render a Signal with 2 lights -// * -// * @param g2d the graphics context -// */ -// protected void renderSignal2(Graphics2D g2d) { -// int rx = RENDER_GRID; -// int ry = RENDER_GRID + 60; -// int rw = 180; -// int rh = 100; -// int l1x = RENDER_GRID + 20; -// int l1y = RENDER_GRID + 80; -// int l2x = RENDER_GRID + 100; -// int l2y = RENDER_GRID + 80; -// -// Color color1 = Color.gray; -// Color color2 = Color.gray; -// -// if (this.signalValue == null) { -// this.signalValue = SignalValue.OFF; -// } -// -// switch (signalValue) { -// case Hp0 -> { -// color1 = Color.red; -// color2 = Color.gray; -// } -// case Hp1 -> { -// color1 = Color.gray; -// color2 = Color.green; -// } -// default -> { -// } -// } -// -// g2d.setStroke(new BasicStroke(10f)); -// g2d.setPaint(Color.darkGray); -// g2d.fillRoundRect(rx, ry, rw, rh, 30, 30); -// -// g2d.setPaint(color1); -// g2d.fillOval(l1x, l1y, 60, 60); -// g2d.setPaint(color2); -// g2d.fillOval(l2x, l2y, 60, 60); -// } -// protected void renderSignal3(Graphics2D g2d) { -// int rx = RENDER_GRID; -// int ry = RENDER_GRID + 60; -// int rw = 180; -// int rh = 100; -// -// int c1x = RENDER_GRID + 130; -// int c1y = RENDER_GRID + 115; -// -// int c2x = RENDER_GRID + 10; -// int c2y = RENDER_GRID + 115; -// -// int c3x = RENDER_GRID + 10; -// int c3y = RENDER_GRID + 65; -// -// // Initialize all "lights" -// Color color1 = Color.gray; -// Color color2 = Color.gray; -// Color color3 = Color.gray; -// -// if (this.signalValue == null) { -// this.signalValue = SignalValue.OFF; -// } -// -// switch (this.signalValue) { -// case Hp0 -> { -// color3 = Color.red; -// } -// case Hp1 -> -// color1 = Color.green; -// case Hp2 -> { -// color1 = Color.green; -// color2 = Color.yellow; -// } -// default -> { -// } -// } -// -// g2d.setStroke(new BasicStroke(10f)); -// g2d.setPaint(Color.darkGray); -// g2d.fillRoundRect(rx, ry, rw, rh, 30, 30); -// -// g2d.setPaint(color1); -// g2d.fillOval(c1x, c1y, 40, 40); -// -// g2d.setPaint(color2); -// g2d.fillOval(c2x, c2y, 40, 40); -// -// g2d.setPaint(color3); -// g2d.fillOval(c3x, c3y, 40, 40); -// } -// /** -// * Render a entry Signal which can show 4 light images -// * -// * @param g2d the Graphics context -// */ -// protected void renderSignal4(Graphics2D g2d) { -// int rx = RENDER_GRID - 50; -// int ry = RENDER_GRID + 50; -// int rw = 240; -// int rh = 120; -// int c1x = RENDER_GRID + 140; -// int c1y = RENDER_GRID + 60; -// -// int c2x = RENDER_GRID + 90; -// int c2y = RENDER_GRID + 60; -// -// int c3x = RENDER_GRID + 90; -// int c3y = RENDER_GRID + 120; -// -// int c4x = RENDER_GRID + 60; -// int c4y = RENDER_GRID + 130; -// -// int c5x = RENDER_GRID + 10; -// int c5y = RENDER_GRID + 70; -// -// int c6x = RENDER_GRID - 40; -// int c6y = RENDER_GRID + 60; -// -// // Initialize all "lights" -// Color color1 = Color.gray; -// Color color2 = Color.gray; -// Color color3 = Color.gray; -// Color color4 = Color.gray; -// Color color5 = Color.gray; -// Color color6 = Color.gray; -// -// if (this.signalValue == null) { -// this.signalValue = SignalValue.OFF; -// } -// -// switch (this.signalValue) { -// case Hp0 -> { -// color2 = Color.red; -// color3 = Color.red; -// } -// case Hp1 -> -// color1 = Color.green; -// case Hp2 -> { -// color1 = Color.green; -// color6 = Color.yellow; -// } -// case Hp0Sh1 -> { -// color2 = Color.red; -// color4 = Color.white; -// color5 = Color.white; -// } -// default -> { -// } -// } -// -// g2d.setStroke(new BasicStroke(10f)); -// g2d.setPaint(Color.darkGray); -// g2d.fillRoundRect(rx, ry, rw, rh, 30, 30); -// -// g2d.setPaint(color1); -// g2d.fillOval(c1x, c1y, 40, 40); -// g2d.setPaint(color2); -// g2d.fillOval(c2x, c2y, 40, 40); -// g2d.setPaint(color3); -// g2d.fillOval(c3x, c3y, 40, 40); -// g2d.setPaint(color4); -// g2d.fillOval(c4x, c4y, 20, 20); -// g2d.setPaint(color5); -// g2d.fillOval(c5x, c5y, 20, 20); -// g2d.setPaint(color6); -// g2d.fillOval(c6x, c6y, 40, 40); -// } -// /** -// * Render a midget Signal -// * -// * @param g2d the Graphics context -// */ -// protected void renderSignal2m(Graphics2D g2d) { -// int[] xps -// = new int[]{ -// RENDER_GRID + 80, -// +RENDER_GRID + 150, -// +RENDER_GRID + 170, -// RENDER_GRID + 170, -// +RENDER_GRID + 150, -// RENDER_GRID + 80 -// }; -// int[] yps -// = new int[]{ -// RENDER_GRID + 60, -// RENDER_GRID + 60, -// RENDER_GRID + 80, -// +RENDER_GRID + 160, -// +RENDER_GRID + 180, -// RENDER_GRID + 180 -// }; -// -// Polygon signalOutline = new Polygon(xps, yps, xps.length); -// -// int c1x = RENDER_GRID + 130; -// int c1y = RENDER_GRID + 70; -// -// int c2x = RENDER_GRID + 130; -// int c2y = RENDER_GRID + 140; -// -// int c3x = RENDER_GRID + 130; -// int c3y = RENDER_GRID + 105; -// -// int c4x = RENDER_GRID + 85; -// int c4y = RENDER_GRID + 70; -// -// Color color1 = Color.gray; -// Color color2 = Color.gray; -// Color color3 = Color.gray; -// Color color4 = Color.gray; -// -// if (this.signalValue == null) { -// this.signalValue = SignalValue.OFF; -// } -// -// switch (this.signalValue) { -// case Hp0 -> { -// color1 = Color.red; -// color2 = Color.red; -// } -// case Hp1 -> { -// color3 = Color.white; -// color4 = Color.white; -// } -// default -> { -// } -// } -// -// g2d.setStroke(new BasicStroke(10f)); -// g2d.setPaint(Color.darkGray); -// -// g2d.fillPolygon(signalOutline); -// -// g2d.setPaint(color1); -// g2d.fillOval(c1x, c1y, 30, 30); -// -// g2d.setPaint(color2); -// g2d.fillOval(c2x, c2y, 30, 30); -// -// g2d.setPaint(color3); -// g2d.fillOval(c3x, c3y, 30, 30); -// -// g2d.setPaint(color4); -// g2d.fillOval(c4x, c4y, 30, 30); -// } -// @Override -// public void renderTile(Graphics2D g2) { -// Graphics2D g2d = (Graphics2D) g2.create(); -// renderStraight(g2d); -// -// if (signalType == null) { -// signalType = SignalType.NONE; -// } -// -// switch (signalType) { -// case HP012 -> -// renderSignal3(g2d); -// case HP012SH1 -> -// renderSignal4(g2d); -// case HP0SH1 -> -// renderSignal2m(g2d); -// default -> -// renderSignal2(g2d); -// } -// -// g2d.dispose(); -// } //TODO move to UI delegate @Override public void onAccessoryChange(AccessoryEvent event) { diff --git a/src/main/java/jcs/ui/layout/tiles/Straight.java b/src/main/java/jcs/ui/layout/tiles/Straight.java index 2160a5f1..437c48ff 100755 --- a/src/main/java/jcs/ui/layout/tiles/Straight.java +++ b/src/main/java/jcs/ui/layout/tiles/Straight.java @@ -25,6 +25,9 @@ import jcs.entities.TileBean.Orientation; import jcs.entities.TileBean.TileType; +/** + * Representation of a Straight track on the layout + */ public class Straight extends Tile { public Straight(TileBean tileBean) { diff --git a/src/main/java/jcs/ui/layout/tiles/StraightDirection.java b/src/main/java/jcs/ui/layout/tiles/StraightDirection.java index df847634..a3ae761c 100644 --- a/src/main/java/jcs/ui/layout/tiles/StraightDirection.java +++ b/src/main/java/jcs/ui/layout/tiles/StraightDirection.java @@ -24,6 +24,9 @@ import jcs.ui.layout.tiles.ui.StraightDirectionUI; import jcs.ui.layout.tiles.ui.TileUI; +/** + * Representation of a Straight track where trans can only run in one direction on the layout + */ public class StraightDirection extends Straight { public StraightDirection(TileBean tileBean) { @@ -74,19 +77,4 @@ public boolean isArrowDirection(Tile other) { } return arrowDirection && isAdjacent(other); } - -// private void renderDirectionArrow(Graphics2D g2) { -// // |\ -// // ==|+=== -// // |/ -// g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); -// g2.setPaint(Color.green.darker()); -// -// g2.fillPolygon(new int[]{150, 150, 270}, new int[]{130, 270, 200}, 3); -// } -// @Override -// public void renderTile(Graphics2D g2d) { -// renderStraight(g2d); -// renderDirectionArrow(g2d); -// } } diff --git a/src/main/java/jcs/ui/layout/tiles/Switch.java b/src/main/java/jcs/ui/layout/tiles/Switch.java index 933583f8..1ce2f43f 100644 --- a/src/main/java/jcs/ui/layout/tiles/Switch.java +++ b/src/main/java/jcs/ui/layout/tiles/Switch.java @@ -34,6 +34,9 @@ import jcs.ui.layout.tiles.ui.SwitchUI; import jcs.ui.layout.tiles.ui.TileUI; +/** + * Representation of a Switch or Turnout on the layout + */ public class Switch extends Tile implements AccessoryEventListener { public Switch(Orientation orientation, Direction direction, Point center) { @@ -180,96 +183,6 @@ public Map getEdgePoints() { return edgeConnections; } -// protected void renderStraight(Graphics2D g2, Color color) { -// int xx, yy, w, h; -// xx = 0; -// yy = 170; -// w = RENDER_WIDTH; -// h = 60; -// -// g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); -// g2.setPaint(color); -// -// g2.fillRect(xx, yy, w, h); -// } -// protected void renderDiagonal(Graphics2D g2, Color color) { -// int[] xPoints, yPoints; -// if (Direction.RIGHT.equals(getDirection())) { -// xPoints = new int[]{400, 400, 170, 230}; -// yPoints = new int[]{170, 230, 0, 0}; -// } else { -// xPoints = new int[]{400, 400, 170, 230}; -// yPoints = new int[]{230, 170, 400, 400}; -// } -// -// g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); -// g2.setPaint(color); -// g2.fillPolygon(xPoints, yPoints, xPoints.length); -// } -// protected void renderRouteStraight(Graphics2D g2, Color color) { -// int xx, yy, w, h; -// xx = 0; -// yy = 190; -// w = RENDER_WIDTH; -// h = 20; -// -// g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); -// g2.setPaint(color); -// -// g2.fillRect(xx, yy, w, h); -// } -// protected void renderRouteDiagonal(Graphics2D g2, Color color) { -// int[] xPoints, yPoints; -// if (Direction.RIGHT.equals(getDirection())) { -// xPoints = new int[]{400, 400, 190, 210}; -// yPoints = new int[]{190, 210, 0, 0}; -// } else { -// xPoints = new int[]{400, 400, 190, 210}; -// yPoints = new int[]{210, 190, 400, 400}; -// } -// -// g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); -// g2.setPaint(color); -// -// g2.fillPolygon(xPoints, yPoints, xPoints.length); -// } -// @Override -// public void renderTile(Graphics2D g2) { -// if (accessoryValue == null) { -// this.accessoryValue = AccessoryValue.OFF; -// } -// -// switch (accessoryValue) { -// case RED -> { -// renderStraight(g2, trackColor); -// renderDiagonal(g2, Color.red); -// } -// case GREEN -> { -// renderDiagonal(g2, trackColor); -// renderStraight(g2, Color.green); -// } -// default -> { -// renderStraight(g2, trackColor); -// renderDiagonal(g2, trackColor); -// } -// } -// } -// @Override -// public void renderTileRoute(Graphics2D g2) { -// if (routeValue == null) { -// routeValue = AccessoryValue.OFF; -// } -// switch (routeValue) { -// case RED -> { -// renderRouteDiagonal(g2, trackRouteColor); -// } -// case GREEN -> { -// renderRouteStraight(g2, trackRouteColor); -// } -// default -> { -// } -// } -// } @Override public void onAccessoryChange(AccessoryEvent event) { if (getAccessoryBean() != null && event.isEventFor(accessoryBean)) { diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java index 688c48f8..e36a3df1 100755 --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -19,7 +19,6 @@ import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; -import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.ActionEvent; @@ -70,7 +69,9 @@ * Rotation will change the orientation from East -> South -> West -> North -> East.
* *

- * A Tile is rendered to a Buffered Image to speed up the display + * Tile follows the MVC Patten, hence all properties which could change during operation
+ * which have an influence on the screen are in the TileModel.
+ * All Drawing code is in the TileUI. */ public abstract class Tile extends JComponent { // implements ChangeListener @@ -78,9 +79,6 @@ public abstract class Tile extends JComponent { // implements ChangeListener public static final int DEFAULT_WIDTH = GRID * 2; public static final int DEFAULT_HEIGHT = GRID * 2; - //static final int RENDER_GRID = GRID * 10; - //static final int RENDER_WIDTH = RENDER_GRID * 2; - //static final int RENDER_HEIGHT = RENDER_GRID * 2; public static final Color DEFAULT_BACKGROUND_COLOR = Color.white; public static final Color DEFAULT_TRACK_COLOR = Color.lightGray; public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.darkGray; @@ -91,7 +89,7 @@ public abstract class Tile extends JComponent { // implements ChangeListener // public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled"; /** - * The data model that determines the button's state. + * The data model that determines the Tile state. */ protected TileModel model = null; @@ -99,8 +97,6 @@ public abstract class Tile extends JComponent { // implements ChangeListener protected Integer tileX; protected Integer tileY; - //protected int renderWidth; - //protected int renderHeight; protected Direction tileDirection; protected TileType tileType; @@ -120,16 +116,9 @@ public abstract class Tile extends JComponent { // implements ChangeListener protected List neighbours; -// protected int offsetX = 0; -// protected int offsetY = 0; - protected int renderOffsetX = 0; protected int renderOffsetY = 0; - //protected Color trackColor; - //protected Color trackRouteColor; - //protected Orientation incomingSide; - //protected Color backgroundColor; protected boolean drawName = true; protected BufferedImage tileImage; @@ -164,14 +153,6 @@ protected Tile(TileType tileType, Orientation orientation, Direction direction, Dimension d = new Dimension(width, height); setSize(d); setPreferredSize(d); - - //this.renderWidth = RENDER_WIDTH; - //this.renderHeight = RENDER_HEIGHT; - //this.trackColor = DEFAULT_TRACK_COLOR; - //this.backgroundColor = backgroundColor; - //if (this.backgroundColor == null) { - // this.backgroundColor = DEFAULT_BACKGROUND_COLOR; - //} } protected Tile(TileBean tileBean) { @@ -180,7 +161,6 @@ protected Tile(TileBean tileBean) { protected Tile(TileBean tileBean, int width, int height) { this.tileBean = tileBean; - //Quick properties this.id = tileBean.getId(); this.tileType = tileBean.getTileType(); this.tileDirection = tileBean.getDirection(); @@ -199,11 +179,6 @@ protected Tile(TileBean tileBean, int width, int height) { Dimension d = new Dimension(width, height); setSize(d); setPreferredSize(d); - - //this.trackColor = DEFAULT_TRACK_COLOR; - //this.backgroundColor = DEFAULT_BACKGROUND_COLOR; - //this.renderWidth = RENDER_WIDTH; - //this.renderHeight = RENDER_HEIGHT; } @Override @@ -251,19 +226,6 @@ public void setModel(TileModel newModel) { } } -// @Override -// public String getUIClassID() { -// return TileUI.UI_CLASS_ID; -// } -// @Override -// public void updateUI() { -// if (UIManager.get(TileUI.UI_CLASS_ID) == null) { -// UIManager.put(TileUI.UI_CLASS_ID, getUIClassID()); -// } -// -// setUI((TileUI) UIManager.getUI(this)); -// invalidate(); -// } protected static int tileWidth(Orientation orientation, TileType tileType) { if (Orientation.EAST == orientation || Orientation.WEST == orientation) { if (null == tileType) { @@ -318,7 +280,6 @@ public TileBean getTileBean() { tileBean.setX(this.tileX); tileBean.setY(this.tileY); tileBean.setTileType(this.tileType); - //tileBean.setTileOrientation(this.tileOrientation.getOrientation()); tileBean.setTileOrientation(this.model.getTileOrienation().getOrientation()); tileBean.setTileDirection(this.tileDirection.getDirection()); @@ -332,6 +293,10 @@ public TileBean getTileBean() { return tileBean; } + /** + * + * @return true when the Tile is selected in the screen + */ public boolean isSelected() { return model.isSelected(); } @@ -356,14 +321,26 @@ public void setSignalType(SignalType signalType) { this.signalType = signalType; } + /** + * + * @return the Tile X coordinate on the screen. + */ public Integer getTileX() { return tileX; } + /** + * + * @return the Tile Y coordinate on the screen + */ public Integer getTileY() { return tileY; } + /** + * + * @return the Tile X and Y coordinates on the screen. + */ public Point getCenter() { return new Point(this.tileX, this.tileY); } @@ -376,6 +353,10 @@ public void setCenter(Point center) { } } + /** + * + * @return The Tile Orientation. The default orientation is East or from left to right + */ public Orientation getOrientation() { return model.getTileOrienation(); } @@ -553,12 +534,6 @@ public void setBlockBean(BlockBean blockBean) { this.blockBean = blockBean; } -// public void setRenderWidth(int renderWidth) { -// this.renderWidth = renderWidth; -// } -// public void setRenderHeight(int renderHeight) { -// this.renderHeight = renderHeight; -// } public int getRenderOffsetX() { return renderOffsetX; } @@ -583,17 +558,11 @@ public final void setTileType(TileType tileType) { this.tileType = tileType; } -// public Color getTrackColor() { -// return trackColor; -// } public void setTrackColor(Color trackColor) { if (getUI() != null) { getUI().setTrackColor(trackColor); } } -// public Color getTrackRouteColor() { -// return trackRouteColor; -// } public void setTrackRouteColor(Color trackRouteColor) { if (getUI() != null) { @@ -617,12 +586,6 @@ public void setIncomingSide(Orientation incomingSide) { model.setIncomingSide(incomingSide); } -// public Color getBackgroundColor() { -// return backgroundColor; -// } -// public void setBackgroundColor(Color backgroundColor) { -// this.backgroundColor = backgroundColor; -// } public boolean isShowRoute() { return model.isShowRoute(); } @@ -631,14 +594,13 @@ public void setShowRoute(boolean drawRoute) { this.model.setShowRoute(drawRoute); } -// public int getRenderWidth() { -// return renderWidth; -// } -// public int getRenderHeight() { -// return renderHeight; -// } -// abstract void renderTile(Graphics2D g2d); -// abstract void renderTileRoute(Graphics2D g2d); + /** + * + * @return a Map of points which are adjacent of the Tile
+ * The key is the location with respect to this tile, i.e. is the neighbor point o the East (right side)>
+ * on the west side (on the left) or on the top (north) or bottom (south). + * + */ public abstract Map getNeighborPoints(); public abstract Map getEdgePoints(); @@ -657,101 +619,6 @@ Set getAllPoints(Point center) { return aps; } - /** - * Draw the Tile - * - * @param g2d The graphics handle - */ -// public void drawTile(Graphics2D g2d) { -// // by default and image is rendered in the EAST orientation -// Orientation tileOrientation = model.getTileOrienation(); -// -// BufferedImage bf = createImage(); -// Graphics2D g2di = bf.createGraphics(); -// -// //Avoid errors -// if (model.isShowRoute() && model.getIncomingSide() == null) { -// model.setIncomingSide(tileOrientation); -// } -// -// if (model.isSelected()) { -// g2di.setBackground(model.getSelectedColor()); -// } else { -// g2di.setBackground(backgroundColor); -// } -// -// g2di.clearRect(0, 0, renderWidth, renderHeight); -// int ox = 0, oy = 0; -// -// AffineTransform trans = new AffineTransform(); -// switch (tileOrientation) { -// case SOUTH -> { -// trans.rotate(Math.PI / 2, renderWidth / 2, renderHeight / 2); -// ox = (renderHeight - renderWidth) / 2; -// oy = (renderWidth - renderHeight) / 2; -// trans.translate(-ox, -oy); -// } -// case WEST -> { -// trans.rotate(Math.PI, renderWidth / 2, renderHeight / 2); -// trans.translate(ox, oy); -// } -// case NORTH -> { -// trans.rotate(-Math.PI / 2, renderWidth / 2, renderHeight / 2); -// ox = (renderHeight - renderWidth) / 2; -// oy = (renderWidth - renderHeight) / 2; -// trans.translate(-ox, -oy); -// } -// default -> { -// trans.rotate(0.0, this.renderWidth / 2, this.renderHeight / 2); -// trans.translate(ox, oy); -// } -// } -// -// //Logger.trace(tileOrientation.getOrientation() + " renderWidth: " + renderWidth + " renderHeight: " + renderHeight + " CP: (" + renderWidth / 2 + "," + renderHeight / 2 + ")"); -// //Logger.trace(tileOrientation.getOrientation() + " ox: " + ox + " oy: " + oy); -// g2di.setTransform(trans); -// -// renderTile(g2di); -// -// if (model.isShowRoute()) { -// renderTileRoute(g2di); -// } -// -// if (model.isShowCenter()) { -// drawCenterPoint(g2di); -// } -// -// // Scale the image back... -// if (model.isScaleImage()) { -// tileImage = Scalr.resize(bf, Method.AUTOMATIC, Mode.FIT_EXACT, getWidth(), getHeight(), Scalr.OP_ANTIALIAS); -// } else { -// tileImage = bf; -// } -// g2di.dispose(); -// } -// public BufferedImage getTileImage() { -// return tileImage; -// } - /** - * Render a tile image Always starts at (0,0) used the default width and height - * - * @param g2 the Graphic context - */ -// public void drawName(Graphics2D g2) { -// } -// protected void drawCenterPoint(Graphics2D g2d) { -// drawCenterPoint(g2d, Color.magenta); -// } -// protected void drawCenterPoint(Graphics2D g2, Color color) { -// drawCenterPoint(g2, color, 60); -// } -// protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { -// double dX = (renderWidth / 2 - size / 2); -// double dY = (renderHeight / 2 - size / 2); -// -// g2d.setColor(color); -// g2d.fill(new Ellipse2D.Double(dX, dY, size, size)); -// } /** * Rotate the tile clockwise 90 deg * @@ -794,14 +661,6 @@ public void move(int newX, int newY) { setCenter(cs); } -// protected static void drawRotate(Graphics2D g2d, double x, double y, int angle, String text) { -// g2d.translate((float) x, (float) y); -// g2d.rotate(Math.toRadians(angle)); -// g2d.drawString(text, 0, 0); -// g2d.rotate(-Math.toRadians(angle)); -// g2d.translate(-x, -y); -// } - public static BufferedImage flipHorizontally(BufferedImage source) { BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); @@ -830,25 +689,6 @@ public Set getAltPoints() { return Collections.EMPTY_SET; } -// public final int getOffsetX() { -// return offsetX; -// } -// -// public void setOffsetX(int offsetX) { -// this.offsetX = offsetX; -// } -// -// public final int getOffsetY() { -// return offsetY; -// } -// -// public void setOffsetY(int offsetY) { -// this.offsetY = offsetY; -// } - -// protected BufferedImage createImage() { -// return new BufferedImage(renderWidth, renderHeight, BufferedImage.TYPE_INT_RGB); -// } public int getCenterX() { if (tileX > 0) { return this.tileX; @@ -1050,8 +890,6 @@ class Handler implements ActionListener, ChangeListener, Serializable { @Override public void stateChanged(ChangeEvent e) { - //Object source = e.getSource(); - fireStateChanged(); repaint(); } @@ -1108,18 +946,12 @@ public Rectangle getTileBounds() { @Override protected void paintComponent(Graphics g) { - long started = System.currentTimeMillis(); - - super.paintComponent(g); - - //Graphics2D g2 = (Graphics2D) g.create(); - //Graphics2D g2 = (Graphics2D) g.create(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); - //drawTile(g2); - //getUI().drawTile(g2, this); - //g2.dispose(); - //g.drawImage(tileImage, 0, 0, null); - long now = System.currentTimeMillis(); - Logger.trace(id + " Duration: " + (now - started) + " ms. Cp: " + xyToString() + " O: " + model.getTileOrienation()); + if (Logger.isTraceEnabled()) { + long started = System.currentTimeMillis(); + super.paintComponent(g); + long now = System.currentTimeMillis(); + Logger.trace(id + " Duration: " + (now - started) + " ms. Cp: " + xyToString() + " O: " + model.getTileOrienation()); + } } } diff --git a/src/main/java/jcs/ui/layout/tiles/ui/CrossUI.java b/src/main/java/jcs/ui/layout/tiles/ui/CrossUI.java index a592b60d..94255d94 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/CrossUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/CrossUI.java @@ -36,41 +36,12 @@ public class CrossUI extends TileUI { public CrossUI() { super(); - //Default is east -// this.renderWidth = RENDER_GRID * 4; -// this.renderHeight = RENDER_GRID * 2; } public static ComponentUI createUI(JComponent c) { return new CrossUI(); } -// public void changeRenderSize(Tile tile) { -// //Reset offsets -// //this.offsetY = 0; -// //this.renderOffsetY = 0; -// //this.offsetX = 0; -// //this.renderOffsetX = 0; -// -// if (tile.isHorizontal()) { -// this.renderWidth = RENDER_GRID * 4; -// this.renderHeight = RENDER_GRID * 2; -// -// //this.offsetY = 0; -// //this.renderOffsetY = 0; -// } else { -// this.renderWidth = RENDER_GRID * 2; -// this.renderHeight = RENDER_GRID * 4; -// -// //this.offsetX = 0; -// //this.renderOffsetX = 0; -// } -// -// //Due to the asymetical shape (center is on the left) -// //the offset has to be changed with the rotation -//// } -// } - protected void renderStraight(Graphics2D g2, Color color) { int xx = 0; int yy = 170; @@ -237,8 +208,6 @@ public void renderTileRoute(Graphics2D g2, JComponent c) { routeValue = AccessoryBean.AccessoryValue.OFF; } - //Color trackColor = tile.getTrackColor(); - //Color trackRouteColor = tile.getTrackRouteColor(); if (tile.isHorizontal()) { if (AccessoryBean.AccessoryValue.GREEN == routeValue && (TileBean.Orientation.NORTH == incomingSide || TileBean.Orientation.SOUTH == incomingSide)) { renderRouteDiagonal(g2, trackRouteColor, c); diff --git a/src/main/java/jcs/ui/layout/tiles/ui/CrossingUI.java b/src/main/java/jcs/ui/layout/tiles/ui/CrossingUI.java index b7fe6b5b..90eec11c 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/CrossingUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/CrossingUI.java @@ -20,6 +20,7 @@ import java.awt.Graphics2D; import javax.swing.JComponent; import javax.swing.plaf.ComponentUI; +import jcs.entities.TileBean.Orientation; import jcs.ui.layout.tiles.Tile; public class CrossingUI extends StraightUI { @@ -32,9 +33,6 @@ public static ComponentUI createUI(JComponent c) { } protected void renderVerticalAndDividers(Graphics2D g2, JComponent c) { - Tile tile = (Tile) c; - //Color trackColor = tile.getTrackColor(); - int xxn = 175; int yyn = 0; int xxs = 175; @@ -65,16 +63,12 @@ protected void renderVerticalAndDividers(Graphics2D g2, JComponent c) { } protected void renderRouteVertical(Graphics2D g2, JComponent c) { - Tile tile = (Tile) c; - //Color trackRouteColor = tile.getTrackRouteColor(); - - int xxn, yyn, xxs, yys, w, h; - xxn = 190; - yyn = 0; - xxs = 190; - yys = 325; - w = 20; - h = 75; + int xxn = 190; + int yyn = 0; + int xxs = 190; + int yys = 325; + int w = 20; + int h = 75; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(trackRouteColor); @@ -91,4 +85,19 @@ public void renderTile(Graphics2D g2, JComponent c) { renderVerticalAndDividers(g2, c); } + @Override + public void renderTileRoute(Graphics2D g2, JComponent c) { + Tile tile = (Tile) c; + Orientation incomingSide = tile.getIncomingSide(); + if (tile.isHorizontal() && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { + renderRouteVertical(g2, c); + } else if (tile.isHorizontal() && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { + renderRouteStraight(g2, c); + } else if (tile.isVertical() && (Orientation.WEST == incomingSide || Orientation.EAST == incomingSide)) { + renderRouteVertical(g2, c); + } else { + renderRouteStraight(g2, c); + } + } + } diff --git a/src/main/java/jcs/ui/layout/tiles/ui/CurvedUI.java b/src/main/java/jcs/ui/layout/tiles/ui/CurvedUI.java index e9dad0c4..6f176c44 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/CurvedUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/CurvedUI.java @@ -16,7 +16,6 @@ package jcs.ui.layout.tiles.ui; import java.awt.BasicStroke; -import java.awt.Color; import java.awt.Graphics2D; import javax.swing.JComponent; import javax.swing.plaf.ComponentUI; @@ -33,9 +32,6 @@ public static ComponentUI createUI(JComponent c) { @Override public void renderTile(Graphics2D g2, JComponent c) { - Tile tile = (Tile) c; - //Color trackColor = tile.getTrackColor(); - int[] xPoints = new int[]{400, 400, 170, 230}; int[] yPoints = new int[]{230, 170, 400, 400}; @@ -47,9 +43,6 @@ public void renderTile(Graphics2D g2, JComponent c) { @Override public void renderTileRoute(Graphics2D g2, JComponent c) { - Tile tile = (Tile) c; - //Color trackRouteColor = tile.getTrackRouteColor(); - int[] xPoints = new int[]{400, 400, 190, 210}; int[] yPoints = new int[]{210, 190, 400, 400}; diff --git a/src/main/java/jcs/ui/layout/tiles/ui/EndUI.java b/src/main/java/jcs/ui/layout/tiles/ui/EndUI.java index e49ec7ae..c79b3463 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/EndUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/EndUI.java @@ -32,9 +32,6 @@ public static ComponentUI createUI(JComponent c) { } protected void renderEnd(Graphics2D g2, JComponent c) { - Tile tile = (Tile) c; - //Color trackColor = tile.getTrackColor(); - int xx = 0; int yy = 175; int w = RENDER_GRID; diff --git a/src/main/java/jcs/ui/layout/tiles/ui/StraightUI.java b/src/main/java/jcs/ui/layout/tiles/ui/StraightUI.java index 31bb053f..712fc11f 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/StraightUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/StraightUI.java @@ -16,11 +16,9 @@ package jcs.ui.layout.tiles.ui; import java.awt.BasicStroke; -import java.awt.Color; import java.awt.Graphics2D; import javax.swing.JComponent; import javax.swing.plaf.ComponentUI; -import jcs.ui.layout.tiles.Tile; public class StraightUI extends TileUI { @@ -32,9 +30,6 @@ public static ComponentUI createUI(JComponent c) { } protected void renderStraight(Graphics2D g2, JComponent c) { - Tile tile = (Tile) c; - //Color trackColor = tile.getTrackColor(); - int xx = 0; int yy = 170; int w = RENDER_WIDTH; @@ -47,15 +42,12 @@ protected void renderStraight(Graphics2D g2, JComponent c) { } protected void renderRouteStraight(Graphics2D g2, JComponent c) { - Tile tile = (Tile) c; - int xx, yy, w, h; xx = 0; yy = 190; w = RENDER_WIDTH; h = 20; - //Color trackRouteColor = tile.getTrackRouteColor(); g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(trackRouteColor); diff --git a/src/main/java/jcs/ui/layout/tiles/ui/SwitchUI.java b/src/main/java/jcs/ui/layout/tiles/ui/SwitchUI.java index 6b4ae851..fd729988 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/SwitchUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/SwitchUI.java @@ -101,8 +101,6 @@ protected void renderRouteDiagonal(Graphics2D g2, Color color, JComponent c) { public void renderTile(Graphics2D g2, JComponent c) { Tile tile = (Tile) c; AccessoryValue accessoryValue = tile.getAccessoryValue(); - //Color trackColor = tile.getTrackColor(); - if (accessoryValue == null) { accessoryValue = AccessoryBean.AccessoryValue.OFF; } @@ -127,7 +125,6 @@ public void renderTile(Graphics2D g2, JComponent c) { public void renderTileRoute(Graphics2D g2, JComponent c) { Tile tile = (Tile) c; AccessoryValue routeValue = tile.getRouteValue(); - //Color trackRouteColor = tile.getTrackRouteColor(); if (routeValue == null) { routeValue = AccessoryBean.AccessoryValue.OFF; diff --git a/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java b/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java index 3d2f7176..9f30b6f4 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java @@ -37,8 +37,7 @@ import org.tinylog.Logger; /** - * - * @author fransjacobs + * The drawing functionality of a Tile. */ public abstract class TileUI extends ComponentUI { @@ -150,8 +149,6 @@ public void drawTile(Graphics2D g2d, JComponent c) { Tile tile = (Tile) c; TileModel model = ((Tile) c).getModel(); TileBean.Orientation tileOrientation = model.getTileOrienation(); - - //BufferedImage bf = new BufferedImage(tile.getRenderWidth(), tile.getRenderHeight(), BufferedImage.TYPE_INT_RGB); BufferedImage bf = createImage(); Graphics2D g2di = bf.createGraphics(); From 0f837227317d3c2a41353573c94a6ae3eed8a8b8 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Sat, 8 Feb 2025 17:08:28 +0100 Subject: [PATCH 16/70] More cleanup --- .../tiles/sandbox/AlphaButtonPolicy.java | 91 ---------- .../tiles/sandbox/BasicJogShuttleUI.java | 156 ------------------ .../ui/layout/tiles/sandbox/FocusExample.java | 86 ---------- .../tiles/sandbox/FocusTraversalExample.java | 38 ----- .../layout/tiles/sandbox/InvokeExample.java | 115 ------------- .../ui/layout/tiles/sandbox/JogShuttle.java | 154 ----------------- .../ui/layout/tiles/sandbox/JogShuttleUI.java | 11 -- .../ui/layout/tiles/sandbox/SimpleModel.java | 84 ---------- .../tiles/sandbox/SimpleModelInterface.java | 24 --- .../jcs/ui/layout/tiles/sandbox/Sketch.java | 85 ---------- 10 files changed, 844 deletions(-) delete mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/AlphaButtonPolicy.java delete mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/BasicJogShuttleUI.java delete mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/FocusExample.java delete mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/FocusTraversalExample.java delete mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/InvokeExample.java delete mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/JogShuttle.java delete mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/JogShuttleUI.java delete mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/SimpleModel.java delete mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/SimpleModelInterface.java delete mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/Sketch.java diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/AlphaButtonPolicy.java b/src/main/java/jcs/ui/layout/tiles/sandbox/AlphaButtonPolicy.java deleted file mode 100755 index 16e7832a..00000000 --- a/src/main/java/jcs/ui/layout/tiles/sandbox/AlphaButtonPolicy.java +++ /dev/null @@ -1,91 +0,0 @@ -// AlphaButtonPolicy.java -// A custom focus traversal policy that uses alphabetical ordering of button -// labels to determine "next" and "previous" buttons for keyboard traversal. -// -package jcs.ui.layout.tiles.sandbox; - -import java.awt.*; -import java.util.*; -import javax.swing.*; - -public class AlphaButtonPolicy extends FocusTraversalPolicy { - - private SortedMap getSortedButtons(Container focusCycleRoot) { - if (focusCycleRoot == null) { - throw new IllegalArgumentException("focusCycleRoot can't be null"); - } - SortedMap result = new TreeMap(); // Will sort all buttons by text. - sortRecursive(result, focusCycleRoot); - return result; - } - - private void sortRecursive(Map buttons, Container container) { - for (int i = 0; i < container.getComponentCount(); i++) { - Component c = container.getComponent(i); - if (c instanceof JButton) { // Found another button to sort. - buttons.put(((JButton) c).getText(), c); - } - if (c instanceof Container) { // Found a container to search. - sortRecursive(buttons, (Container) c); - } - } - } - - // The rest of the code implements the FocusTraversalPolicy interface. - public Component getFirstComponent(Container focusCycleRoot) { - SortedMap buttons = getSortedButtons(focusCycleRoot); - if (buttons.isEmpty()) { - return null; - } - return (Component) buttons.get(buttons.firstKey()); - } - - public Component getLastComponent(Container focusCycleRoot) { - SortedMap buttons = getSortedButtons(focusCycleRoot); - if (buttons.isEmpty()) { - return null; - } - return (Component) buttons.get(buttons.lastKey()); - } - - public Component getDefaultComponent(Container focusCycleRoot) { - return getFirstComponent(focusCycleRoot); - } - - public Component getComponentAfter(Container focusCycleRoot, - Component aComponent) { - if (!(aComponent instanceof JButton)) { - return null; - } - SortedMap buttons = getSortedButtons(focusCycleRoot); - // Find all buttons after the current one. - String nextName = ((JButton) aComponent).getText() + "\0"; - SortedMap nextButtons = buttons.tailMap(nextName); - if (nextButtons.isEmpty()) { // Wrapped back to beginning - if (!buttons.isEmpty()) { - return (Component) buttons.get(buttons.firstKey()); - } - return null; // Degenerate case of no buttons. - } - return (Component) nextButtons.get(nextButtons.firstKey()); - } - - public Component getComponentBefore(Container focusCycleRoot, - Component aComponent) { - if (!(aComponent instanceof JButton)) { - return null; - } - - SortedMap buttons = getSortedButtons(focusCycleRoot); - SortedMap prevButtons - = // Find all buttons before this one. - buttons.headMap(((JButton) aComponent).getText()); - if (prevButtons.isEmpty()) { // Wrapped back to end. - if (!buttons.isEmpty()) { - return (Component) buttons.get(buttons.lastKey()); - } - return null; // Degenerate case of no buttons. - } - return (Component) prevButtons.get(prevButtons.lastKey()); - } -} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/BasicJogShuttleUI.java b/src/main/java/jcs/ui/layout/tiles/sandbox/BasicJogShuttleUI.java deleted file mode 100755 index 77154263..00000000 --- a/src/main/java/jcs/ui/layout/tiles/sandbox/BasicJogShuttleUI.java +++ /dev/null @@ -1,156 +0,0 @@ -// BasicJogShuttleUI.java -// A UI class for our custom JogShuttle component. -// -package jcs.ui.layout.tiles.sandbox; - -import java.awt.*; -import java.awt.event.*; - -import javax.swing.*; -import javax.swing.plaf.*; - -public class BasicJogShuttleUI extends JogShuttleUI - implements MouseListener, MouseMotionListener { - - private static final int KNOB_DISPLACEMENT = 3; - private static final int FINGER_SLOT_DISPLACEMENT = 15; - - private double lastAngle; // Used to track mouse drags. - - public static ComponentUI createUI(JComponent c) { - return new BasicJogShuttleUI(); - } - - public void installUI(JComponent c) { - JogShuttle shuttle = (JogShuttle) c; - shuttle.addMouseListener(this); - shuttle.addMouseMotionListener(this); - } - - public void uninstallUI(JComponent c) { - JogShuttle shuttle = (JogShuttle) c; - shuttle.removeMouseListener(this); - shuttle.removeMouseMotionListener(this); - } - - public void paint(Graphics g, JComponent c) { - // We don't want to paint inside the insets or borders. - Insets insets = c.getInsets(); - g.translate(insets.left, insets.top); - int width = c.getWidth() - insets.left - insets.right; - int height = c.getHeight() - insets.top - insets.bottom; - - // Draw the outside circle. - g.setColor(c.getForeground()); - g.fillOval(0, 0, width, height); - - Insets d = ((JogShuttle) c).getDialInsets(); - int value = ((JogShuttle) c).getValue(); - int valuePerRevolution = ((JogShuttle) c).getValuePerRevolution(); - - // Draw the edge of the dial. - g.setColor(Color.darkGray); - g.fillOval(d.left, d.top, width - (d.right * 2), height - (d.bottom * 2)); - - // Draw the inside of the dial. - g.setColor(Color.gray); - g.fillOval(d.left + KNOB_DISPLACEMENT, - d.top + KNOB_DISPLACEMENT, - width - (d.right + d.left) - KNOB_DISPLACEMENT * 2, - height - (d.bottom + d.top) - KNOB_DISPLACEMENT * 2); - - // Draw the finger slot. - drawFingerSlot(g, c, value, width, height, valuePerRevolution, - FINGER_SLOT_DISPLACEMENT - 1, - (double) (width / 2) - d.right - FINGER_SLOT_DISPLACEMENT, - (double) (height / 2) - d.bottom - FINGER_SLOT_DISPLACEMENT); - - g.translate(-insets.left, -insets.top); - } - - private void drawFingerSlot(Graphics g, JComponent c, int value, - int width, int height, int valuePerRevolution, int size, - double xradius, double yradius) { - - int currentPosition = value % valuePerRevolution; - - // Obtain the current angle in radians. - double angle = ((double) currentPosition / valuePerRevolution) - * java.lang.Math.PI * 2; - - // Obtain the X and Y coordinates of the finger slot, with the - // minimum value at twelve o'clock. - angle -= (java.lang.Math.PI / 2); - int xPosition = (int) (xradius * java.lang.Math.sin(angle)); - int yPosition = (int) (yradius * java.lang.Math.cos(angle)); - xPosition = (width / 2) - xPosition; - yPosition = (height / 2) + yPosition; - - // Draw the finger slot with a crescent shadow on the top left. - g.setColor(Color.darkGray); - g.fillOval(xPosition - (size / 2), yPosition - (size / 2), size, size); - g.setColor(Color.lightGray); - g.fillOval(xPosition - (size / 2) + 1, yPosition - (size / 2) + 1, - size - 1, size - 1); - - } - - // Figure out angle at which a mouse event occurred with respect to the - // center of the component for intuitive dial dragging. - protected double calculateAngle(MouseEvent e) { - int x = e.getX() - ((JComponent) e.getSource()).getWidth() / 2; - int y = -e.getY() + ((JComponent) e.getSource()).getHeight() / 2; - if (x == 0) { // Handle case where math would blow up. - if (y == 0) { - return lastAngle; // Can't tell... - } - if (y > 0) { - return Math.PI / 2; - } - return -Math.PI / 2; - } - return Math.atan((double) y / (double) x); - } - - public void mousePressed(MouseEvent e) { - lastAngle = calculateAngle(e); - } - - public void mouseReleased(MouseEvent e) { - } - - public void mouseClicked(MouseEvent e) { - } - - public void mouseEntered(MouseEvent e) { - } - - public void mouseExited(MouseEvent e) { - } - - // Figure out the change in angle over which the user has dragged, - // expressed as a fraction of a revolution. - public double angleDragged(MouseEvent e) { - double newAngle = calculateAngle(e); - double change = (lastAngle - newAngle) / Math.PI; - if (Math.abs(change) > 0.5) { // Handle crossing origin. - if (change < 0.0) { - change += 1.0; - } else { - change -= 1.0; - } - } - - lastAngle = newAngle; - return change; - } - - public void mouseDragged(MouseEvent e) { - JogShuttle theShuttle = (JogShuttle) e.getComponent(); - theShuttle.setValue(theShuttle.getValue() - + (int) (angleDragged(e) * theShuttle.getValuePerRevolution())); - } - - public void mouseMoved(MouseEvent e) { - } -} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/FocusExample.java b/src/main/java/jcs/ui/layout/tiles/sandbox/FocusExample.java deleted file mode 100755 index e27171f1..00000000 --- a/src/main/java/jcs/ui/layout/tiles/sandbox/FocusExample.java +++ /dev/null @@ -1,86 +0,0 @@ -// FocusExample.java -// An example of focus traversal using the keyboard to navigate through a -// small set of buttons. -// -package jcs.ui.layout.tiles.sandbox; - -import java.awt.*; -import java.awt.event.*; - -import javax.swing.*; - -public class FocusExample extends JFrame { - - public FocusExample() { - - super("Focus Example"); - setDefaultCloseOperation(EXIT_ON_CLOSE); - MyPanel mypanel = new MyPanel(); - - JButton button1 = new JButton("One"); - JButton button2 = new JButton("Two"); - JButton button3 = new JButton("Three"); - JButton button4 = new JButton("Four"); - JButton button5 = new MyButton("Five*"); - JButton button6 = new MyButton("Six*"); - JButton button7 = new JButton("Seven"); - - mypanel.add(button2); - mypanel.add(button3); - - JInternalFrame frame1 = new JInternalFrame("Internal Frame 1", - true, true, true, true); - - frame1.setBackground(Color.lightGray); - frame1.getContentPane().setLayout(new GridLayout(2, 3)); - frame1.setSize(300, 200); - - frame1.getContentPane().add(button1); - frame1.getContentPane().add(mypanel); - frame1.getContentPane().add(button4); - frame1.getContentPane().add(button5); - frame1.getContentPane().add(button6); - frame1.getContentPane().add(button7); - - JDesktopPane desktop = new JDesktopPane(); - desktop.add(frame1, new Integer(1)); - desktop.setOpaque(true); - - // Now set up the user interface window. - Container contentPane = getContentPane(); - contentPane.add(desktop, BorderLayout.CENTER); - setSize(new Dimension(400, 300)); - frame1.setVisible(true); - setVisible(true); - } - - public static void main(String[] args) { - new FocusExample(); - } - - class MyButton extends JButton { - - public MyButton(String s) { - super(s); - } - - public boolean isFocusable() { - return false; - } - } - - class MyPanel extends JPanel { - - public MyPanel() { - super(true); - java.util.Set upKeys = new java.util.HashSet(1); - upKeys.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_UP, 0)); - setFocusTraversalKeys(KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, - upKeys); - } - - public boolean isFocusCycleRoot() { - return true; - } - } -} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/FocusTraversalExample.java b/src/main/java/jcs/ui/layout/tiles/sandbox/FocusTraversalExample.java deleted file mode 100755 index 39fdbec1..00000000 --- a/src/main/java/jcs/ui/layout/tiles/sandbox/FocusTraversalExample.java +++ /dev/null @@ -1,38 +0,0 @@ -//FocusTraversalExample.java -// Similar to the FocusExample, this class uses the custom AlphaButtonPolicy -// focus traversal policy to navigate another small set of buttons. -// -package jcs.ui.layout.tiles.sandbox; - -import java.awt.*; -import javax.swing.*; - -public class FocusTraversalExample extends JPanel { - - public FocusTraversalExample() { - setLayout(new GridLayout(6, 1)); - JButton button1 = new JButton("Texas"); - JButton button2 = new JButton("Vermont"); - JButton button3 = new JButton("Florida"); - JButton button4 = new JButton("Alabama"); - JButton button5 = new JButton("Minnesota"); - JButton button6 = new JButton("California"); - - setBackground(Color.lightGray); - add(button1); - add(button2); - add(button3); - add(button4); - add(button5); - add(button6); - } - - public static void main(String[] args) { - JFrame frame = new JFrame("Alphabetized Button Focus Traversal"); - frame.setFocusTraversalPolicy(new AlphaButtonPolicy()); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - frame.setContentPane(new FocusTraversalExample()); - frame.setSize(400, 300); - frame.setVisible(true); - } -} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/InvokeExample.java b/src/main/java/jcs/ui/layout/tiles/sandbox/InvokeExample.java deleted file mode 100755 index 2f4815c2..00000000 --- a/src/main/java/jcs/ui/layout/tiles/sandbox/InvokeExample.java +++ /dev/null @@ -1,115 +0,0 @@ -// InvokeExample.java -// This class demonstrates several examples of how to handle long-running -// tasks (such as querying a remote resource). Some of the examples are -// good, some are not! -// - -package jcs.ui.layout.tiles.sandbox; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.*; - -public class InvokeExample { - private static JButton good = new JButton("Good"); - private static JButton bad = new JButton("Bad"); - private static JButton bad2 = new JButton("Bad2"); - private static JLabel resultLabel = new JLabel("Ready", JLabel.CENTER); - - public static void main(String[] args) { - JFrame f = new JFrame(); - f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - - // Layout . . . - JPanel p = new JPanel(); - p.setOpaque(true); - p.setLayout(new FlowLayout()); - p.add(good); - p.add(bad); - p.add(bad2); - - Container c = f.getContentPane(); - c.setLayout(new BorderLayout()); - c.add(p, BorderLayout.CENTER); - c.add(resultLabel, BorderLayout.SOUTH); - - // Listeners - good.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent ev) { - resultLabel.setText("Working . . ."); - setEnabled(false); - - // We're going to do something that takes a long time, so we - // spin off a thread and update the display when we're done. - Thread worker = new Thread() { - public void run() { - // Something that takes a long time . . . in real life, this - // might be a DB query, remote method invocation, etc. - try { - Thread.sleep(5000); - } - catch (InterruptedException ex) {} - - // Report the result using invokeLater(). - SwingUtilities.invokeLater(new Runnable() { - public void run() { - resultLabel.setText("Ready"); - setEnabled(true); - } - }); - } - }; - - worker.start(); // So we don't hold up the dispatch thread. - } - }); - - bad.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent ev) { - resultLabel.setText("Working . . ."); - setEnabled(false); - - // We're going to do the same thing, but not in a separate thread. - try { - Thread.sleep(5000); // Dispatch thread is starving! - } - catch (InterruptedException ex) {} - - // Report the result. - resultLabel.setText("Ready"); - setEnabled(true); - } - }); - - bad2.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent ev) { - resultLabel.setText("Working . . . "); - setEnabled(false); - - // The wrong way to use invokeLater(). The runnable() shouldn't - // starve the dispatch thread. - SwingUtilities.invokeLater(new Runnable() { - public void run() { - try { - Thread.sleep(5000); // Dispatch thread is starving! - } - catch (InterruptedException ex) {} - - resultLabel.setText("Ready"); - setEnabled(true); - } - }); - } - }); - - f.setSize(300, 100); - f.setVisible(true); - } - - // Allows us to turn the buttons on or off while we work. - static void setEnabled(boolean b) { - good.setEnabled(b); - bad.setEnabled(b); - bad2.setEnabled(b); - } -} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/JogShuttle.java b/src/main/java/jcs/ui/layout/tiles/sandbox/JogShuttle.java deleted file mode 100755 index d39366fb..00000000 --- a/src/main/java/jcs/ui/layout/tiles/sandbox/JogShuttle.java +++ /dev/null @@ -1,154 +0,0 @@ -// JogShuttle.java -// A custom jog shuttle component. (Some VCRs have such a thing for doing -// variable speed fast-forward and fast-reverse.) An example of using the -// JogShuttle can be found in Sketch.java. -// -package jcs.ui.layout.tiles.sandbox; - -import java.awt.*; - -import javax.swing.*; -import javax.swing.event.*; - -public class JogShuttle extends JComponent implements ChangeListener { - - private BoundedRangeModel model; - - // The dialInsets property tells how far the dial is inset - // from the sunken border. - private Insets dialInsets = new Insets(3, 3, 3, 3); - - // The valuePerRevolution property tells how many units the dial - // takes to make a complete revolution. - private int valuePerRevolution; - - // Constructors - public JogShuttle() { - init(new DefaultBoundedRangeModel()); - } - - public JogShuttle(BoundedRangeModel m) { - init(m); - } - - public JogShuttle(int min, int max, int value) { - init(new DefaultBoundedRangeModel(value, 1, min, max)); - } - - protected void init(BoundedRangeModel m) { - setModel(m); - valuePerRevolution = m.getMaximum() - m.getMinimum(); - setMinimumSize(new Dimension(80, 80)); - setPreferredSize(new Dimension(80, 80)); - updateUI(); - } - - public void setUI(JogShuttleUI ui) { - super.setUI(ui); - } - - public void updateUI() { - setUI((JogShuttleUI) UIManager.getUI(this)); - invalidate(); - } - - public String getUIClassID() { - return JogShuttleUI.UI_CLASS_ID; - } - - public void setModel(BoundedRangeModel m) { - BoundedRangeModel old = model; - if (old != null) { - old.removeChangeListener(this); - } - - if (m == null) { - model = new DefaultBoundedRangeModel(); - } else { - model = m; - } - model.addChangeListener(this); - - firePropertyChange("model", old, model); - } - - public BoundedRangeModel getModel() { - return model; - } - - // Methods - public void resetToMinimum() { - model.setValue(model.getMinimum()); - } - - public void resetToMaximum() { - model.setValue(model.getMaximum()); - } - - public void stateChanged(ChangeEvent e) { - repaint(); - } - - // Accessors and mutators - public int getMinimum() { - return model.getMinimum(); - } - - public void setMinimum(int m) { - int old = getMinimum(); - if (m != old) { - model.setMinimum(m); - firePropertyChange("minimum", old, m); - } - } - - public int getMaximum() { - return model.getMaximum(); - } - - public void setMaximum(int m) { - int old = getMaximum(); - if (m != old) { - model.setMaximum(m); - firePropertyChange("maximum", old, m); - } - } - - public int getValue() { - return model.getValue(); - } - - public void setValue(int v) { - int old = getValue(); - if (v != old) { - model.setValue(v); - firePropertyChange("value", old, v); - } - } - - // Display-specific properties - public int getValuePerRevolution() { - return valuePerRevolution; - } - - public void setValuePerRevolution(int v) { - int old = getValuePerRevolution(); - if (v != old) { - valuePerRevolution = v; - firePropertyChange("valuePerRevolution", old, v); - } - repaint(); - } - - public void setDialInsets(Insets i) { - dialInsets = i; - } - - public void setDialInsets(int top, int left, int bottom, int right) { - dialInsets = new Insets(top, left, bottom, right); - } - - public Insets getDialInsets() { - return dialInsets; - } -} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/JogShuttleUI.java b/src/main/java/jcs/ui/layout/tiles/sandbox/JogShuttleUI.java deleted file mode 100755 index 790e0ae7..00000000 --- a/src/main/java/jcs/ui/layout/tiles/sandbox/JogShuttleUI.java +++ /dev/null @@ -1,11 +0,0 @@ -// JogShuttleUI.java -// Fill out the proper UIClassID information for our JogShuttle. -// - -package jcs.ui.layout.tiles.sandbox; - -import javax.swing.plaf.*; - -public abstract class JogShuttleUI extends ComponentUI { - public static final String UI_CLASS_ID = "JogShuttleUI"; -} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/SimpleModel.java b/src/main/java/jcs/ui/layout/tiles/sandbox/SimpleModel.java deleted file mode 100755 index bcbbbea9..00000000 --- a/src/main/java/jcs/ui/layout/tiles/sandbox/SimpleModel.java +++ /dev/null @@ -1,84 +0,0 @@ -// SimpleModel.java -// An example of a custom data model that could be used in any MVC -// scenario. -// -package jcs.ui.layout.tiles.sandbox; - -import javax.swing.event.*; - -public class SimpleModel implements SimpleModelInterface { - - protected transient ChangeEvent changeEvent = null; - protected EventListenerList listenerList = new EventListenerList(); - - private int value = 0; - private boolean activated = false; - - public SimpleModel() { - } - - public SimpleModel(int v) { - value = v; - } - - public SimpleModel(boolean b) { - activated = b; - } - - public SimpleModel(int v, boolean b) { - value = v; - activated = b; - } - - public int getValue() { - return value; - } - - public synchronized void setValue(int v) { - if (v != value) { - value = v; - fireChange(); - } - } - - public boolean isActivated() { - return activated; - } - - public synchronized void setActivated(boolean b) { - if (b != activated) { - activated = b; - fireChange(); - } - } - - public void addChangeListener(ChangeListener l) { - listenerList.add(ChangeListener.class, l); - } - - public void removeChangeListener(ChangeListener l) { - listenerList.remove(ChangeListener.class, l); - } - - public ChangeListener[] getChangeListeners() { - return (ChangeListener[]) listenerList.getListeners(ChangeListener.class); - } - - protected void fireChange() { - Object[] listeners = listenerList.getListenerList(); - for (int i = listeners.length - 2; i >= 0; i -= 2) { - if (listeners[i] == ChangeListener.class) { - if (changeEvent == null) { - changeEvent = new ChangeEvent(this); - } - ((ChangeListener) listeners[i + 1]).stateChanged(changeEvent); - } - } - } - - public String toString() { - String modelString = "value=" + getValue() + ", " - + "activated=" + isActivated(); - return getClass().getName() + "[" + modelString + "]"; - } -} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/SimpleModelInterface.java b/src/main/java/jcs/ui/layout/tiles/sandbox/SimpleModelInterface.java deleted file mode 100755 index 1d24c7f0..00000000 --- a/src/main/java/jcs/ui/layout/tiles/sandbox/SimpleModelInterface.java +++ /dev/null @@ -1,24 +0,0 @@ -// SimpleModelInteface.java -// An example of a data model interface that could be used in any MVC -// scenario. This interface is implemented in the SimpleModel class. -// -package jcs.ui.layout.tiles.sandbox; - -import javax.swing.event.*; - -public interface SimpleModelInterface { - - public int getValue(); - - public void setValue(int v); - - public boolean isActivated(); - - public void setActivated(boolean b); - - public void addChangeListener(ChangeListener l); - - public void removeChangeListener(ChangeListener l); - - public ChangeListener[] getChangeListeners(); -} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/Sketch.java b/src/main/java/jcs/ui/layout/tiles/sandbox/Sketch.java deleted file mode 100755 index a8d4e2f7..00000000 --- a/src/main/java/jcs/ui/layout/tiles/sandbox/Sketch.java +++ /dev/null @@ -1,85 +0,0 @@ -// Sketch.java -// A sketching application with two dials: one for horizontal movement, one -// for vertical movement. The dials are instances of the JogShuttle class. -// -package jcs.ui.layout.tiles.sandbox; - -import java.awt.*; -import java.awt.event.*; -import java.beans.*; - -import javax.swing.*; -import javax.swing.border.*; - -public class Sketch extends JPanel - implements PropertyChangeListener, ActionListener { - - JogShuttle shuttle1; - JogShuttle shuttle2; - JPanel board; - JButton clear; - - int lastX, lastY; // Keep track of the last point we drew. - - public Sketch() { - super(true); - - setLayout(new BorderLayout()); - board = new JPanel(true); - board.setPreferredSize(new Dimension(300, 300)); - board.setBorder(new LineBorder(Color.black, 5)); - - clear = new JButton("Clear Drawing Area"); - clear.addActionListener(this); - - shuttle1 = new JogShuttle(0, 300, 150); - lastX = shuttle1.getValue(); - shuttle2 = new JogShuttle(0, 300, 150); - lastY = shuttle2.getValue(); - - shuttle1.setValuePerRevolution(100); - shuttle2.setValuePerRevolution(100); - - shuttle1.addPropertyChangeListener(this); - shuttle2.addPropertyChangeListener(this); - - shuttle1.setBorder(new BevelBorder(BevelBorder.RAISED)); - shuttle2.setBorder(new BevelBorder(BevelBorder.RAISED)); - - add(board, BorderLayout.NORTH); - add(shuttle1, BorderLayout.WEST); - add(clear, BorderLayout.CENTER); - add(shuttle2, BorderLayout.EAST); - } - - public void propertyChange(PropertyChangeEvent e) { - if (e.getPropertyName() == "value") { - Graphics g = board.getGraphics(); - g.setColor(getForeground()); - g.drawLine(lastX, lastY, - shuttle1.getValue(), shuttle2.getValue()); - lastX = shuttle1.getValue(); - lastY = shuttle2.getValue(); - } - } - - public void actionPerformed(ActionEvent e) { - // The button must have been pressed. - Insets insets = board.getInsets(); - Graphics g = board.getGraphics(); - g.setColor(board.getBackground()); - g.fillRect(insets.left, insets.top, - board.getWidth() - insets.left - insets.right, - board.getHeight() - insets.top - insets.bottom); - } - - public static void main(String[] args) { - UIManager.put(JogShuttleUI.UI_CLASS_ID, "BasicJogShuttleUI"); - Sketch s = new Sketch(); - JFrame frame = new JFrame("Sample Sketch Application"); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - frame.setContentPane(s); - frame.pack(); - frame.setVisible(true); - } -} From 2f2ca21b8b767eaf60a5ee14170d80d2e9b60101 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Sun, 9 Feb 2025 14:56:32 +0100 Subject: [PATCH 17/70] The Sensor dispaly is now working again. Clicking on a Sensor will trigger the Sensor actions --- .../commandStation/JCSCommandStationImpl.java | 2 + .../esu/ecos/EsuEcosCommandStationImpl.java | 14 +- .../commandStation/events/AccessoryEvent.java | 4 +- .../commandStation/events/JCSActionEvent.java | 30 ++ .../commandStation/events/SensorEvent.java | 22 +- src/main/java/jcs/entities/SensorBean.java | 26 +- src/main/java/jcs/ui/layout/LayoutCanvas.form | 234 +++++++++++- src/main/java/jcs/ui/layout/LayoutCanvas.java | 54 ++- .../jcs/ui/layout/dialogs/SensorDialog.java | 2 +- src/main/java/jcs/ui/layout/tiles/Sensor.java | 1 - src/main/java/jcs/ui/layout/tiles/Tile.java | 335 +++++++++--------- .../layout/tiles/TileActionEventHandler.java | 96 +++++ .../java/jcs/ui/layout/tiles/TileCache.java | 162 ++------- .../java/jcs/ui/layout/tiles/TileFactory.java | 321 ++++++++++++++++- .../java/jcs/ui/layout/tiles/ui/SensorUI.java | 67 +++- .../java/jcs/ui/layout/tiles/ui/TileUI.java | 19 + 16 files changed, 1039 insertions(+), 350 deletions(-) create mode 100644 src/main/java/jcs/commandStation/events/JCSActionEvent.java create mode 100644 src/main/java/jcs/ui/layout/tiles/TileActionEventHandler.java diff --git a/src/main/java/jcs/commandStation/JCSCommandStationImpl.java b/src/main/java/jcs/commandStation/JCSCommandStationImpl.java index d0b0aa2e..73048cef 100755 --- a/src/main/java/jcs/commandStation/JCSCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/JCSCommandStationImpl.java @@ -671,11 +671,13 @@ private class SensorChangeEventListener implements SensorEventListener { @Override public void onSensorChange(SensorEvent event) { SensorBean sb = event.getSensorBean(); + boolean newValue = event.isActive(); SensorBean dbsb = PersistenceFactory.getService().getSensor(sb.getDeviceId(), sb.getContactId()); if (dbsb != null) { sb.setId(dbsb.getId()); sb.setName(dbsb.getName()); + sb.setActive(newValue); PersistenceFactory.getService().persist(sb); } diff --git a/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java b/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java index 53ec814a..b1b98540 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java @@ -236,7 +236,8 @@ private void initFeedbackManager() { for (int i = 0; i < feedbackManager.getSize(); i++) { int moduleId = i + FeedbackManager.S88_OFFSET; - reply = connection.sendMessage(EcosMessageFactory.getFeedbackModuleInfo(moduleId)); + //reply = + connection.sendMessage(EcosMessageFactory.getFeedbackModuleInfo(moduleId)); //TODO: Start of day... //feedbackManager.update(reply); @@ -575,8 +576,12 @@ public List getFeedbackModules() { @Override public void fireSensorEventListeners(SensorEvent sensorEvent) { Logger.trace("SensorEvent: " + sensorEvent); - for (SensorEventListener listener : sensorEventListeners) { - listener.onSensorChange(sensorEvent); + if (sensorEventListeners != null && !sensorEventListeners.isEmpty()) { + for (SensorEventListener listener : sensorEventListeners) { + //if (listener != null) { + listener.onSensorChange(sensorEvent); + //} + } } } @@ -703,7 +708,8 @@ public void run() { } } -////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////// + /// @param a // For testing only public static void main(String[] a) { diff --git a/src/main/java/jcs/commandStation/events/AccessoryEvent.java b/src/main/java/jcs/commandStation/events/AccessoryEvent.java index 6da6b9b2..ab2c04d9 100755 --- a/src/main/java/jcs/commandStation/events/AccessoryEvent.java +++ b/src/main/java/jcs/commandStation/events/AccessoryEvent.java @@ -15,12 +15,11 @@ */ package jcs.commandStation.events; -import java.io.Serializable; import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.AccessoryValue; import jcs.entities.AccessoryBean.SignalValue; -public class AccessoryEvent implements Serializable { +public class AccessoryEvent implements JCSActionEvent { private final AccessoryBean accessoryBean; @@ -51,6 +50,7 @@ public AccessoryValue getValue() { return this.accessoryBean.getAccessoryValue(); } + @Override public String getId() { return this.accessoryBean.getId(); } diff --git a/src/main/java/jcs/commandStation/events/JCSActionEvent.java b/src/main/java/jcs/commandStation/events/JCSActionEvent.java new file mode 100644 index 00000000..49a278bd --- /dev/null +++ b/src/main/java/jcs/commandStation/events/JCSActionEvent.java @@ -0,0 +1,30 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.commandStation.events; + +/** + * + * An Action is required on the implemented delegate Event Object. + */ +public interface JCSActionEvent { + + /** + * + * @return the id of the Object which requires an action + */ + String getId(); + +} diff --git a/src/main/java/jcs/commandStation/events/SensorEvent.java b/src/main/java/jcs/commandStation/events/SensorEvent.java index 2021fcfb..b498b2f8 100755 --- a/src/main/java/jcs/commandStation/events/SensorEvent.java +++ b/src/main/java/jcs/commandStation/events/SensorEvent.java @@ -18,21 +18,27 @@ import jcs.entities.SensorBean; /** - * - * @author Frans Jacobs + * Value change happened on a Sensor. */ -public class SensorEvent { +public class SensorEvent implements JCSActionEvent { private final SensorBean sensorBean; + private final boolean newValue; public SensorEvent(SensorBean sensorBean) { + this(sensorBean, sensorBean.isActive()); + } + + public SensorEvent(SensorBean sensorBean, boolean newValue) { this.sensorBean = sensorBean; + this.newValue = newValue; } public SensorBean getSensorBean() { return sensorBean; } + @Override public String getId() { if (sensorBean.getId() != null) { return sensorBean.getId(); @@ -51,21 +57,21 @@ public String getId() { } public Integer getDeviceId() { - return this.sensorBean.getDeviceId(); + return sensorBean.getDeviceId(); } public Integer getContactId() { - return this.sensorBean.getContactId(); + return sensorBean.getContactId(); } public boolean isChanged() { - boolean active = sensorBean.isActive(); + //boolean active = sensorBean.isActive(); boolean prevActive = sensorBean.isPreviousActive(); - return active != prevActive; + return newValue != prevActive; } public boolean isActive() { - return sensorBean.isActive(); + return newValue; //sensorBean.isActive(); } @Override diff --git a/src/main/java/jcs/entities/SensorBean.java b/src/main/java/jcs/entities/SensorBean.java index 74a76cf2..4f341f8f 100755 --- a/src/main/java/jcs/entities/SensorBean.java +++ b/src/main/java/jcs/entities/SensorBean.java @@ -147,7 +147,7 @@ public void toggle() { status = 0; } previousStatus = status; - Date lastChanged = this.lastUpdated; + Date lastChanged = lastUpdated; if (lastChanged == null) { lastChanged = new Date(); } @@ -177,8 +177,14 @@ public Date getLastUpdated() { return lastUpdated; } - public void setLastUpdated(Date lastUpdated) { - this.lastUpdated = lastUpdated; + public void setLastUpdated(Date updatedOn) { + Date prevUpdated = lastUpdated; + lastUpdated = updatedOn; + + if (lastUpdated != null && prevUpdated != null) { + Long m = (updatedOn.getTime() - prevUpdated.getTime()) / 10; + this.millis = m.intValue(); + } } @Transient @@ -191,22 +197,28 @@ public boolean isActive() { } public void setActive(boolean active) { - this.status = active ? 1 : 0; + previousStatus = status; + status = active ? 1 : 0; } public void setPreviousActive(boolean active) { - this.previousStatus = active ? 1 : 0; + previousStatus = active ? 1 : 0; } @Transient public boolean isPreviousActive() { - if (this.previousStatus != null) { - return this.previousStatus > 0; + if (previousStatus != null) { + return previousStatus > 0; } else { return false; } } + @Transient + public boolean hasChanged() { + return !status.equals(previousStatus); + } + @Override public int hashCode() { int hash = 3; diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.form b/src/main/java/jcs/ui/layout/LayoutCanvas.form index 3a7b262c..884eba14 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.form +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.form @@ -1 +1,233 @@ -

\ No newline at end of file + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.java b/src/main/java/jcs/ui/layout/LayoutCanvas.java index bc89dd21..860c36fd 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.java +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.java @@ -38,14 +38,11 @@ import javax.swing.JPopupMenu; import javax.swing.SwingUtilities; import jcs.JCS; -import jcs.commandStation.FeedbackController; import jcs.commandStation.autopilot.AutoPilot; -import jcs.commandStation.events.SensorEvent; import jcs.entities.AccessoryBean; import jcs.entities.BlockBean; import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; -import jcs.entities.SensorBean; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; @@ -61,6 +58,7 @@ import static jcs.entities.TileBean.TileType.STRAIGHT_DIR; import static jcs.entities.TileBean.TileType.SWITCH; import jcs.persistence.PersistenceFactory; +import static jcs.ui.layout.LayoutCanvas.Mode.CONTROL; import jcs.ui.layout.dialogs.BlockControlDialog; import jcs.ui.layout.dialogs.BlockDialog; import jcs.ui.layout.dialogs.SensorDialog; @@ -139,6 +137,10 @@ private void postInit() { routesDialog = new RoutesDialog(getParentFrame(), false, this, this.readonly); } + public boolean isReadonly() { + return readonly; + } + @Override public void paint(Graphics g) { //long started = System.currentTimeMillis(); @@ -256,7 +258,7 @@ void loadLayoutInBackground() { } private void loadTiles() { - List tiles = TileCache.loadTiles(); + List tiles = TileCache.loadTiles(readonly); removeAll(); selectedTile = null; @@ -284,7 +286,8 @@ private void mousePressedAction(MouseEvent evt) { //Clear any previous selection Tile previousSelected = selectedTile; selectedTile = TileCache.findTile(snapPoint); - if (selectedTile != null) { + //Only show selected tile in edit mode + if (selectedTile != null && CONTROL != mode) { selectedTile.setSelected(true); } @@ -460,7 +463,7 @@ private void executeControlActionForTile(Tile tile, Point p) { case CURVED -> { } case SENSOR -> { - this.executor.execute(() -> toggleSensor((Sensor) tile)); + //this.executor.execute(() -> toggleSensor((Sensor) tile)); } case BLOCK -> { Logger.trace("Show BlockDialog for " + tile.getId()); @@ -505,24 +508,22 @@ private void toggleSignal(Signal signal) { } } - private void toggleSensor(Sensor sensor) { - SensorBean sb = sensor.getSensorBean(); - if (sb != null) { - sb.toggle(); - sensor.setActive((sb.getStatus() == 1)); - Logger.trace("id: " + sb.getId() + " state " + sb.getStatus()); - SensorEvent sensorEvent = new SensorEvent(sb); - fireFeedbackEvent(sensorEvent); - } - } - - private void fireFeedbackEvent(SensorEvent sensorEvent) { - List acl = JCS.getJcsCommandStation().getFeedbackControllers(); - for (FeedbackController fbc : acl) { - fbc.fireSensorEventListeners(sensorEvent); - } - } - +// private void toggleSensor(Sensor sensor) { +// SensorBean sb = sensor.getSensorBean(); +// if (sb != null) { +// sb.toggle(); +// sensor.setActive((sb.getStatus() == 1)); +// Logger.trace("id: " + sb.getId() + " state " + sb.getStatus()); +// SensorEvent sensorEvent = new SensorEvent(sb); +// fireFeedbackEvent(sensorEvent); +// } +// } +// private void fireFeedbackEvent(SensorEvent sensorEvent) { +// List acl = JCS.getJcsCommandStation().getFeedbackControllers(); +// for (FeedbackController fbc : acl) { +// fbc.fireSensorEventListeners(sensorEvent); +// } +// } private void editSelectedTileProperties() { //the first tile should be the selected one boolean showProperties = false; @@ -940,7 +941,6 @@ private void horizontalMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_hor Logger.trace(this.orientation + ", " + evt.getModifiers() + ", " + evt.paramString()); if (this.mouseLocation != null && evt.getModifiers() == ActionEvent.MOUSE_EVENT_MASK) { - //addTile(this.mouseLocation); this.mouseLocation = null; } }//GEN-LAST:event_horizontalMIActionPerformed @@ -949,7 +949,6 @@ private void verticalMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_verti Logger.trace(this.orientation + ", " + evt.getModifiers() + ", " + evt.paramString()); if (this.mouseLocation != null && evt.getModifiers() == ActionEvent.MOUSE_EVENT_MASK) { - //addTile(this.mouseLocation); this.mouseLocation = null; } }//GEN-LAST:event_verticalMIActionPerformed @@ -958,7 +957,6 @@ private void rightMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_rightMIA Logger.trace(this.orientation + ", " + evt.getModifiers() + ", " + evt.paramString()); if (this.mouseLocation != null && evt.getModifiers() == ActionEvent.MOUSE_EVENT_MASK) { - //addTile(this.mouseLocation); this.mouseLocation = null; } }//GEN-LAST:event_rightMIActionPerformed @@ -967,7 +965,6 @@ private void leftMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_leftMIAct Logger.trace(this.orientation + ", " + evt.getModifiers() + ", " + evt.paramString()); if (this.mouseLocation != null && evt.getModifiers() == ActionEvent.MOUSE_EVENT_MASK) { - //addTile(this.mouseLocation); this.mouseLocation = null; } }//GEN-LAST:event_leftMIActionPerformed @@ -1129,6 +1126,7 @@ private void resetGhostMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_res if (this.selectedTile != null) { Block block = (Block) selectedTile; BlockBean.BlockState currentState = block.getBlockState(); + if (BlockBean.BlockState.GHOST == currentState) { if (block.getBlockBean().getLocomotiveId() != null) { block.setBlockState(BlockBean.BlockState.OCCUPIED); diff --git a/src/main/java/jcs/ui/layout/dialogs/SensorDialog.java b/src/main/java/jcs/ui/layout/dialogs/SensorDialog.java index baf222ca..0d7f2c20 100644 --- a/src/main/java/jcs/ui/layout/dialogs/SensorDialog.java +++ b/src/main/java/jcs/ui/layout/dialogs/SensorDialog.java @@ -69,7 +69,7 @@ private void postInit() { usedSensorIds.add(tb.getSensorId()); } } - //Filter the unused turnouts + //Filter the unused sensors List filtered = new ArrayList<>(); for (SensorBean sb : sensors) { if (!usedSensorIds.contains(sb.getId())) { diff --git a/src/main/java/jcs/ui/layout/tiles/Sensor.java b/src/main/java/jcs/ui/layout/tiles/Sensor.java index 25ecf42b..baedc593 100644 --- a/src/main/java/jcs/ui/layout/tiles/Sensor.java +++ b/src/main/java/jcs/ui/layout/tiles/Sensor.java @@ -65,7 +65,6 @@ public void onSensorChange(SensorEvent event) { SensorBean sensor = event.getSensorBean(); if (sensor.equalsDeviceIdAndContactId(getSensorBean())) { setActive(sensor.isActive()); - repaint(); } } diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java index e36a3df1..144fdb56 100755 --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -78,13 +78,13 @@ public abstract class Tile extends JComponent { // implements ChangeListener public static final int GRID = 20; public static final int DEFAULT_WIDTH = GRID * 2; public static final int DEFAULT_HEIGHT = GRID * 2; - + public static final Color DEFAULT_BACKGROUND_COLOR = Color.white; public static final Color DEFAULT_TRACK_COLOR = Color.lightGray; public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.darkGray; public static final Color DEFAULT_SELECTED_COLOR = Color.yellow; public static final Color DEFAULT_WARN_COLOR = Color.red; - + public static final String MODEL_CHANGED_PROPERTY = "model"; // public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled"; @@ -92,73 +92,73 @@ public abstract class Tile extends JComponent { // implements ChangeListener * The data model that determines the Tile state. */ protected TileModel model = null; - + protected String id; protected Integer tileX; protected Integer tileY; - + protected Direction tileDirection; - + protected TileType tileType; protected String accessoryId; protected String sensorId; - + protected AccessoryValue accessoryValue; protected AccessoryValue routeValue; - + protected SignalType signalType; protected AccessoryBean.SignalValue signalValue; - + protected TileBean tileBean; protected AccessoryBean accessoryBean; protected SensorBean sensorBean; protected BlockBean blockBean; - + protected List neighbours; - + protected int renderOffsetX = 0; protected int renderOffsetY = 0; - + protected boolean drawName = true; - + protected BufferedImage tileImage; - + protected PropertyChangeListener propertyChangeListener; - + protected ChangeListener changeListener = null; protected ActionListener actionListener = null; - + protected transient ChangeEvent changeEvent; private Handler handler; - + protected Tile(TileType tileType, Orientation orientation, Point center, int width, int height) { this(tileType, orientation, Direction.CENTER, center.x, center.y, width, height); } - + protected Tile(TileType tileType, Orientation orientation, int x, int y, int width, int height) { this(tileType, orientation, Direction.CENTER, x, y, width, height); } - + protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { this(tileType, orientation, direction, x, y, width, height, null, null); } - + protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height, Color backgroundColor, Color selectedColor) { this.tileType = tileType; this.tileDirection = direction; this.tileX = x; this.tileY = y; - + setLayout(null); Dimension d = new Dimension(width, height); setSize(d); setPreferredSize(d); } - + protected Tile(TileBean tileBean) { this(tileBean, tileWidth(tileBean.getOrientation(), tileBean.getTileType()), tileHeight(tileBean.getOrientation(), tileBean.getTileType())); } - + protected Tile(TileBean tileBean, int width, int height) { this.tileBean = tileBean; this.id = tileBean.getId(); @@ -166,66 +166,66 @@ protected Tile(TileBean tileBean, int width, int height) { this.tileDirection = tileBean.getDirection(); this.tileX = tileBean.getX(); this.tileY = tileBean.getY(); - + this.accessoryId = tileBean.getAccessoryId(); this.accessoryBean = tileBean.getAccessoryBean(); this.signalType = tileBean.getSignalType(); - + this.sensorId = tileBean.getSensorId(); this.sensorBean = tileBean.getSensorBean(); this.blockBean = tileBean.getBlockBean(); - + setLayout(null); Dimension d = new Dimension(width, height); setSize(d); setPreferredSize(d); } - + @Override public String getUIClassID() { return TileUI.UI_CLASS_ID; } - + @Override public TileUI getUI() { return (TileUI) ui; } - + public void setUI(TileUI ui) { super.setUI(ui); } - + public TileModel getModel() { return model; } - + public void setModel(TileModel newModel) { TileModel oldModel = getModel(); - + if (oldModel != null) { oldModel.removeChangeListener(changeListener); oldModel.removeActionListener(actionListener); changeListener = null; actionListener = null; } - + model = newModel; - + if (newModel != null) { changeListener = createChangeListener(); actionListener = createActionListener(); - + newModel.addChangeListener(changeListener); newModel.addActionListener(actionListener); } - + firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel); if (newModel != oldModel) { revalidate(); repaint(); } } - + protected static int tileWidth(Orientation orientation, TileType tileType) { if (Orientation.EAST == orientation || Orientation.WEST == orientation) { if (null == tileType) { @@ -244,7 +244,7 @@ protected static int tileWidth(Orientation orientation, TileType tileType) { return DEFAULT_WIDTH; } } - + protected static int tileHeight(Orientation orientation, TileType tileType) { if (Orientation.EAST == orientation || Orientation.WEST == orientation) { return DEFAULT_HEIGHT; @@ -263,7 +263,7 @@ protected static int tileHeight(Orientation orientation, TileType tileType) { } } } - + protected void populateModel() { if (this.blockBean != null) { this.model.setBlockState(this.blockBean.getBlockState()); @@ -272,7 +272,7 @@ protected void populateModel() { this.model.setLogicalDirection(LocomotiveBean.Direction.get(this.blockBean.getLogicalDirection())); } } - + public TileBean getTileBean() { if (tileBean == null) { tileBean = new TileBean(); @@ -281,7 +281,19 @@ public TileBean getTileBean() { tileBean.setY(this.tileY); tileBean.setTileType(this.tileType); tileBean.setTileOrientation(this.model.getTileOrienation().getOrientation()); - + + tileBean.setTileDirection(this.tileDirection.getDirection()); + tileBean.setSignalType(this.signalType); + tileBean.setAccessoryId(this.accessoryId); + tileBean.setSensorId(this.sensorId); + tileBean.setAccessoryBean(this.accessoryBean); + tileBean.setSensorBean(this.sensorBean); + tileBean.setBlockBean(this.blockBean); + } else { + //update + tileBean.setX(this.tileX); + tileBean.setY(this.tileY); + tileBean.setTileOrientation(this.model.getTileOrienation().getOrientation()); tileBean.setTileDirection(this.tileDirection.getDirection()); tileBean.setSignalType(this.signalType); tileBean.setAccessoryId(this.accessoryId); @@ -300,23 +312,23 @@ public TileBean getTileBean() { public boolean isSelected() { return model.isSelected(); } - + public void setSelected(boolean b) { model.setSelected(b); } - + public String getId() { return id; } - + public void setId(String id) { this.id = id; } - + public SignalType getSignalType() { return signalType; } - + public void setSignalType(SignalType signalType) { this.signalType = signalType; } @@ -344,7 +356,7 @@ public Integer getTileY() { public Point getCenter() { return new Point(this.tileX, this.tileY); } - + public void setCenter(Point center) { tileX = center.x; tileY = center.y; @@ -360,56 +372,59 @@ public void setCenter(Point center) { public Orientation getOrientation() { return model.getTileOrienation(); } - + public void setOrientation(Orientation orientation) { model.setTileOrienation(orientation); if (tileBean != null) { tileBean.setOrientation(orientation); } } - + public Direction getDirection() { return tileDirection; } - + public void setDirection(Direction direction) { this.tileDirection = direction; if (tileBean != null) { tileBean.setDirection(direction); } } - + public String getAccessoryId() { return accessoryId; } - + public void setAccessoryId(String accessoryId) { this.accessoryId = accessoryId; if (tileBean != null) { tileBean.setAccessoryId(accessoryId); } } - + public String getSensorId() { return sensorId; } - + public void setSensorId(String sensorId) { this.sensorId = sensorId; } - + public boolean isActive() { return model.isSensorActive(); } - + public void setActive(boolean active) { model.setSensorActive(active); + if (this.sensorBean != null) { + this.sensorBean.setActive(active); + } } - + public BlockState getBlockState() { return model.getBlockState(); } - + public void setBlockState(BlockState blockState) { if (blockBean != null) { blockBean.setBlockState(blockState); @@ -418,60 +433,60 @@ public void setBlockState(BlockState blockState) { } model.setBlockState(blockState); } - + public String getDepartureSuffix() { return model.getDepartureSuffix(); } - + public void setDepartureSuffix(String suffix) { if (blockBean != null) { blockBean.setDepartureSuffix(suffix); } model.setDepartureSuffix(suffix); } - + public boolean isReverseArrival() { return model.isReverseArrival(); } - + public void setReverseArrival(boolean reverseArrival) { if (blockBean != null) { blockBean.setReverseArrival(reverseArrival); } model.setReverseArrival(reverseArrival); } - + public LocomotiveBean.Direction getLogicalDirection() { return model.getLogicalDirection(); } - + public void setLogicalDirection(LocomotiveBean.Direction logicalDirection) { if (blockBean != null) { blockBean.setLogicalDirection(logicalDirection.getDirection()); } model.setLogicalDirection(logicalDirection); } - + public LocomotiveBean getLocomotive() { return model.getLocomotive(); } - + public void setLocomotive(LocomotiveBean locomotive) { if (blockBean != null) { blockBean.setLocomotive(locomotive); model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (model.getBlockState() == BlockState.OCCUPIED || model.getBlockState() == BlockState.INBOUND || model.getBlockState() == BlockState.OUTBOUND)); } - + model.setLocomotive(locomotive); } - + public AccessoryBean getAccessoryBean() { return accessoryBean; } - + public void setAccessoryBean(AccessoryBean accessoryBean) { this.accessoryBean = accessoryBean; - + if (accessoryBean != null) { accessoryId = accessoryBean.getId(); signalValue = accessoryBean.getSignalValue(); @@ -482,7 +497,7 @@ public void setAccessoryBean(AccessoryBean accessoryBean) { signalValue = AccessoryBean.SignalValue.OFF; } } - + public AccessoryValue getAccessoryValue() { if (this.accessoryValue == null) { return AccessoryValue.OFF; @@ -490,12 +505,12 @@ public AccessoryValue getAccessoryValue() { return accessoryValue; } } - + public void setAccessoryValue(AccessoryValue value) { this.accessoryValue = value; repaint(); } - + public AccessoryValue getRouteValue() { if (routeValue == null) { return AccessoryValue.OFF; @@ -503,93 +518,93 @@ public AccessoryValue getRouteValue() { return routeValue; } } - + public void setRouteValue(AccessoryValue value) { this.routeValue = value; repaint(); } - + public AccessoryBean.SignalValue getSignalValue() { return signalValue; } - + public void setSignalValue(AccessoryBean.SignalValue signalValue) { this.signalValue = signalValue; repaint(); } - + public SensorBean getSensorBean() { return sensorBean; } - + public void setSensorBean(SensorBean sensorBean) { this.sensorBean = sensorBean; } - + public BlockBean getBlockBean() { return blockBean; } - + public void setBlockBean(BlockBean blockBean) { this.blockBean = blockBean; } - + public int getRenderOffsetX() { return renderOffsetX; } - + public void setRenderOffsetX(int renderOffsetX) { this.renderOffsetX = renderOffsetX; } - + public int getRenderOffsetY() { return renderOffsetY; } - + public void setRenderOffsetY(int renderOffsetY) { this.renderOffsetY = renderOffsetY; } - + public TileBean.TileType getTileType() { return this.tileType; } - + public final void setTileType(TileType tileType) { this.tileType = tileType; } - + public void setTrackColor(Color trackColor) { if (getUI() != null) { getUI().setTrackColor(trackColor); } } - + public void setTrackRouteColor(Color trackRouteColor) { if (getUI() != null) { getUI().setTrackRouteColor(trackRouteColor); } } - + public Color getSelectedColor() { return model.getSelectedColor(); } - + public void setSelectedColor(Color selectedColor) { model.setSelectedColor(selectedColor); } - + public Orientation getIncomingSide() { return model.getIncomingSide(); } - + public void setIncomingSide(Orientation incomingSide) { model.setIncomingSide(incomingSide); } - + public boolean isShowRoute() { return model.isShowRoute(); } - + public void setShowRoute(boolean drawRoute) { this.model.setShowRoute(drawRoute); } @@ -602,17 +617,17 @@ public void setShowRoute(boolean drawRoute) { * */ public abstract Map getNeighborPoints(); - + public abstract Map getEdgePoints(); - + Set getAltPoints(Point center) { return Collections.EMPTY_SET; } - + public Set getAllPoints() { return getAllPoints(getCenter()); } - + Set getAllPoints(Point center) { Set aps = new HashSet<>(); aps.add(center); @@ -638,7 +653,7 @@ public Orientation rotate() { } return model.getTileOrienation(); } - + public void flipHorizontal() { Orientation tileOrientation = model.getTileOrienation(); if (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) { @@ -646,7 +661,7 @@ public void flipHorizontal() { rotate(); } } - + public void flipVertical() { Orientation tileOrientation = model.getTileOrienation(); if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { @@ -654,41 +669,41 @@ public void flipVertical() { rotate(); } } - + @Override public void move(int newX, int newY) { Point cs = LayoutUtil.snapToGrid(newX, newY); setCenter(cs); } - + public static BufferedImage flipHorizontally(BufferedImage source) { BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); - + AffineTransform flip = AffineTransform.getScaleInstance(1, -1); flip.translate(0, -source.getHeight()); AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); - + op.filter(source, output); - + return output; } - + public static BufferedImage flipVertically(BufferedImage source) { BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); - + AffineTransform flip = AffineTransform.getScaleInstance(-1, 1); flip.translate(-source.getWidth(), 0); AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); - + op.filter(source, output); - + return output; } - + public Set getAltPoints() { return Collections.EMPTY_SET; } - + public int getCenterX() { if (tileX > 0) { return this.tileX; @@ -696,7 +711,7 @@ public int getCenterX() { return GRID; } } - + public int getCenterY() { if (tileY > 0) { return this.tileY; @@ -704,19 +719,19 @@ public int getCenterY() { return GRID; } } - + public boolean isDrawName() { return drawName; } - + public void setDrawName(boolean drawName) { this.drawName = drawName; } - + public boolean isScaleImage() { return model.isScaleImage(); } - + public void setScaleImage(boolean scaleImage) { Dimension d; if (scaleImage) { @@ -724,23 +739,23 @@ public void setScaleImage(boolean scaleImage) { } else { int renderWidth = getUI().getRenderWidth(); int renderHeight = getUI().getRenderHeight(); - + d = new Dimension(renderWidth, renderHeight); } - + setSize(d); setPreferredSize(d); model.setScaleImage(scaleImage); } - + public boolean isDrawCenterPoint() { return model.isShowCenter(); } - + public void setDrawCenterPoint(boolean drawCenterPoint) { model.setShowCenter(drawCenterPoint); } - + @Override public String toString() { return this.getClass().getSimpleName() @@ -754,7 +769,7 @@ public String toString() { + xyToString() + "}"; } - + public String xyToString() { return "(" + this.tileX + "," + this.tileY + ")"; } @@ -778,15 +793,15 @@ public boolean isVertical() { Orientation tileOrientation = model.getTileOrienation(); return (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) && TileType.CURVED != tileType; } - + public boolean isJunction() { return TileType.SWITCH == tileType || TileType.CROSS == tileType; } - + public boolean isBlock() { return TileType.BLOCK == tileType; } - + public boolean isDirectional() { return TileType.STRAIGHT_DIR == tileType; } @@ -799,52 +814,52 @@ public boolean isDirectional() { public boolean isDiagonal() { return TileType.CURVED == tileType; } - + public boolean isCrossing() { return TileType.CROSSING == tileType; } - + public List getNeighbours() { return neighbours; } - + public void setNeighbours(List neighbours) { this.neighbours = neighbours; } - + public String getIdSuffix(Tile other) { return ""; } - + public Map getNeighborOrientations() { Map edgeOrientations = new HashMap<>(); - + Map neighborPoints = getNeighborPoints(); - + for (Orientation o : Orientation.values()) { edgeOrientations.put(neighborPoints.get(o), o); } return edgeOrientations; } - + public Map getEdgeOrientations() { Map edgeOrientations = new HashMap<>(); - + Map edgeConnections = getEdgePoints(); - + for (Orientation o : Orientation.values()) { edgeOrientations.put(edgeConnections.get(o), o); } return edgeOrientations; } - + public boolean isAdjacent(Tile other) { boolean adjacent = false; - + if (other != null) { Collection thisEdgePoints = getEdgePoints().values(); Collection otherEdgePoints = other.getEdgePoints().values(); - + for (Point p : thisEdgePoints) { adjacent = otherEdgePoints.contains(p); if (adjacent) { @@ -852,7 +867,7 @@ public boolean isAdjacent(Tile other) { } } } - + return adjacent; } @@ -866,40 +881,40 @@ public boolean isAdjacent(Tile other) { public boolean isArrowDirection(Tile other) { return true; } - + public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { return AccessoryValue.OFF; } - + protected ChangeListener createChangeListener() { return getHandler(); } - + protected ActionListener createActionListener() { return getHandler(); } - + private Handler getHandler() { if (handler == null) { handler = new Handler(); } return handler; } - + class Handler implements ActionListener, ChangeListener, Serializable { - + @Override public void stateChanged(ChangeEvent e) { fireStateChanged(); repaint(); } - + @Override public void actionPerformed(ActionEvent event) { fireActionPerformed(event); } } - + protected void fireStateChanged() { Object[] listeners = listenerList.getListenerList(); //reverse order @@ -913,7 +928,7 @@ protected void fireStateChanged() { } } } - + protected void fireActionPerformed(ActionEvent event) { Object[] listeners = listenerList.getListenerList(); ActionEvent e = null; @@ -932,26 +947,26 @@ protected void fireActionPerformed(ActionEvent event) { } } } - + public Rectangle getTileBounds() { if (model.isScaleImage()) { return new Rectangle(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); } else { int renderWidth = getUI().getRenderWidth(); int renderHeight = getUI().getRenderHeight(); - + return new Rectangle(tileX - renderWidth / 2, tileY - renderHeight / 2, renderWidth, renderHeight); } } - - @Override - protected void paintComponent(Graphics g) { - if (Logger.isTraceEnabled()) { - long started = System.currentTimeMillis(); - super.paintComponent(g); - long now = System.currentTimeMillis(); - Logger.trace(id + " Duration: " + (now - started) + " ms. Cp: " + xyToString() + " O: " + model.getTileOrienation()); - } - } - + +// @Override +// protected void paintComponent(Graphics g) { +// if (Logger.isTraceEnabled()) { +// long started = System.currentTimeMillis(); +// super.paintComponent(g); +// long now = System.currentTimeMillis(); +// Logger.trace(id + " Duration: " + (now - started) + " ms. Cp: " + xyToString() + " O: " + model.getTileOrienation()); +// } +// } + } diff --git a/src/main/java/jcs/ui/layout/tiles/TileActionEventHandler.java b/src/main/java/jcs/ui/layout/tiles/TileActionEventHandler.java new file mode 100644 index 00000000..bc36f141 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/TileActionEventHandler.java @@ -0,0 +1,96 @@ +/* + * Copyright 2025 fransjacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles; + +import java.util.List; +import java.util.concurrent.ConcurrentLinkedQueue; +import jcs.JCS; +import jcs.commandStation.FeedbackController; +import jcs.commandStation.events.AccessoryEvent; +import jcs.commandStation.events.JCSActionEvent; +import jcs.commandStation.events.SensorEvent; +import org.tinylog.Logger; + +/** + * + * @author fransjacobs + */ +class TileActionEventHandler extends Thread { + + private boolean stop = false; + private boolean quit = true; + + private final ConcurrentLinkedQueue eventQueue; + + TileActionEventHandler(ConcurrentLinkedQueue eventQueue) { + this.eventQueue = eventQueue; + } + + void quit() { + this.quit = true; + } + + boolean isRunning() { + return !this.quit; + } + + boolean isFinished() { + return this.stop; + } + + @Override + public void run() { + this.quit = false; + this.setName("TILE-ACTION-EVENT-HANDLER"); + + Logger.trace("Tile ActionEventHandler Started..."); + + while (isRunning()) { + try { + JCSActionEvent event = eventQueue.poll(); + if (event != null) { + if (event instanceof SensorEvent sensorEvent) { + fireSensorEvent(sensorEvent); + } + if (event instanceof AccessoryEvent) { + + } + + } else { + //lets sleep for a while + synchronized (this) { + wait(10000); + } + } + + } catch (InterruptedException ex) { + Logger.error(ex); + } + } + + stop = true; + Logger.trace("Tile ActionEventHandler Stopped..."); + } + + private void fireSensorEvent(SensorEvent sensorEvent) { + //Logger.trace("Firing Sensor Action " + sensorEvent.getId() + " -> " + sensorEvent.isActive()); + List acl = JCS.getJcsCommandStation().getFeedbackControllers(); + for (FeedbackController fbc : acl) { + fbc.fireSensorEventListeners(sensorEvent); + } + } + +} diff --git a/src/main/java/jcs/ui/layout/tiles/TileCache.java b/src/main/java/jcs/ui/layout/tiles/TileCache.java index a2f9d7c5..528b637c 100644 --- a/src/main/java/jcs/ui/layout/tiles/TileCache.java +++ b/src/main/java/jcs/ui/layout/tiles/TileCache.java @@ -20,10 +20,15 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentLinkedQueue; import java.util.stream.Collectors; +import jcs.JCS; +import jcs.commandStation.FeedbackController; import jcs.entities.TileBean; import jcs.persistence.PersistenceFactory; import org.tinylog.Logger; +import jcs.commandStation.events.JCSActionEvent; +import jcs.commandStation.events.SensorEvent; /** * Factory object to create Tiles and cache tiles @@ -32,55 +37,26 @@ */ public class TileCache { - //private static boolean showValues; static final Map tiles = new HashMap<>(); static final Map tileAltPoints = new HashMap<>(); static final Map points = new HashMap<>(); + private static final ConcurrentLinkedQueue eventsQueue = new ConcurrentLinkedQueue(); + + private static final TileActionEventHandler actionEventQueueHandler = new TileActionEventHandler(eventsQueue); + + static { + actionEventQueueHandler.start(); + } + private TileCache() { } -// @Deprecated -// public static void setShowValues(boolean showValues) { -// TileCache.showValues = showValues; -// -// for (Tile tile : tiles.values()) { -// TileType tileType = tile.getTileType(); -// switch (tileType) { -// case SWITCH -> { -// if (showValues && ((Switch) tile).getTileBean().getAccessoryBean() != null) { -// tile.setAccessoryValue(tile.getTileBean().getAccessoryBean().getAccessoryValue()); -// } else { -// tile.setAccessoryValue(AccessoryValue.OFF); -// } -// } -// case CROSS -> { -// if (showValues && ((Cross) tile).getTileBean().getAccessoryBean() != null) { -// tile.setAccessoryValue(tile.getTileBean().getAccessoryBean().getAccessoryValue()); -// } else { -// tile.setAccessoryValue(AccessoryValue.OFF); -// } -// } -// case SIGNAL -> { -// if (showValues && ((Signal) tile).getTileBean().getAccessoryBean() != null) { -// tile.setSignalValue(tile.getTileBean().getAccessoryBean().getSignalValue()); -// } else { -// tile.setSignalValue(SignalValue.OFF); -// } -// } -// case SENSOR -> { -// if (showValues && ((Sensor) tile).getTileBean().getSensorBean() != null) { -// tile.setActive(tile.getTileBean().getSensorBean().isActive()); -// } else { -// tile.setActive(false); -// } -// } -// case BLOCK -> { -// } -// } -// } -// } public static List loadTiles() { + return loadTiles(false); + } + + public static List loadTiles(boolean showvalues) { tileAltPoints.clear(); points.clear(); tiles.clear(); @@ -88,7 +64,7 @@ public static List loadTiles() { List tileBeans = PersistenceFactory.getService().getTileBeans(); for (TileBean tb : tileBeans) { - Tile tile = TileFactory.createTile(tb, false); + Tile tile = TileFactory.createTile(tb, showvalues); tiles.put(tile.getCenter(), tile); points.put(tile.getId(), tile.getCenter()); //Alternative point(s) to be able to find all points @@ -98,6 +74,8 @@ public static List loadTiles() { tileAltPoints.put(ap, tile); } } + //Extra actions for some tile of tiles + } Logger.trace("Loaded " + tiles.size() + " Tiles..."); @@ -225,67 +203,6 @@ public static void moveTo(Tile tile, Point p) { } } -// @Deprecated -// public static boolean checkTileOccupation(Tile tile) { -// Set tilePoints = tile.getAllPoints(); -// for (Point p : tilePoints) { -// if (tiles.containsKey(p) || tileAltPoints.containsKey(p)) { -// //The is a match, check if it is an other tile -// Tile mt = findTile(p); -// if (tile.getId().equals(mt.getId())) { -// //same tile continue -// } else { -// //Other tile so really occupied -// return true; -// } -// } -// } -// return false; -// } -// @Deprecated -// public static boolean containsPoint(Set points) { -// for (Point p : points) { -// return tiles.containsKey(p) || tileAltPoints.containsKey(p); -// } -// return false; -// } -// public static boolean containsPoint(Point point) { -// return tiles.containsKey(point) || tileAltPoints.containsKey(point); -// } -// @Deprecated -// public static Point checkAvailable(Point newPoint, Orientation orientation) { -// if (tiles.containsKey(newPoint)) { -// Tile et = tiles.get(newPoint); -// Logger.trace("@ " + newPoint + " is allready occcupied by: " + et + "..."); -// //Search for the nearest avalaible free point -// //first get the Center point of the tile which is occuping this slot -// // show warning! -// Point ecp = et.getCenter(); -// -// int w = et.getWidth(); -// int h = et.getHeight(); -// -// Point np; -// np = switch (orientation) { -// case EAST -> -// new Point(ecp.x + w, ecp.y); -// case WEST -> -// new Point(newPoint.x - w, ecp.y); -// case SOUTH -> -// new Point(ecp.x, newPoint.y + h); -// default -> -// new Point(ecp.x, newPoint.y - h); -// }; -// -// Logger.trace("Alternative CP: " + np); -// // recursive check -// return checkAvailable(np, orientation); -// } else { -// Logger.trace("@ " + newPoint + " is not yet used..."); -// -// return newPoint; -// } -// } public static Tile rotateTile(Tile tile) { if (!tiles.containsKey(tile.getCenter())) { Logger.warn("Tile " + tile.getId() + " NOT in cache!"); @@ -341,36 +258,11 @@ private static Tile flipTile(Tile tile, boolean horizontal) { return tile; } -// @Deprecated -// public static void addTileEventListener(TileEventListener listener) { -// String key = listener.getId(); -// //tileEventListeners.put(key, listener); -// } -// @Deprecated -// public static void removeTileEventListener(Tile tile) { -// if (tile instanceof TileEventListener tileEventListener) { -// removeTileEventListener(tileEventListener); -// } -// } -// static void removeTileEventListener(TileEventListener listener) { -// String key = listener.getId(); -// //tileEventListeners.remove(key, listener); -// } -// @Deprecated -// public static void fireTileEventListener(TileEvent tileEvent) { -//// String key = tileEvent.getTileId(); -//// TileEventListener listener = tileEventListeners.get(key); -//// if (listener != null) { -//// listener.onTileChange(tileEvent); -//// Logger.trace("Fire listener on tile " + key); -//// } else { -//// //Logger.trace("Tile " + key + " not available"); -//// } -// } -// @Deprecated -// public static void fireAllTileEventListeners(TileEvent tileEvent) { -//// for (TileEventListener listener : tileEventListeners.values()) { -//// listener.onTileChange(tileEvent); -//// } -// } + public static void enqueTileAction(JCSActionEvent jcsEvent) { + eventsQueue.offer(jcsEvent); + synchronized (TileCache.actionEventQueueHandler) { + actionEventQueueHandler.notifyAll(); + } + } + } diff --git a/src/main/java/jcs/ui/layout/tiles/TileFactory.java b/src/main/java/jcs/ui/layout/tiles/TileFactory.java index 5b0439c2..0e6c6b0d 100755 --- a/src/main/java/jcs/ui/layout/tiles/TileFactory.java +++ b/src/main/java/jcs/ui/layout/tiles/TileFactory.java @@ -1 +1,320 @@ -/* * Copyright 2023 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.Point; import java.util.LinkedList; import java.util.List; import jcs.JCS; import jcs.commandStation.events.AccessoryEventListener; import jcs.commandStation.events.SensorEventListener; import jcs.entities.AccessoryBean; import jcs.entities.SensorBean; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.TileType.BLOCK; import static jcs.entities.TileBean.TileType.CROSS; import static jcs.entities.TileBean.TileType.CROSSING; import static jcs.entities.TileBean.TileType.CURVED; import static jcs.entities.TileBean.TileType.END; import static jcs.entities.TileBean.TileType.SENSOR; import static jcs.entities.TileBean.TileType.SIGNAL; import static jcs.entities.TileBean.TileType.STRAIGHT; import static jcs.entities.TileBean.TileType.STRAIGHT_DIR; import static jcs.entities.TileBean.TileType.SWITCH; import org.tinylog.Logger; /** * Factory object to create Tiles and cache tiles * * @author frans */ public class TileFactory { // Keep the records of the used id sequence number private static int straightIdSeq; private static int crossingIdSeq; private static int curvedIdSeq; private static int switchIdSeq; private static int crossIdSeq; private static int signalIdSeq; private static int sensorIdSeq; private static int blockIdSeq; private static int straightDirectionIdSeq; private static int endIdSeq; private TileFactory() { } private static int nextIdSeq(String id) { String idnr = id.substring(3); int idSeq = Integer.parseInt(idnr); return idSeq; } private static String nextTileId(TileBean.TileType tileType) { switch (tileType) { case STRAIGHT -> { straightIdSeq++; return "st-" + straightIdSeq; } case CROSSING -> { crossingIdSeq++; return "cr-" + crossingIdSeq; } case CURVED -> { curvedIdSeq++; return "ct-" + curvedIdSeq; } case SWITCH -> { switchIdSeq++; return "sw-" + switchIdSeq; } case CROSS -> { crossIdSeq++; return "cs-" + crossIdSeq; } case SIGNAL -> { signalIdSeq++; return "si-" + signalIdSeq; } case SENSOR -> { sensorIdSeq++; return "se-" + sensorIdSeq; } case BLOCK -> { blockIdSeq++; return "bk-" + blockIdSeq; } case STRAIGHT_DIR -> { straightDirectionIdSeq++; return "sd-" + straightDirectionIdSeq; } case END -> { endIdSeq++; return "et-" + endIdSeq; } default -> { Logger.warn("Unknown Tile Type " + tileType); return null; } } } private static int maxIdSeq(int currentId, int newId) { if (currentId < newId) { return newId; } else { return currentId; } } public static Tile createTile(String tileId) { TileBean tileBean = JCS.getPersistenceService().getTileBean(tileId); return createTile(tileBean); } public static Tile createTile(TileBean tileBean) { return createTile(tileBean, false); } public static Tile createTile(TileBean tileBean, boolean showValues) { if (tileBean == null) { return null; } TileBean.TileType tileType = tileBean.getTileType(); Tile tile = null; switch (tileType) { case STRAIGHT -> { tile = new Straight(tileBean); straightIdSeq = maxIdSeq(straightIdSeq, nextIdSeq(tileBean.getId())); } case CROSSING -> { tile = new Crossing(tileBean); crossingIdSeq = maxIdSeq(crossingIdSeq, nextIdSeq(tileBean.getId())); } case CURVED -> { tile = new Curved(tileBean); curvedIdSeq = maxIdSeq(curvedIdSeq, nextIdSeq(tileBean.getId())); } case SWITCH -> { tile = new Switch(tileBean); tile.setAccessoryBean(tileBean.getAccessoryBean()); switchIdSeq = maxIdSeq(switchIdSeq, nextIdSeq(tileBean.getId())); if (showValues && tileBean.getAccessoryBean() != null) { tile.setAccessoryValue((tileBean.getAccessoryBean()).getAccessoryValue()); } JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); } case CROSS -> { tile = new Cross(tileBean); tile.setAccessoryBean(tileBean.getAccessoryBean()); crossIdSeq = maxIdSeq(crossIdSeq, nextIdSeq(tileBean.getId())); if (showValues && tileBean.getAccessoryBean() != null) { tile.setAccessoryValue((tileBean.getAccessoryBean()).getAccessoryValue()); } JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); } case SIGNAL -> { tile = new Signal(tileBean); tile.setAccessoryBean(tileBean.getAccessoryBean()); signalIdSeq = maxIdSeq(signalIdSeq, nextIdSeq(tileBean.getId())); if (showValues && tileBean.getAccessoryBean() != null) { ((Signal) tile).setSignalValue(((AccessoryBean) tileBean.getAccessoryBean()).getSignalValue()); } JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); } case SENSOR -> { tile = new Sensor(tileBean); tile.setSensorBean(tileBean.getSensorBean()); sensorIdSeq = maxIdSeq(sensorIdSeq, nextIdSeq(tileBean.getId())); if (showValues && tileBean.getSensorBean() != null) { ((Sensor) tile).setActive(((SensorBean) tileBean.getSensorBean()).isActive()); } JCS.getJcsCommandStation().addSensorEventListener((SensorEventListener) tile); } case BLOCK -> { tile = new Block(tileBean); tile.setBlockBean(tileBean.getBlockBean()); blockIdSeq = maxIdSeq(blockIdSeq, nextIdSeq(tileBean.getId())); } case STRAIGHT_DIR -> { tile = new StraightDirection(tileBean); straightDirectionIdSeq = maxIdSeq(straightDirectionIdSeq, nextIdSeq(tileBean.getId())); } case END -> { tile = new End(tileBean); endIdSeq = maxIdSeq(endIdSeq, nextIdSeq(tileBean.getId())); } default -> Logger.warn("Unknown Tile Type " + tileType); } return (Tile) tile; } public static void rollback(Tile tile) { switch (tile.tileType) { case STRAIGHT -> { straightIdSeq--; } case CROSSING -> { crossingIdSeq--; } case CURVED -> { curvedIdSeq--; } case SWITCH -> { switchIdSeq--; } case CROSS -> { crossIdSeq--; } case SIGNAL -> { signalIdSeq--; } case SENSOR -> { sensorIdSeq--; } case BLOCK -> { blockIdSeq--; } case STRAIGHT_DIR -> { straightDirectionIdSeq--; } case END -> { endIdSeq--; } } } /** * @param tileType type of type to create * @param orientation whether the orientation of the Tile is EAST, WEST, NORTH or SOUTH * @param x the tile center X * @param y the tile center Y * @return a Tile object */ public static Tile createTile(TileBean.TileType tileType, Orientation orientation, int x, int y) { return createTile(tileType, orientation, Direction.CENTER, x, y); } /** * @param tileType type of type to create * @param orientation whether the orientation of the Tile is EAST, WEST, NORTH or SOUTH * @param direction direction plays a role with Turnout tiles whether it goes to the Left or Right * @param x the tile center X * @param y the tile center Y * @return a Tile object */ public static Tile createTile(TileBean.TileType tileType, Orientation orientation, Direction direction, int x, int y) { return createTile(tileType, orientation, direction, new Point(x, y)); } public static Tile createTile(TileBean.TileType tileType, Orientation orientation, Direction direction, Point center) { Tile tile = null; switch (tileType) { case STRAIGHT -> { tile = new Straight(orientation, center); } case CROSSING -> { tile = new Crossing(orientation, center); } case CURVED -> tile = new Curved(orientation, center); case SWITCH -> tile = new Switch(orientation, direction, center); case CROSS -> tile = new Cross(orientation, direction, center); case SIGNAL -> tile = new Signal(orientation, center); case SENSOR -> tile = new Sensor(orientation, center); case BLOCK -> tile = new Block(orientation, center); case STRAIGHT_DIR -> tile = new StraightDirection(orientation, center); case END -> tile = new End(orientation, center); default -> Logger.warn("Unknown Tile Type " + tileType); } if (tile != null) { tile.setId(nextTileId(tileType)); } return (Tile) tile; } public static List toTiles(List tileBeans, boolean drawOutline, boolean showValues) { List tileList = new LinkedList<>(); for (TileBean tileBean : tileBeans) { Tile tile = createTile(tileBean, showValues); tileList.add(tile); } return tileList; } } \ No newline at end of file +/* + * Copyright 2023 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles; + +import java.awt.Point; +import java.util.LinkedList; +import java.util.List; +import jcs.JCS; +import jcs.commandStation.events.AccessoryEventListener; +import jcs.commandStation.events.SensorEventListener; +import jcs.entities.AccessoryBean; +import jcs.entities.SensorBean; +import jcs.entities.TileBean; +import jcs.entities.TileBean.Direction; +import jcs.entities.TileBean.Orientation; +import static jcs.entities.TileBean.TileType.BLOCK; +import static jcs.entities.TileBean.TileType.CROSS; +import static jcs.entities.TileBean.TileType.CROSSING; +import static jcs.entities.TileBean.TileType.CURVED; +import static jcs.entities.TileBean.TileType.END; +import static jcs.entities.TileBean.TileType.SENSOR; +import static jcs.entities.TileBean.TileType.SIGNAL; +import static jcs.entities.TileBean.TileType.STRAIGHT; +import static jcs.entities.TileBean.TileType.STRAIGHT_DIR; +import static jcs.entities.TileBean.TileType.SWITCH; +import org.tinylog.Logger; + +/** + * Factory object to create Tiles and cache tiles + * + * @author frans + */ +public class TileFactory { + + // Keep the records of the used id sequence number + private static int straightIdSeq; + private static int crossingIdSeq; + private static int curvedIdSeq; + private static int switchIdSeq; + private static int crossIdSeq; + private static int signalIdSeq; + private static int sensorIdSeq; + private static int blockIdSeq; + private static int straightDirectionIdSeq; + private static int endIdSeq; + + private TileFactory() { + } + + private static int nextIdSeq(String id) { + String idnr = id.substring(3); + int idSeq = Integer.parseInt(idnr); + return idSeq; + } + + private static String nextTileId(TileBean.TileType tileType) { + switch (tileType) { + case STRAIGHT -> { + straightIdSeq++; + return "st-" + straightIdSeq; + } + case CROSSING -> { + crossingIdSeq++; + return "cr-" + crossingIdSeq; + } + case CURVED -> { + curvedIdSeq++; + return "ct-" + curvedIdSeq; + } + case SWITCH -> { + switchIdSeq++; + return "sw-" + switchIdSeq; + } + case CROSS -> { + crossIdSeq++; + return "cs-" + crossIdSeq; + } + case SIGNAL -> { + signalIdSeq++; + return "si-" + signalIdSeq; + } + case SENSOR -> { + sensorIdSeq++; + return "se-" + sensorIdSeq; + } + case BLOCK -> { + blockIdSeq++; + return "bk-" + blockIdSeq; + } + case STRAIGHT_DIR -> { + straightDirectionIdSeq++; + return "sd-" + straightDirectionIdSeq; + } + case END -> { + endIdSeq++; + return "et-" + endIdSeq; + } + default -> { + Logger.warn("Unknown Tile Type " + tileType); + return null; + } + } + } + + private static int maxIdSeq(int currentId, int newId) { + if (currentId < newId) { + return newId; + } else { + return currentId; + } + } + + public static Tile createTile(String tileId) { + TileBean tileBean = JCS.getPersistenceService().getTileBean(tileId); + return createTile(tileBean); + } + + public static Tile createTile(TileBean tileBean) { + return createTile(tileBean, false); + } + + public static Tile createTile(TileBean tileBean, boolean showValues) { + if (tileBean == null) { + return null; + } + + TileBean.TileType tileType = tileBean.getTileType(); + Tile tile = null; + switch (tileType) { + case STRAIGHT -> { + tile = new Straight(tileBean); + straightIdSeq = maxIdSeq(straightIdSeq, nextIdSeq(tileBean.getId())); + } + case CROSSING -> { + tile = new Crossing(tileBean); + crossingIdSeq = maxIdSeq(crossingIdSeq, nextIdSeq(tileBean.getId())); + } + case CURVED -> { + tile = new Curved(tileBean); + curvedIdSeq = maxIdSeq(curvedIdSeq, nextIdSeq(tileBean.getId())); + } + case SWITCH -> { + tile = new Switch(tileBean); + tile.setAccessoryBean(tileBean.getAccessoryBean()); + + switchIdSeq = maxIdSeq(switchIdSeq, nextIdSeq(tileBean.getId())); + if (showValues && tileBean.getAccessoryBean() != null) { + tile.setAccessoryValue((tileBean.getAccessoryBean()).getAccessoryValue()); + } + JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); + } + case CROSS -> { + tile = new Cross(tileBean); + tile.setAccessoryBean(tileBean.getAccessoryBean()); + + crossIdSeq = maxIdSeq(crossIdSeq, nextIdSeq(tileBean.getId())); + if (showValues && tileBean.getAccessoryBean() != null) { + tile.setAccessoryValue((tileBean.getAccessoryBean()).getAccessoryValue()); + } + JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); + } + case SIGNAL -> { + tile = new Signal(tileBean); + tile.setAccessoryBean(tileBean.getAccessoryBean()); + + signalIdSeq = maxIdSeq(signalIdSeq, nextIdSeq(tileBean.getId())); + if (showValues && tileBean.getAccessoryBean() != null) { + ((Signal) tile).setSignalValue(((AccessoryBean) tileBean.getAccessoryBean()).getSignalValue()); + } + JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); + } + case SENSOR -> { + tile = new Sensor(tileBean); + tile.setSensorBean(tileBean.getSensorBean()); + sensorIdSeq = maxIdSeq(sensorIdSeq, nextIdSeq(tileBean.getId())); + + if (showValues && tileBean.getSensorBean() != null) { + ((Sensor) tile).setActive(((SensorBean) tileBean.getSensorBean()).isActive()); + } + JCS.getJcsCommandStation().addSensorEventListener((SensorEventListener) tile); + } + case BLOCK -> { + tile = new Block(tileBean); + tile.setBlockBean(tileBean.getBlockBean()); + blockIdSeq = maxIdSeq(blockIdSeq, nextIdSeq(tileBean.getId())); + } + case STRAIGHT_DIR -> { + tile = new StraightDirection(tileBean); + straightDirectionIdSeq = maxIdSeq(straightDirectionIdSeq, nextIdSeq(tileBean.getId())); + } + case END -> { + tile = new End(tileBean); + endIdSeq = maxIdSeq(endIdSeq, nextIdSeq(tileBean.getId())); + } + default -> + Logger.warn("Unknown Tile Type " + tileType); + } + + return (Tile) tile; + } + + public static void rollback(Tile tile) { + switch (tile.tileType) { + case STRAIGHT -> { + straightIdSeq--; + } + case CROSSING -> { + crossingIdSeq--; + } + case CURVED -> { + curvedIdSeq--; + } + case SWITCH -> { + switchIdSeq--; + } + case CROSS -> { + crossIdSeq--; + } + case SIGNAL -> { + signalIdSeq--; + } + case SENSOR -> { + sensorIdSeq--; + } + case BLOCK -> { + blockIdSeq--; + } + case STRAIGHT_DIR -> { + straightDirectionIdSeq--; + } + case END -> { + endIdSeq--; + } + } + + } + + /** + * @param tileType type of type to create + * @param orientation whether the orientation of the Tile is EAST, WEST, NORTH or SOUTH + * @param x the tile center X + * @param y the tile center Y + * @return a Tile object + */ + public static Tile createTile(TileBean.TileType tileType, Orientation orientation, int x, int y) { + return createTile(tileType, orientation, Direction.CENTER, x, y); + } + + /** + * @param tileType type of type to create + * @param orientation whether the orientation of the Tile is EAST, WEST, NORTH or SOUTH + * @param direction direction plays a role with Turnout tiles whether it goes to the Left or Right + * @param x the tile center X + * @param y the tile center Y + * @return a Tile object + */ + public static Tile createTile(TileBean.TileType tileType, Orientation orientation, Direction direction, int x, int y) { + return createTile(tileType, orientation, direction, new Point(x, y)); + } + + public static Tile createTile(TileBean.TileType tileType, Orientation orientation, Direction direction, Point center) { + Tile tile = null; + switch (tileType) { + case STRAIGHT -> { + tile = new Straight(orientation, center); + } + case CROSSING -> { + tile = new Crossing(orientation, center); + } + case CURVED -> + tile = new Curved(orientation, center); + case SWITCH -> + tile = new Switch(orientation, direction, center); + case CROSS -> + tile = new Cross(orientation, direction, center); + case SIGNAL -> + tile = new Signal(orientation, center); + case SENSOR -> + tile = new Sensor(orientation, center); + case BLOCK -> + tile = new Block(orientation, center); + case STRAIGHT_DIR -> + tile = new StraightDirection(orientation, center); + case END -> + tile = new End(orientation, center); + default -> + Logger.warn("Unknown Tile Type " + tileType); + } + + if (tile != null) { + tile.setId(nextTileId(tileType)); + } + + return (Tile) tile; + } + + public static List toTiles(List tileBeans, boolean drawOutline, boolean showValues) { + List tileList = new LinkedList<>(); + + for (TileBean tileBean : tileBeans) { + Tile tile = createTile(tileBean, showValues); + tileList.add(tile); + } + return tileList; + } + +} diff --git a/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java b/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java index 0e2ce14e..c24a6a91 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java @@ -16,17 +16,25 @@ package jcs.ui.layout.tiles.ui; import java.awt.Color; +import java.awt.Component; import java.awt.Graphics2D; import java.awt.MultipleGradientPaint; import java.awt.Point; import java.awt.RadialGradientPaint; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; import java.awt.geom.Ellipse2D; +import java.util.Date; import javax.swing.JComponent; import javax.swing.plaf.ComponentUI; +import jcs.commandStation.events.SensorEvent; +import jcs.entities.SensorBean; import jcs.ui.layout.tiles.Tile; +import jcs.ui.layout.tiles.TileCache; import jcs.ui.layout.tiles.TileModel; +import org.tinylog.Logger; -public class SensorUI extends StraightUI { +public class SensorUI extends StraightUI implements MouseListener { public SensorUI() { } @@ -35,6 +43,18 @@ public static ComponentUI createUI(JComponent c) { return new SensorUI(); } + @Override + public void installUI(JComponent c) { + Tile tile = (Tile) c; + tile.addMouseListener(this); + } + + @Override + public void uninstallUI(JComponent c) { + Tile tile = (Tile) c; + tile.removeMouseListener(this); + } + private void renderSensor(Graphics2D g2, JComponent c) { Tile tile = (Tile) c; TileModel model = tile.getModel(); @@ -59,11 +79,54 @@ private void renderSensor(Graphics2D g2, JComponent c) { g2.fill(new Ellipse2D.Double(xx, yy, 0.5f * radius, 0.5f * radius)); } - @Override public void renderTile(Graphics2D g2, JComponent c) { renderStraight(g2, c); renderSensor(g2, c); } + @Override + public void mousePressed(MouseEvent e) { + //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); + redispatchToParent(e); + } + + @Override + public void mouseReleased(MouseEvent e) { + //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); + redispatchToParent(e); + } + + @Override + public void mouseClicked(MouseEvent e) { + //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); + //Only JCS is in CONTROL mode (readonly) activate sensor action events. + + if (isControlMode((Component) e.getSource()) && e.getButton() == MouseEvent.BUTTON1) { + Tile tile = (Tile) e.getSource(); + tile.setActive(!tile.isActive()); + if (tile.getSensorBean() != null) { + SensorBean sb = tile.getSensorBean(); + sb.setLastUpdated(new Date()); + SensorEvent sae = new SensorEvent(sb); + TileCache.enqueTileAction(sae); + //Logger.trace("Changing Tile "+tile.getId()+" Sensor "+sb.getId()+" to "+sb.isActive()+"..."); + } + } else { + redispatchToParent(e); + } + } + + @Override + public void mouseEntered(MouseEvent e) { + //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); + redispatchToParent(e); + } + + @Override + public void mouseExited(MouseEvent e) { + //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); + redispatchToParent(e); + } + } diff --git a/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java b/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java index 9f30b6f4..039988b6 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java @@ -16,18 +16,22 @@ package jcs.ui.layout.tiles.ui; import java.awt.Color; +import java.awt.Component; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Insets; +import java.awt.event.MouseEvent; import java.awt.geom.AffineTransform; import java.awt.geom.Ellipse2D; import java.awt.image.BufferedImage; import javax.swing.JComponent; +import javax.swing.SwingUtilities; import javax.swing.plaf.ComponentUI; import jcs.entities.TileBean; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; +import jcs.ui.layout.LayoutCanvas; import jcs.ui.layout.tiles.Tile; import static jcs.ui.layout.tiles.Tile.DEFAULT_BACKGROUND_COLOR; import static jcs.ui.layout.tiles.Tile.DEFAULT_TRACK_COLOR; @@ -266,4 +270,19 @@ public void paint(Graphics g, JComponent c) { Logger.trace(tile.getId() + " Duration: " + (now - started) + " ms. Cp: " + tile.xyToString() + " O: " + model.getTileOrienation()); } } + + protected void redispatchToParent(MouseEvent e) { + Component source = (Component) e.getSource(); + MouseEvent parentEvent = SwingUtilities.convertMouseEvent(source, e, source.getParent()); + source.getParent().dispatchEvent(parentEvent); + } + + protected boolean isControlMode(Component c) { + if (c.getParent() != null && c.getParent() instanceof LayoutCanvas) { + return ((LayoutCanvas) c.getParent()).isReadonly(); + } else { + return false; + } + } + } From 461ee5230cd1eb4b2e72d821b938f6aaf892bd95 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Sun, 9 Feb 2025 20:03:43 +0100 Subject: [PATCH 18/70] Restored the control of Switches using the Command screen --- .../esu/ecos/EsuEcosCommandStationImpl.java | 8 +- src/main/java/jcs/ui/layout/LayoutCanvas.java | 34 +- .../jcs/ui/layout/tiles/DefaultTileModel.java | 29 +- src/main/java/jcs/ui/layout/tiles/Signal.java | 2 +- src/main/java/jcs/ui/layout/tiles/Tile.java | 384 +++++++++--------- .../layout/tiles/TileActionEventHandler.java | 10 +- .../java/jcs/ui/layout/tiles/TileModel.java | 9 + .../java/jcs/ui/layout/tiles/ui/CrossUI.java | 4 +- .../java/jcs/ui/layout/tiles/ui/SensorUI.java | 10 +- .../java/jcs/ui/layout/tiles/ui/SignalUI.java | 13 +- .../java/jcs/ui/layout/tiles/ui/SwitchUI.java | 81 +++- 11 files changed, 369 insertions(+), 215 deletions(-) diff --git a/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java b/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java index b1b98540..86379a6a 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java @@ -579,7 +579,7 @@ public void fireSensorEventListeners(SensorEvent sensorEvent) { if (sensorEventListeners != null && !sensorEventListeners.isEmpty()) { for (SensorEventListener listener : sensorEventListeners) { //if (listener != null) { - listener.onSensorChange(sensorEvent); + listener.onSensorChange(sensorEvent); //} } } @@ -617,8 +617,10 @@ void fireFunctionEventListeners(final LocomotiveFunctionEvent functionEvent) { } void fireAccessoryEventListeners(final AccessoryEvent accessoryEvent) { - for (AccessoryEventListener listener : this.accessoryEventListeners) { - listener.onAccessoryChange(accessoryEvent); + if (accessoryEventListeners != null && !accessoryEventListeners.isEmpty()) { + for (AccessoryEventListener listener : accessoryEventListeners) { + listener.onAccessoryChange(accessoryEvent); + } } } diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.java b/src/main/java/jcs/ui/layout/LayoutCanvas.java index 860c36fd..f50704db 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.java +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.java @@ -472,29 +472,31 @@ private void executeControlActionForTile(Tile tile, Point p) { BlockControlDialog bcd = new BlockControlDialog(getParentFrame(), block); bcd.setVisible(true); } - case SIGNAL -> - this.executor.execute(() -> toggleSignal((Signal) tile)); - case SWITCH -> - this.executor.execute(() -> toggleSwitch((Switch) tile)); + case SIGNAL -> { + //this.executor.execute(() -> toggleSignal((Signal) tile)); + } + case SWITCH -> { + //this.executor.execute(() -> toggleSwitch((Switch) tile)); + } case CROSS -> { - this.executor.execute(() -> toggleSwitch((Switch) tile)); + //this.executor.execute(() -> toggleSwitch((Switch) tile)); } default -> { } } } - private void toggleSwitch(Switch turnout) { - if (turnout.getAccessoryBean() != null) { - AccessoryBean ab = turnout.getAccessoryBean(); - ab.toggle(); - turnout.setAccessoryValue(ab.getAccessoryValue()); - - JCS.getJcsCommandStation().switchAccessory(ab, ab.getAccessoryValue()); - } else { - Logger.trace("No AccessoryBean configured for Turnout: " + turnout.getId()); - } - } +// private void toggleSwitch(Switch turnout) { +// if (turnout.getAccessoryBean() != null) { +// AccessoryBean ab = turnout.getAccessoryBean(); +// ab.toggle(); +// turnout.setAccessoryValue(ab.getAccessoryValue()); +// +// JCS.getJcsCommandStation().switchAccessory(ab, ab.getAccessoryValue()); +// } else { +// Logger.trace("No AccessoryBean configured for Turnout: " + turnout.getId()); +// } +// } private void toggleSignal(Signal signal) { if (signal.getAccessoryBean() != null) { diff --git a/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java b/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java index 2d97658b..7aabdfd7 100644 --- a/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java +++ b/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java @@ -21,6 +21,8 @@ import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.EventListenerList; +import jcs.entities.AccessoryBean.AccessoryValue; +import jcs.entities.AccessoryBean.SignalValue; import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; import jcs.entities.TileBean.Orientation; @@ -47,6 +49,9 @@ public class DefaultTileModel implements TileModel { protected boolean showAccessoryValue = false; protected boolean showSignalValue = false; protected boolean sensorActive = false; + protected AccessoryValue accessoryValue; + protected SignalValue signalValue; + protected boolean showOutline = false; protected BlockState blockState; @@ -127,7 +132,7 @@ public void setTileOrienation(Orientation tileOrienation) { this.tileOrienation = tileOrienation; fireStateChanged(); } - + @Override public Orientation getIncomingSide() { return incomingSide; @@ -204,6 +209,28 @@ public void setSensorActive(boolean sensorActive) { fireStateChanged(); } + @Override + public AccessoryValue getAccessoryValue() { + return accessoryValue; + } + + @Override + public void setAccessoryValue(AccessoryValue accessoryValue) { + this.accessoryValue = accessoryValue; + fireStateChanged(); + } + + @Override + public SignalValue getSignalValue() { + return signalValue; + } + + @Override + public void setSignalValue(SignalValue signalValue) { + this.signalValue = signalValue; + fireStateChanged(); + } + @Override public BlockState getBlockState() { if (blockState == null) { diff --git a/src/main/java/jcs/ui/layout/tiles/Signal.java b/src/main/java/jcs/ui/layout/tiles/Signal.java index 25765a26..f0c6eb69 100644 --- a/src/main/java/jcs/ui/layout/tiles/Signal.java +++ b/src/main/java/jcs/ui/layout/tiles/Signal.java @@ -48,7 +48,7 @@ public class Signal extends Straight implements AccessoryEventListener { super(orientation, center); this.tileType = TileType.SIGNAL; this.signalType = signalType; - this.signalValue = SignalValue.OFF; + model.setSignalValue(SignalValue.OFF); } @Override diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java index 144fdb56..1c3648ee 100755 --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -18,7 +18,6 @@ import jcs.ui.layout.tiles.ui.TileUI; import java.awt.Color; import java.awt.Dimension; -import java.awt.Graphics; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.ActionEvent; @@ -41,6 +40,7 @@ import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.AccessoryValue; import jcs.entities.AccessoryBean.SignalType; +import jcs.entities.AccessoryBean.SignalValue; import jcs.entities.BlockBean; import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; @@ -52,7 +52,6 @@ import jcs.ui.layout.LayoutUtil; import static jcs.ui.layout.tiles.Block.BLOCK_HEIGHT; import static jcs.ui.layout.tiles.Block.BLOCK_WIDTH; -import org.tinylog.Logger; /** * Basic graphic element to display a track, turnout, etc on the screen.
@@ -78,13 +77,13 @@ public abstract class Tile extends JComponent { // implements ChangeListener public static final int GRID = 20; public static final int DEFAULT_WIDTH = GRID * 2; public static final int DEFAULT_HEIGHT = GRID * 2; - + public static final Color DEFAULT_BACKGROUND_COLOR = Color.white; public static final Color DEFAULT_TRACK_COLOR = Color.lightGray; public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.darkGray; public static final Color DEFAULT_SELECTED_COLOR = Color.yellow; public static final Color DEFAULT_WARN_COLOR = Color.red; - + public static final String MODEL_CHANGED_PROPERTY = "model"; // public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled"; @@ -92,140 +91,139 @@ public abstract class Tile extends JComponent { // implements ChangeListener * The data model that determines the Tile state. */ protected TileModel model = null; - + protected String id; protected Integer tileX; protected Integer tileY; - + protected Direction tileDirection; - + protected TileType tileType; protected String accessoryId; protected String sensorId; - - protected AccessoryValue accessoryValue; + + //protected AccessoryValue accessoryValue; protected AccessoryValue routeValue; - + protected SignalType signalType; - protected AccessoryBean.SignalValue signalValue; - + //protected AccessoryBean.SignalValue signalValue; + protected TileBean tileBean; protected AccessoryBean accessoryBean; protected SensorBean sensorBean; protected BlockBean blockBean; - + protected List neighbours; - + protected int renderOffsetX = 0; protected int renderOffsetY = 0; - + protected boolean drawName = true; - + protected BufferedImage tileImage; - + protected PropertyChangeListener propertyChangeListener; - + protected ChangeListener changeListener = null; protected ActionListener actionListener = null; - + protected transient ChangeEvent changeEvent; private Handler handler; - + protected Tile(TileType tileType, Orientation orientation, Point center, int width, int height) { this(tileType, orientation, Direction.CENTER, center.x, center.y, width, height); } - + protected Tile(TileType tileType, Orientation orientation, int x, int y, int width, int height) { this(tileType, orientation, Direction.CENTER, x, y, width, height); } - + protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { this(tileType, orientation, direction, x, y, width, height, null, null); } - + protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height, Color backgroundColor, Color selectedColor) { this.tileType = tileType; this.tileDirection = direction; this.tileX = x; this.tileY = y; - + setLayout(null); Dimension d = new Dimension(width, height); setSize(d); setPreferredSize(d); } - + protected Tile(TileBean tileBean) { this(tileBean, tileWidth(tileBean.getOrientation(), tileBean.getTileType()), tileHeight(tileBean.getOrientation(), tileBean.getTileType())); } - + protected Tile(TileBean tileBean, int width, int height) { this.tileBean = tileBean; - this.id = tileBean.getId(); - this.tileType = tileBean.getTileType(); - this.tileDirection = tileBean.getDirection(); - this.tileX = tileBean.getX(); - this.tileY = tileBean.getY(); - - this.accessoryId = tileBean.getAccessoryId(); - this.accessoryBean = tileBean.getAccessoryBean(); - this.signalType = tileBean.getSignalType(); - - this.sensorId = tileBean.getSensorId(); - this.sensorBean = tileBean.getSensorBean(); - this.blockBean = tileBean.getBlockBean(); - + id = tileBean.getId(); + tileType = tileBean.getTileType(); + tileDirection = tileBean.getDirection(); + tileX = tileBean.getX(); + tileY = tileBean.getY(); + + accessoryId = tileBean.getAccessoryId(); + accessoryBean = tileBean.getAccessoryBean(); + + sensorId = tileBean.getSensorId(); + sensorBean = tileBean.getSensorBean(); + blockBean = tileBean.getBlockBean(); + setLayout(null); Dimension d = new Dimension(width, height); setSize(d); setPreferredSize(d); } - + @Override public String getUIClassID() { return TileUI.UI_CLASS_ID; } - + @Override public TileUI getUI() { return (TileUI) ui; } - + public void setUI(TileUI ui) { super.setUI(ui); } - + public TileModel getModel() { return model; } - + public void setModel(TileModel newModel) { TileModel oldModel = getModel(); - + if (oldModel != null) { oldModel.removeChangeListener(changeListener); oldModel.removeActionListener(actionListener); changeListener = null; actionListener = null; } - + model = newModel; - + if (newModel != null) { changeListener = createChangeListener(); actionListener = createActionListener(); - + newModel.addChangeListener(changeListener); newModel.addActionListener(actionListener); } - + firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel); if (newModel != oldModel) { revalidate(); repaint(); } } - + protected static int tileWidth(Orientation orientation, TileType tileType) { if (Orientation.EAST == orientation || Orientation.WEST == orientation) { if (null == tileType) { @@ -244,7 +242,7 @@ protected static int tileWidth(Orientation orientation, TileType tileType) { return DEFAULT_WIDTH; } } - + protected static int tileHeight(Orientation orientation, TileType tileType) { if (Orientation.EAST == orientation || Orientation.WEST == orientation) { return DEFAULT_HEIGHT; @@ -263,7 +261,7 @@ protected static int tileHeight(Orientation orientation, TileType tileType) { } } } - + protected void populateModel() { if (this.blockBean != null) { this.model.setBlockState(this.blockBean.getBlockState()); @@ -271,8 +269,15 @@ protected void populateModel() { this.model.setArrivalSuffix(this.blockBean.getArrivalSuffix()); this.model.setLogicalDirection(LocomotiveBean.Direction.get(this.blockBean.getLogicalDirection())); } + if (accessoryBean != null) { + setAccessoryBean(accessoryBean); + } + if (sensorBean != null) { + setSensorBean(sensorBean); + } + } - + public TileBean getTileBean() { if (tileBean == null) { tileBean = new TileBean(); @@ -281,7 +286,7 @@ public TileBean getTileBean() { tileBean.setY(this.tileY); tileBean.setTileType(this.tileType); tileBean.setTileOrientation(this.model.getTileOrienation().getOrientation()); - + tileBean.setTileDirection(this.tileDirection.getDirection()); tileBean.setSignalType(this.signalType); tileBean.setAccessoryId(this.accessoryId); @@ -312,23 +317,23 @@ public TileBean getTileBean() { public boolean isSelected() { return model.isSelected(); } - + public void setSelected(boolean b) { model.setSelected(b); } - + public String getId() { return id; } - + public void setId(String id) { this.id = id; } - + public SignalType getSignalType() { return signalType; } - + public void setSignalType(SignalType signalType) { this.signalType = signalType; } @@ -356,7 +361,7 @@ public Integer getTileY() { public Point getCenter() { return new Point(this.tileX, this.tileY); } - + public void setCenter(Point center) { tileX = center.x; tileY = center.y; @@ -372,59 +377,59 @@ public void setCenter(Point center) { public Orientation getOrientation() { return model.getTileOrienation(); } - + public void setOrientation(Orientation orientation) { model.setTileOrienation(orientation); if (tileBean != null) { tileBean.setOrientation(orientation); } } - + public Direction getDirection() { return tileDirection; } - + public void setDirection(Direction direction) { this.tileDirection = direction; if (tileBean != null) { tileBean.setDirection(direction); } } - + public String getAccessoryId() { return accessoryId; } - + public void setAccessoryId(String accessoryId) { this.accessoryId = accessoryId; if (tileBean != null) { tileBean.setAccessoryId(accessoryId); } } - + public String getSensorId() { return sensorId; } - + public void setSensorId(String sensorId) { this.sensorId = sensorId; } - + public boolean isActive() { return model.isSensorActive(); } - + public void setActive(boolean active) { model.setSensorActive(active); if (this.sensorBean != null) { this.sensorBean.setActive(active); } } - + public BlockState getBlockState() { return model.getBlockState(); } - + public void setBlockState(BlockState blockState) { if (blockBean != null) { blockBean.setBlockState(blockState); @@ -433,84 +438,90 @@ public void setBlockState(BlockState blockState) { } model.setBlockState(blockState); } - + public String getDepartureSuffix() { return model.getDepartureSuffix(); } - + public void setDepartureSuffix(String suffix) { if (blockBean != null) { blockBean.setDepartureSuffix(suffix); } model.setDepartureSuffix(suffix); } - + public boolean isReverseArrival() { return model.isReverseArrival(); } - + public void setReverseArrival(boolean reverseArrival) { if (blockBean != null) { blockBean.setReverseArrival(reverseArrival); } model.setReverseArrival(reverseArrival); } - + public LocomotiveBean.Direction getLogicalDirection() { return model.getLogicalDirection(); } - + public void setLogicalDirection(LocomotiveBean.Direction logicalDirection) { if (blockBean != null) { blockBean.setLogicalDirection(logicalDirection.getDirection()); } model.setLogicalDirection(logicalDirection); } - + public LocomotiveBean getLocomotive() { return model.getLocomotive(); } - + public void setLocomotive(LocomotiveBean locomotive) { if (blockBean != null) { blockBean.setLocomotive(locomotive); model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (model.getBlockState() == BlockState.OCCUPIED || model.getBlockState() == BlockState.INBOUND || model.getBlockState() == BlockState.OUTBOUND)); } - + model.setLocomotive(locomotive); } - + public AccessoryBean getAccessoryBean() { return accessoryBean; } - + public void setAccessoryBean(AccessoryBean accessoryBean) { this.accessoryBean = accessoryBean; - if (accessoryBean != null) { accessoryId = accessoryBean.getId(); - signalValue = accessoryBean.getSignalValue(); - signalType = SignalType.getSignalType(accessoryBean.getType()); + if (accessoryBean.isSignal()) { + signalType = SignalType.getSignalType(accessoryBean.getType()); + model.setSignalValue(accessoryBean.getSignalValue()); + } else if (accessoryBean.isTurnout()) { + model.setAccessoryValue(accessoryBean.getAccessoryValue()); + } else { + model.setAccessoryValue(AccessoryValue.OFF); + } } else { accessoryId = null; signalType = SignalType.NONE; - signalValue = AccessoryBean.SignalValue.OFF; + model.setAccessoryValue(AccessoryValue.OFF); } } - - public AccessoryValue getAccessoryValue() { - if (this.accessoryValue == null) { - return AccessoryValue.OFF; - } else { - return accessoryValue; - } - } - + +// public AccessoryValue getAccessoryValue() { +// if (this.accessoryValue == null) { +// return AccessoryValue.OFF; +// } else { +// return accessoryValue; +// } +// } public void setAccessoryValue(AccessoryValue value) { - this.accessoryValue = value; - repaint(); + model.setAccessoryValue(value); + if (accessoryBean != null) { + accessoryBean.setAccessoryValue(value); + } } - + public AccessoryValue getRouteValue() { if (routeValue == null) { return AccessoryValue.OFF; @@ -518,93 +529,101 @@ public AccessoryValue getRouteValue() { return routeValue; } } - + public void setRouteValue(AccessoryValue value) { this.routeValue = value; repaint(); } - - public AccessoryBean.SignalValue getSignalValue() { - return signalValue; - } - + +// public AccessoryBean.SignalValue getSignalValue() { +// return signalValue; +// } public void setSignalValue(AccessoryBean.SignalValue signalValue) { - this.signalValue = signalValue; - repaint(); + model.setSignalValue(signalValue); + if (this.accessoryBean != null) { + this.accessoryBean.setSignalValue(signalValue); + } } - + public SensorBean getSensorBean() { return sensorBean; } - + public void setSensorBean(SensorBean sensorBean) { this.sensorBean = sensorBean; + if (sensorBean != null) { + sensorId = sensorBean.getId(); + model.setSensorActive(sensorBean.isActive()); + } else { + model.setSensorActive(false); + sensorId = null; + } } - + public BlockBean getBlockBean() { return blockBean; } - + public void setBlockBean(BlockBean blockBean) { this.blockBean = blockBean; } - + public int getRenderOffsetX() { return renderOffsetX; } - + public void setRenderOffsetX(int renderOffsetX) { this.renderOffsetX = renderOffsetX; } - + public int getRenderOffsetY() { return renderOffsetY; } - + public void setRenderOffsetY(int renderOffsetY) { this.renderOffsetY = renderOffsetY; } - + public TileBean.TileType getTileType() { return this.tileType; } - + public final void setTileType(TileType tileType) { this.tileType = tileType; } - + public void setTrackColor(Color trackColor) { if (getUI() != null) { getUI().setTrackColor(trackColor); } } - + public void setTrackRouteColor(Color trackRouteColor) { if (getUI() != null) { getUI().setTrackRouteColor(trackRouteColor); } } - + public Color getSelectedColor() { return model.getSelectedColor(); } - + public void setSelectedColor(Color selectedColor) { model.setSelectedColor(selectedColor); } - + public Orientation getIncomingSide() { return model.getIncomingSide(); } - + public void setIncomingSide(Orientation incomingSide) { model.setIncomingSide(incomingSide); } - + public boolean isShowRoute() { return model.isShowRoute(); } - + public void setShowRoute(boolean drawRoute) { this.model.setShowRoute(drawRoute); } @@ -617,17 +636,17 @@ public void setShowRoute(boolean drawRoute) { * */ public abstract Map getNeighborPoints(); - + public abstract Map getEdgePoints(); - + Set getAltPoints(Point center) { return Collections.EMPTY_SET; } - + public Set getAllPoints() { return getAllPoints(getCenter()); } - + Set getAllPoints(Point center) { Set aps = new HashSet<>(); aps.add(center); @@ -653,7 +672,7 @@ public Orientation rotate() { } return model.getTileOrienation(); } - + public void flipHorizontal() { Orientation tileOrientation = model.getTileOrienation(); if (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) { @@ -661,7 +680,7 @@ public void flipHorizontal() { rotate(); } } - + public void flipVertical() { Orientation tileOrientation = model.getTileOrienation(); if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { @@ -669,41 +688,41 @@ public void flipVertical() { rotate(); } } - + @Override public void move(int newX, int newY) { Point cs = LayoutUtil.snapToGrid(newX, newY); setCenter(cs); } - + public static BufferedImage flipHorizontally(BufferedImage source) { BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); - + AffineTransform flip = AffineTransform.getScaleInstance(1, -1); flip.translate(0, -source.getHeight()); AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); - + op.filter(source, output); - + return output; } - + public static BufferedImage flipVertically(BufferedImage source) { BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); - + AffineTransform flip = AffineTransform.getScaleInstance(-1, 1); flip.translate(-source.getWidth(), 0); AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); - + op.filter(source, output); - + return output; } - + public Set getAltPoints() { return Collections.EMPTY_SET; } - + public int getCenterX() { if (tileX > 0) { return this.tileX; @@ -711,7 +730,7 @@ public int getCenterX() { return GRID; } } - + public int getCenterY() { if (tileY > 0) { return this.tileY; @@ -719,19 +738,19 @@ public int getCenterY() { return GRID; } } - + public boolean isDrawName() { return drawName; } - + public void setDrawName(boolean drawName) { this.drawName = drawName; } - + public boolean isScaleImage() { return model.isScaleImage(); } - + public void setScaleImage(boolean scaleImage) { Dimension d; if (scaleImage) { @@ -739,23 +758,23 @@ public void setScaleImage(boolean scaleImage) { } else { int renderWidth = getUI().getRenderWidth(); int renderHeight = getUI().getRenderHeight(); - + d = new Dimension(renderWidth, renderHeight); } - + setSize(d); setPreferredSize(d); model.setScaleImage(scaleImage); } - + public boolean isDrawCenterPoint() { return model.isShowCenter(); } - + public void setDrawCenterPoint(boolean drawCenterPoint) { model.setShowCenter(drawCenterPoint); } - + @Override public String toString() { return this.getClass().getSimpleName() @@ -769,7 +788,7 @@ public String toString() { + xyToString() + "}"; } - + public String xyToString() { return "(" + this.tileX + "," + this.tileY + ")"; } @@ -793,15 +812,15 @@ public boolean isVertical() { Orientation tileOrientation = model.getTileOrienation(); return (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) && TileType.CURVED != tileType; } - + public boolean isJunction() { return TileType.SWITCH == tileType || TileType.CROSS == tileType; } - + public boolean isBlock() { return TileType.BLOCK == tileType; } - + public boolean isDirectional() { return TileType.STRAIGHT_DIR == tileType; } @@ -814,52 +833,52 @@ public boolean isDirectional() { public boolean isDiagonal() { return TileType.CURVED == tileType; } - + public boolean isCrossing() { return TileType.CROSSING == tileType; } - + public List getNeighbours() { return neighbours; } - + public void setNeighbours(List neighbours) { this.neighbours = neighbours; } - + public String getIdSuffix(Tile other) { return ""; } - + public Map getNeighborOrientations() { Map edgeOrientations = new HashMap<>(); - + Map neighborPoints = getNeighborPoints(); - + for (Orientation o : Orientation.values()) { edgeOrientations.put(neighborPoints.get(o), o); } return edgeOrientations; } - + public Map getEdgeOrientations() { Map edgeOrientations = new HashMap<>(); - + Map edgeConnections = getEdgePoints(); - + for (Orientation o : Orientation.values()) { edgeOrientations.put(edgeConnections.get(o), o); } return edgeOrientations; } - + public boolean isAdjacent(Tile other) { boolean adjacent = false; - + if (other != null) { Collection thisEdgePoints = getEdgePoints().values(); Collection otherEdgePoints = other.getEdgePoints().values(); - + for (Point p : thisEdgePoints) { adjacent = otherEdgePoints.contains(p); if (adjacent) { @@ -867,7 +886,7 @@ public boolean isAdjacent(Tile other) { } } } - + return adjacent; } @@ -881,40 +900,40 @@ public boolean isAdjacent(Tile other) { public boolean isArrowDirection(Tile other) { return true; } - + public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { return AccessoryValue.OFF; } - + protected ChangeListener createChangeListener() { return getHandler(); } - + protected ActionListener createActionListener() { return getHandler(); } - + private Handler getHandler() { if (handler == null) { handler = new Handler(); } return handler; } - + class Handler implements ActionListener, ChangeListener, Serializable { - + @Override public void stateChanged(ChangeEvent e) { fireStateChanged(); repaint(); } - + @Override public void actionPerformed(ActionEvent event) { fireActionPerformed(event); } } - + protected void fireStateChanged() { Object[] listeners = listenerList.getListenerList(); //reverse order @@ -928,7 +947,7 @@ protected void fireStateChanged() { } } } - + protected void fireActionPerformed(ActionEvent event) { Object[] listeners = listenerList.getListenerList(); ActionEvent e = null; @@ -947,18 +966,18 @@ protected void fireActionPerformed(ActionEvent event) { } } } - + public Rectangle getTileBounds() { if (model.isScaleImage()) { return new Rectangle(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); } else { int renderWidth = getUI().getRenderWidth(); int renderHeight = getUI().getRenderHeight(); - + return new Rectangle(tileX - renderWidth / 2, tileY - renderHeight / 2, renderWidth, renderHeight); } } - + // @Override // protected void paintComponent(Graphics g) { // if (Logger.isTraceEnabled()) { @@ -968,5 +987,4 @@ public Rectangle getTileBounds() { // Logger.trace(id + " Duration: " + (now - started) + " ms. Cp: " + xyToString() + " O: " + model.getTileOrienation()); // } // } - } diff --git a/src/main/java/jcs/ui/layout/tiles/TileActionEventHandler.java b/src/main/java/jcs/ui/layout/tiles/TileActionEventHandler.java index bc36f141..93a1cf34 100644 --- a/src/main/java/jcs/ui/layout/tiles/TileActionEventHandler.java +++ b/src/main/java/jcs/ui/layout/tiles/TileActionEventHandler.java @@ -22,6 +22,7 @@ import jcs.commandStation.events.AccessoryEvent; import jcs.commandStation.events.JCSActionEvent; import jcs.commandStation.events.SensorEvent; +import jcs.entities.AccessoryBean; import org.tinylog.Logger; /** @@ -65,8 +66,8 @@ public void run() { if (event instanceof SensorEvent sensorEvent) { fireSensorEvent(sensorEvent); } - if (event instanceof AccessoryEvent) { - + if (event instanceof AccessoryEvent accessoryEvent) { + switchChanged(accessoryEvent); } } else { @@ -93,4 +94,9 @@ private void fireSensorEvent(SensorEvent sensorEvent) { } } + private void switchChanged(AccessoryEvent accessoryEvent) { + AccessoryBean ab = accessoryEvent.getAccessoryBean(); + JCS.getJcsCommandStation().switchAccessory(ab, ab.getAccessoryValue()); + } + } diff --git a/src/main/java/jcs/ui/layout/tiles/TileModel.java b/src/main/java/jcs/ui/layout/tiles/TileModel.java index 31a4cb28..4266b0e7 100644 --- a/src/main/java/jcs/ui/layout/tiles/TileModel.java +++ b/src/main/java/jcs/ui/layout/tiles/TileModel.java @@ -19,6 +19,7 @@ import java.awt.event.ActionListener; import java.io.Serializable; import javax.swing.event.ChangeListener; +import jcs.entities.AccessoryBean; import jcs.entities.BlockBean; import jcs.entities.LocomotiveBean; import jcs.entities.TileBean; @@ -77,6 +78,14 @@ public interface TileModel extends Serializable { public void setSensorActive(boolean active); + AccessoryBean.AccessoryValue getAccessoryValue(); + + public void setAccessoryValue(AccessoryBean.AccessoryValue accessoryValue); + + AccessoryBean.SignalValue getSignalValue(); + + public void setSignalValue(AccessoryBean.SignalValue signalValue); + BlockBean.BlockState getBlockState(); public void setBlockState(BlockBean.BlockState blockState); diff --git a/src/main/java/jcs/ui/layout/tiles/ui/CrossUI.java b/src/main/java/jcs/ui/layout/tiles/ui/CrossUI.java index 94255d94..62848973 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/CrossUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/CrossUI.java @@ -162,8 +162,8 @@ protected void renderRouteDiagonal2(Graphics2D g2, Color color, JComponent c) { @Override public void renderTile(Graphics2D g2, JComponent c) { Tile tile = (Tile) c; - AccessoryBean.AccessoryValue accessoryValue = tile.getAccessoryValue(); - //Color trackColor = tile.getTrackColor(); + TileModel model = tile.getModel(); + AccessoryBean.AccessoryValue accessoryValue = model.getAccessoryValue(); if (accessoryValue == null) { accessoryValue = AccessoryBean.AccessoryValue.OFF; diff --git a/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java b/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java index c24a6a91..ba953453 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java @@ -32,7 +32,6 @@ import jcs.ui.layout.tiles.Tile; import jcs.ui.layout.tiles.TileCache; import jcs.ui.layout.tiles.TileModel; -import org.tinylog.Logger; public class SensorUI extends StraightUI implements MouseListener { @@ -120,12 +119,21 @@ public void mouseClicked(MouseEvent e) { @Override public void mouseEntered(MouseEvent e) { //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); + Tile tile = (Tile) e.getSource(); + String toolTipText = tile.getId(); + if (tile.getSensorBean() != null) { + toolTipText = toolTipText + "; Id: " + tile.getSensorBean().getId(); + } + tile.setToolTipText(toolTipText); + redispatchToParent(e); } @Override public void mouseExited(MouseEvent e) { //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); + Tile tile = (Tile) e.getSource(); + tile.setToolTipText(null); redispatchToParent(e); } diff --git a/src/main/java/jcs/ui/layout/tiles/ui/SignalUI.java b/src/main/java/jcs/ui/layout/tiles/ui/SignalUI.java index f53462b1..a312bc55 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/SignalUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/SignalUI.java @@ -32,6 +32,7 @@ import static jcs.entities.AccessoryBean.SignalValue.Hp1; import static jcs.entities.AccessoryBean.SignalValue.Hp2; import jcs.ui.layout.tiles.Tile; +import jcs.ui.layout.tiles.TileModel; public class SignalUI extends StraightUI { @@ -50,7 +51,8 @@ public static ComponentUI createUI(JComponent c) { */ protected void renderSignal2(Graphics2D g2d, JComponent c) { Tile tile = (Tile) c; - SignalValue signalValue = tile.getSignalValue(); + TileModel model = tile.getModel(); + SignalValue signalValue = model.getSignalValue(); int rx = RENDER_GRID; int ry = RENDER_GRID + 60; @@ -93,7 +95,8 @@ protected void renderSignal2(Graphics2D g2d, JComponent c) { protected void renderSignal3(Graphics2D g2d, JComponent c) { Tile tile = (Tile) c; - SignalValue signalValue = tile.getSignalValue(); + TileModel model = tile.getModel(); + SignalValue signalValue = model.getSignalValue(); int rx = RENDER_GRID; int ry = RENDER_GRID + 60; @@ -154,7 +157,8 @@ protected void renderSignal3(Graphics2D g2d, JComponent c) { */ protected void renderSignal4(Graphics2D g2d, JComponent c) { Tile tile = (Tile) c; - SignalValue signalValue = tile.getSignalValue(); + TileModel model = tile.getModel(); + SignalValue signalValue = model.getSignalValue(); int rx = RENDER_GRID - 50; int ry = RENDER_GRID + 50; @@ -236,7 +240,8 @@ protected void renderSignal4(Graphics2D g2d, JComponent c) { */ protected void renderSignal2m(Graphics2D g2d, JComponent c) { Tile tile = (Tile) c; - SignalValue signalValue = tile.getSignalValue(); + TileModel model = tile.getModel(); + SignalValue signalValue = model.getSignalValue(); int[] xps = new int[]{RENDER_GRID + 80, +RENDER_GRID + 150, +RENDER_GRID + 170, RENDER_GRID + 170, +RENDER_GRID + 150, RENDER_GRID + 80}; diff --git a/src/main/java/jcs/ui/layout/tiles/ui/SwitchUI.java b/src/main/java/jcs/ui/layout/tiles/ui/SwitchUI.java index fd729988..598719d9 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/SwitchUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/SwitchUI.java @@ -17,17 +17,24 @@ import java.awt.BasicStroke; import java.awt.Color; +import java.awt.Component; import java.awt.Graphics2D; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; import javax.swing.JComponent; import javax.swing.plaf.ComponentUI; +import jcs.commandStation.events.AccessoryEvent; import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.AccessoryValue; import static jcs.entities.AccessoryBean.AccessoryValue.GREEN; import static jcs.entities.AccessoryBean.AccessoryValue.RED; import jcs.entities.TileBean; import jcs.ui.layout.tiles.Tile; +import jcs.ui.layout.tiles.TileCache; +import jcs.ui.layout.tiles.TileModel; +import org.tinylog.Logger; -public class SwitchUI extends TileUI { +public class SwitchUI extends TileUI implements MouseListener { public SwitchUI() { } @@ -36,6 +43,18 @@ public static ComponentUI createUI(JComponent c) { return new SwitchUI(); } + @Override + public void installUI(JComponent c) { + Tile tile = (Tile) c; + tile.addMouseListener(this); + } + + @Override + public void uninstallUI(JComponent c) { + Tile tile = (Tile) c; + tile.removeMouseListener(this); + } + protected void renderStraight(Graphics2D g2, Color color, JComponent c) { int xx = 0; int yy = 170; @@ -100,7 +119,9 @@ protected void renderRouteDiagonal(Graphics2D g2, Color color, JComponent c) { @Override public void renderTile(Graphics2D g2, JComponent c) { Tile tile = (Tile) c; - AccessoryValue accessoryValue = tile.getAccessoryValue(); + TileModel model = tile.getModel(); + AccessoryValue accessoryValue = model.getAccessoryValue(); + if (accessoryValue == null) { accessoryValue = AccessoryBean.AccessoryValue.OFF; } @@ -140,4 +161,60 @@ public void renderTileRoute(Graphics2D g2, JComponent c) { } } } + + @Override + public void mousePressed(MouseEvent e) { + //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); + redispatchToParent(e); + } + + @Override + public void mouseReleased(MouseEvent e) { + //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); + redispatchToParent(e); + } + + @Override + public void mouseClicked(MouseEvent e) { + //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); + //Only JCS is in CONTROL mode (readonly) activate accessory action events. + if (isControlMode((Component) e.getSource()) && e.getButton() == MouseEvent.BUTTON1) { + Tile tile = (Tile) e.getSource(); + tile.setActive(!tile.isActive()); + + if (tile.getAccessoryBean() != null) { + AccessoryBean ab = tile.getAccessoryBean(); + ab.toggle(); + tile.setAccessoryValue(ab.getAccessoryValue()); + + AccessoryEvent aae = new AccessoryEvent(ab); + TileCache.enqueTileAction(aae); + Logger.trace("Changing Tile " + tile.getId() + " Accessory " + ab.getId() + " to " + ab.getAccessoryValue().getValue() + "..."); + } + } else { + redispatchToParent(e); + } + } + + @Override + public void mouseEntered(MouseEvent e) { + //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); + Tile tile = (Tile) e.getSource(); + String toolTipText = tile.getId(); + if (tile.getAccessoryBean() != null) { + toolTipText = toolTipText + "; Id: " + tile.getAccessoryBean().getId(); + } + tile.setToolTipText(toolTipText); + + redispatchToParent(e); + } + + @Override + public void mouseExited(MouseEvent e) { + //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); + Tile tile = (Tile) e.getSource(); + tile.setToolTipText(null); + redispatchToParent(e); + } + } From 138b01285efa6f9dcf2a83a1821b5c7d6216eb97 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Mon, 10 Feb 2025 21:16:55 +0100 Subject: [PATCH 19/70] Fixed draging, added Restored Signal Control --- .../jcs/persistence/H2PersistenceService.java | 25 ++++++ src/main/java/jcs/ui/layout/LayoutCanvas.java | 34 +------- .../java/jcs/ui/layout/LayoutPanelTester.java | 2 +- .../jcs/ui/layout/LayoutPanelTesterRO.java | 2 +- src/main/java/jcs/ui/layout/tiles/Tile.java | 10 --- .../java/jcs/ui/layout/tiles/ui/SensorUI.java | 45 ++++++---- .../java/jcs/ui/layout/tiles/ui/SignalUI.java | 82 ++++++++++++++++++- .../java/jcs/ui/layout/tiles/ui/SwitchUI.java | 42 ++++++---- .../java/jcs/ui/layout/tiles/ui/TileUI.java | 10 ++- 9 files changed, 174 insertions(+), 78 deletions(-) diff --git a/src/main/java/jcs/persistence/H2PersistenceService.java b/src/main/java/jcs/persistence/H2PersistenceService.java index cb696eac..001e1e64 100755 --- a/src/main/java/jcs/persistence/H2PersistenceService.java +++ b/src/main/java/jcs/persistence/H2PersistenceService.java @@ -629,6 +629,8 @@ public synchronized TileBean persist(TileBean tileBean) { @Override public synchronized void remove(TileBean tileBean) { + removeRouteByTileId(tileBean.getId()); + if (tileBean.getBlockBean() != null) { BlockBean bb = tileBean.getBlockBean(); this.remove(bb); @@ -774,6 +776,29 @@ public synchronized RouteBean persist(RouteBean route) { return route; } + private void removeRouteElementsByRouteId(String routeId) { + database.sql("delete from route_elements where route_id =?", routeId).execute(); + } + + private void removeRouteByTileId(String tileId) { + + List routIds = new ArrayList<>(); + List fromRoutes = database.where("from_tile_id = ?", tileId).results(RouteBean.class); + for (RouteBean rb : fromRoutes) { + removeRouteElementsByRouteId(rb.getId()); + routIds.add(rb.getId()); + } + List toRoutes = database.where("to_tile_id = ?", tileId).results(RouteBean.class); + for (RouteBean rb : toRoutes) { + removeRouteElementsByRouteId(rb.getId()); + routIds.add(rb.getId()); + } + + for (String rid : routIds) { + database.sql("delete from routes where id =?", rid).execute(); + } + } + @Override public synchronized void remove(RouteBean route) { if (route.getRouteElements() != null && !route.getRouteElements().isEmpty()) { diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.java b/src/main/java/jcs/ui/layout/LayoutCanvas.java index f50704db..a42424c7 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.java +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.java @@ -282,6 +282,7 @@ private void mouseMoveAction(MouseEvent evt) { } private void mousePressedAction(MouseEvent evt) { + Logger.trace("@ (" + evt.getX() + "," + evt.getY() + ")"); Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); //Clear any previous selection Tile previousSelected = selectedTile; @@ -376,11 +377,12 @@ void removeTile(Tile tile) { } private void mouseDragAction(MouseEvent evt) { + //Logger.trace("@ (" + evt.getX() + "," + evt.getY() + ")"); Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); if (selectedTile != null) { int z = getComponentZOrder(selectedTile); setComponentZOrder(selectedTile, 0); - //Logger.trace("Moving: " + selectedTile.getId() + " @ " + selectedTile.xyToString() + " P: " + snapPoint.x + "," + snapPoint.y + ")"); + Logger.trace("Moving: " + selectedTile.getId() + " @ " + selectedTile.xyToString() + " P: " + snapPoint.x + "," + snapPoint.y + ")"); if (TileCache.canMoveTo(selectedTile, snapPoint)) { selectedTile.setSelectedColor(Tile.DEFAULT_SELECTED_COLOR); @@ -426,7 +428,6 @@ private void mouseDragAction(MouseEvent evt) { } } selectedTile.setBounds(curX, curY, selectedTile.getWidth(), selectedTile.getHeight()); - //this.repaint(selectedTile.getTileBounds()); } } @@ -486,18 +487,6 @@ private void executeControlActionForTile(Tile tile, Point p) { } } -// private void toggleSwitch(Switch turnout) { -// if (turnout.getAccessoryBean() != null) { -// AccessoryBean ab = turnout.getAccessoryBean(); -// ab.toggle(); -// turnout.setAccessoryValue(ab.getAccessoryValue()); -// -// JCS.getJcsCommandStation().switchAccessory(ab, ab.getAccessoryValue()); -// } else { -// Logger.trace("No AccessoryBean configured for Turnout: " + turnout.getId()); -// } -// } - private void toggleSignal(Signal signal) { if (signal.getAccessoryBean() != null) { AccessoryBean ab = signal.getAccessoryBean(); @@ -510,22 +499,6 @@ private void toggleSignal(Signal signal) { } } -// private void toggleSensor(Sensor sensor) { -// SensorBean sb = sensor.getSensorBean(); -// if (sb != null) { -// sb.toggle(); -// sensor.setActive((sb.getStatus() == 1)); -// Logger.trace("id: " + sb.getId() + " state " + sb.getStatus()); -// SensorEvent sensorEvent = new SensorEvent(sb); -// fireFeedbackEvent(sensorEvent); -// } -// } -// private void fireFeedbackEvent(SensorEvent sensorEvent) { -// List acl = JCS.getJcsCommandStation().getFeedbackControllers(); -// for (FeedbackController fbc : acl) { -// fbc.fireSensorEventListeners(sensorEvent); -// } -// } private void editSelectedTileProperties() { //the first tile should be the selected one boolean showProperties = false; @@ -1118,7 +1091,6 @@ private void toggleOutOfOrderMIActionPerformed(ActionEvent evt) {//GEN-FIRST:eve if (currentState != block.getBlockState()) { //getRouteBlockState()) { this.executor.execute(() -> { PersistenceFactory.getService().persist(block.getBlockBean()); - }); } } diff --git a/src/main/java/jcs/ui/layout/LayoutPanelTester.java b/src/main/java/jcs/ui/layout/LayoutPanelTester.java index 21c26fb0..3dbe297b 100644 --- a/src/main/java/jcs/ui/layout/LayoutPanelTester.java +++ b/src/main/java/jcs/ui/layout/LayoutPanelTester.java @@ -42,7 +42,7 @@ public static void main(String args[]) { java.awt.EventQueue.invokeLater(() -> { JFrame f = new JFrame("LayoutPanel Tester"); LayoutPanel layoutPanel = new LayoutPanel(); - f.add(layoutPanel); + f.getContentPane().add(layoutPanel); URL iconUrl = JCS.class.getResource("/media/jcs-train-64.png"); if (iconUrl != null) { diff --git a/src/main/java/jcs/ui/layout/LayoutPanelTesterRO.java b/src/main/java/jcs/ui/layout/LayoutPanelTesterRO.java index 7eb4f2d7..80807bf7 100644 --- a/src/main/java/jcs/ui/layout/LayoutPanelTesterRO.java +++ b/src/main/java/jcs/ui/layout/LayoutPanelTesterRO.java @@ -42,7 +42,7 @@ public static void main(String args[]) { java.awt.EventQueue.invokeLater(() -> { JFrame f = new JFrame("LayoutPanel Tester"); LayoutPanel layoutPanel = new LayoutPanel(true); - f.add(layoutPanel); + f.getContentPane().add(layoutPanel); URL iconUrl = JCS.class.getResource("/media/jcs-train-64.png"); if (iconUrl != null) { diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java index 1c3648ee..9242f325 100755 --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -508,13 +508,6 @@ public void setAccessoryBean(AccessoryBean accessoryBean) { } } -// public AccessoryValue getAccessoryValue() { -// if (this.accessoryValue == null) { -// return AccessoryValue.OFF; -// } else { -// return accessoryValue; -// } -// } public void setAccessoryValue(AccessoryValue value) { model.setAccessoryValue(value); if (accessoryBean != null) { @@ -535,9 +528,6 @@ public void setRouteValue(AccessoryValue value) { repaint(); } -// public AccessoryBean.SignalValue getSignalValue() { -// return signalValue; -// } public void setSignalValue(AccessoryBean.SignalValue signalValue) { model.setSignalValue(signalValue); if (this.accessoryBean != null) { diff --git a/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java b/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java index ba953453..da0c54c4 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java @@ -23,6 +23,7 @@ import java.awt.RadialGradientPaint; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; import java.awt.geom.Ellipse2D; import java.util.Date; import javax.swing.JComponent; @@ -32,8 +33,9 @@ import jcs.ui.layout.tiles.Tile; import jcs.ui.layout.tiles.TileCache; import jcs.ui.layout.tiles.TileModel; +import org.tinylog.Logger; -public class SensorUI extends StraightUI implements MouseListener { +public class SensorUI extends StraightUI implements MouseListener, MouseMotionListener { public SensorUI() { } @@ -46,12 +48,14 @@ public static ComponentUI createUI(JComponent c) { public void installUI(JComponent c) { Tile tile = (Tile) c; tile.addMouseListener(this); + tile.addMouseMotionListener(this); } @Override public void uninstallUI(JComponent c) { Tile tile = (Tile) c; tile.removeMouseListener(this); + tile.removeMouseMotionListener(this); } private void renderSensor(Graphics2D g2, JComponent c) { @@ -86,21 +90,8 @@ public void renderTile(Graphics2D g2, JComponent c) { @Override public void mousePressed(MouseEvent e) { - //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); - redispatchToParent(e); - } - - @Override - public void mouseReleased(MouseEvent e) { - //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); - redispatchToParent(e); - } - - @Override - public void mouseClicked(MouseEvent e) { - //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); + //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + "," + e.getYOnScreen() + ")"); //Only JCS is in CONTROL mode (readonly) activate sensor action events. - if (isControlMode((Component) e.getSource()) && e.getButton() == MouseEvent.BUTTON1) { Tile tile = (Tile) e.getSource(); tile.setActive(!tile.isActive()); @@ -116,6 +107,18 @@ public void mouseClicked(MouseEvent e) { } } + @Override + public void mouseReleased(MouseEvent e) { + //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + "," + e.getYOnScreen() + ")"); + redispatchToParent(e); + } + + @Override + public void mouseClicked(MouseEvent e) { + //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + "," + e.getYOnScreen()); + redispatchToParent(e); + } + @Override public void mouseEntered(MouseEvent e) { //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); @@ -137,4 +140,16 @@ public void mouseExited(MouseEvent e) { redispatchToParent(e); } + @Override + public void mouseDragged(MouseEvent e) { + //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + "," + e.getYOnScreen()); + redispatchToParent(e); + } + + @Override + public void mouseMoved(MouseEvent e) { + //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + "," + e.getYOnScreen()); + redispatchToParent(e); + } + } diff --git a/src/main/java/jcs/ui/layout/tiles/ui/SignalUI.java b/src/main/java/jcs/ui/layout/tiles/ui/SignalUI.java index a312bc55..d15db642 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/SignalUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/SignalUI.java @@ -17,10 +17,15 @@ import java.awt.BasicStroke; import java.awt.Color; +import java.awt.Component; import java.awt.Graphics2D; import java.awt.Polygon; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; import javax.swing.JComponent; import javax.swing.plaf.ComponentUI; +import jcs.commandStation.events.AccessoryEvent; import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.SignalType; import static jcs.entities.AccessoryBean.SignalType.HP012; @@ -32,9 +37,11 @@ import static jcs.entities.AccessoryBean.SignalValue.Hp1; import static jcs.entities.AccessoryBean.SignalValue.Hp2; import jcs.ui.layout.tiles.Tile; +import jcs.ui.layout.tiles.TileCache; import jcs.ui.layout.tiles.TileModel; +import org.tinylog.Logger; -public class SignalUI extends StraightUI { +public class SignalUI extends StraightUI implements MouseListener, MouseMotionListener { public SignalUI() { } @@ -43,6 +50,20 @@ public static ComponentUI createUI(JComponent c) { return new SignalUI(); } + @Override + public void installUI(JComponent c) { + Tile tile = (Tile) c; + tile.addMouseListener(this); + tile.addMouseMotionListener(this); + } + + @Override + public void uninstallUI(JComponent c) { + Tile tile = (Tile) c; + tile.removeMouseListener(this); + tile.removeMouseMotionListener(this); + } + /** * Render a Signal with 2 lights * @@ -327,4 +348,63 @@ public void renderTile(Graphics2D g2, JComponent c) { g2d.dispose(); } + @Override + public void mousePressed(MouseEvent e) { + //Only JCS is in CONTROL mode (readonly) activate accessory action events. + if (isControlMode((Component) e.getSource()) && e.getButton() == MouseEvent.BUTTON1) { + Tile tile = (Tile) e.getSource(); + tile.setActive(!tile.isActive()); + + if (tile.getAccessoryBean() != null) { + AccessoryBean ab = tile.getAccessoryBean(); + ab.toggle(); + tile.setSignalValue(ab.getSignalValue()); + + AccessoryEvent aae = new AccessoryEvent(ab); + TileCache.enqueTileAction(aae); + Logger.trace("Changing Tile " + tile.getId() + " Accessory " + ab.getId() + " to " + ab.getSignalValue().getSignalValue() + "..."); + } + } else { + redispatchToParent(e); + } + } + + @Override + public void mouseReleased(MouseEvent e) { + redispatchToParent(e); + } + + @Override + public void mouseClicked(MouseEvent e) { + redispatchToParent(e); + } + + @Override + public void mouseEntered(MouseEvent e) { + Tile tile = (Tile) e.getSource(); + String toolTipText = tile.getId(); + if (tile.getAccessoryBean() != null) { + toolTipText = toolTipText + "; Id: " + tile.getAccessoryBean().getId(); + } + tile.setToolTipText(toolTipText); + redispatchToParent(e); + } + + @Override + public void mouseExited(MouseEvent e) { + Tile tile = (Tile) e.getSource(); + tile.setToolTipText(null); + redispatchToParent(e); + } + + @Override + public void mouseDragged(MouseEvent e) { + redispatchToParent(e); + } + + @Override + public void mouseMoved(MouseEvent e) { + redispatchToParent(e); + } + } diff --git a/src/main/java/jcs/ui/layout/tiles/ui/SwitchUI.java b/src/main/java/jcs/ui/layout/tiles/ui/SwitchUI.java index 598719d9..b12cb799 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/SwitchUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/SwitchUI.java @@ -21,6 +21,7 @@ import java.awt.Graphics2D; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; import javax.swing.JComponent; import javax.swing.plaf.ComponentUI; import jcs.commandStation.events.AccessoryEvent; @@ -34,7 +35,7 @@ import jcs.ui.layout.tiles.TileModel; import org.tinylog.Logger; -public class SwitchUI extends TileUI implements MouseListener { +public class SwitchUI extends TileUI implements MouseListener, MouseMotionListener { public SwitchUI() { } @@ -47,12 +48,14 @@ public static ComponentUI createUI(JComponent c) { public void installUI(JComponent c) { Tile tile = (Tile) c; tile.addMouseListener(this); + tile.addMouseMotionListener(this); } @Override public void uninstallUI(JComponent c) { Tile tile = (Tile) c; tile.removeMouseListener(this); + tile.removeMouseMotionListener(this); } protected void renderStraight(Graphics2D g2, Color color, JComponent c) { @@ -164,19 +167,6 @@ public void renderTileRoute(Graphics2D g2, JComponent c) { @Override public void mousePressed(MouseEvent e) { - //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); - redispatchToParent(e); - } - - @Override - public void mouseReleased(MouseEvent e) { - //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); - redispatchToParent(e); - } - - @Override - public void mouseClicked(MouseEvent e) { - //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); //Only JCS is in CONTROL mode (readonly) activate accessory action events. if (isControlMode((Component) e.getSource()) && e.getButton() == MouseEvent.BUTTON1) { Tile tile = (Tile) e.getSource(); @@ -196,16 +186,24 @@ public void mouseClicked(MouseEvent e) { } } + @Override + public void mouseReleased(MouseEvent e) { + redispatchToParent(e); + } + + @Override + public void mouseClicked(MouseEvent e) { + redispatchToParent(e); + } + @Override public void mouseEntered(MouseEvent e) { - //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); Tile tile = (Tile) e.getSource(); String toolTipText = tile.getId(); if (tile.getAccessoryBean() != null) { toolTipText = toolTipText + "; Id: " + tile.getAccessoryBean().getId(); } tile.setToolTipText(toolTipText); - redispatchToParent(e); } @@ -217,4 +215,16 @@ public void mouseExited(MouseEvent e) { redispatchToParent(e); } + @Override + public void mouseDragged(MouseEvent e) { + //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + "," + e.getYOnScreen()); + redispatchToParent(e); + } + + @Override + public void mouseMoved(MouseEvent e) { + //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + "," + e.getYOnScreen()); + redispatchToParent(e); + } + } diff --git a/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java b/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java index 039988b6..3ba5bec9 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java @@ -20,6 +20,7 @@ import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Insets; +import java.awt.Point; import java.awt.event.MouseEvent; import java.awt.geom.AffineTransform; import java.awt.geom.Ellipse2D; @@ -32,6 +33,7 @@ import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.ui.layout.LayoutCanvas; +import jcs.ui.layout.LayoutUtil; import jcs.ui.layout.tiles.Tile; import static jcs.ui.layout.tiles.Tile.DEFAULT_BACKGROUND_COLOR; import static jcs.ui.layout.tiles.Tile.DEFAULT_TRACK_COLOR; @@ -263,7 +265,7 @@ public void paint(Graphics g, JComponent c) { g.drawImage(tileImage, 0, 0, null); g.translate(-insets.left, -insets.top); - if (Logger.isTraceEnabled()) { + if (Logger.isTraceEnabled() && 1 == 2) { Tile tile = (Tile) c; TileModel model = tile.getModel(); long now = System.currentTimeMillis(); @@ -273,8 +275,10 @@ public void paint(Graphics g, JComponent c) { protected void redispatchToParent(MouseEvent e) { Component source = (Component) e.getSource(); - MouseEvent parentEvent = SwingUtilities.convertMouseEvent(source, e, source.getParent()); - source.getParent().dispatchEvent(parentEvent); + Point cp = SwingUtilities.convertPoint(source, e.getPoint(), source.getParent()); + MouseEvent me = new MouseEvent(source, e.getID(), e.getWhen(), e.getModifiersEx(), cp.x, cp.y, e.getClickCount(), e.isPopupTrigger(), e.getButton()); + //Logger.trace("ME @ (" + me.getXOnScreen() + "," + me.getYOnScreen() + ") PE @ (" + cp.x + "," + cp.y + ")"); + source.getParent().dispatchEvent(me); } protected boolean isControlMode(Component c) { From f49924043051e94a6db6884e6acba3e57c872c96 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Wed, 12 Feb 2025 20:54:04 +0100 Subject: [PATCH 20/70] Autopilot is working more or less with some issues --- .../commandStation/autopilot/AutoPilot.java | 50 +++-- .../autopilot/state/Dispatcher.java | 42 ++-- .../autopilot/state/EnterBlockState.java | 14 +- .../autopilot/state/PrepareRouteState.java | 2 +- src/main/java/jcs/ui/JCSFrame.form | 10 +- src/main/java/jcs/ui/JCSFrame.java | 11 +- src/main/java/jcs/ui/layout/LayoutCanvas.java | 92 +++------ src/main/java/jcs/ui/layout/LayoutPanel.form | 6 +- src/main/java/jcs/ui/layout/LayoutPanel.java | 4 +- .../ui/layout/dialogs/BlockControlDialog.java | 174 +++++++++-------- .../jcs/ui/layout/tiles/DefaultTileModel.java | 35 +++- src/main/java/jcs/ui/layout/tiles/Tile.java | 38 +++- .../java/jcs/ui/layout/tiles/TileCache.java | 179 ++++++++++-------- .../java/jcs/ui/layout/tiles/TileModel.java | 2 + .../java/jcs/ui/layout/tiles/ui/BlockUI.java | 3 - 15 files changed, 356 insertions(+), 306 deletions(-) diff --git a/src/main/java/jcs/commandStation/autopilot/AutoPilot.java b/src/main/java/jcs/commandStation/autopilot/AutoPilot.java index d31d1637..ec8f7415 100644 --- a/src/main/java/jcs/commandStation/autopilot/AutoPilot.java +++ b/src/main/java/jcs/commandStation/autopilot/AutoPilot.java @@ -37,13 +37,15 @@ import jcs.entities.RouteBean; import jcs.entities.SensorBean; import jcs.persistence.PersistenceFactory; +import jcs.ui.layout.tiles.Tile; import jcs.ui.layout.tiles.TileCache; -import jcs.ui.layout.events.TileEvent; import org.tinylog.Logger; /** - * - * @author frans + * The AutoPilot is the "automatic driving engine".
+ * Every Locomotive on the track will start it own Thread.
+ * The Dispatcher is run in this Thread.
+ * The AutoPilot has it own Monitor Thread: AutoPilotThread. * */ public final class AutoPilot { @@ -52,9 +54,7 @@ public final class AutoPilot { private static CommandStationBean commandStationBean; - //private final Map sensorHandlers = Collections.synchronizedMap(new HashMap<>()); private static final Map sensorHandlers = new HashMap<>(); - //private final Map dispatchers = Collections.synchronizedMap(new HashMap<>()); private static final Map dispatchers = new HashMap<>(); //Need a list to be able to unregister @@ -289,6 +289,7 @@ public static void resetStates() { int freeBlockCounter = 0; List blocks = PersistenceFactory.getService().getBlocks(); for (BlockBean block : blocks) { + Tile tile = TileCache.findTile(block.getTileId()); if (block.getLocomotiveId() != null) { if (null == block.getBlockState()) { if (BlockBean.BlockState.OCCUPIED == block.getBlockState()) { @@ -298,35 +299,33 @@ public static void resetStates() { switch (block.getBlockState()) { case LOCKED, INBOUND -> { //destinations block, reset! - block.setLocomotive(null); - block.setBlockState(BlockBean.BlockState.FREE); - block.setArrivalSuffix(null); + tile.setLocomotive(null); + //block.setLocomotive(null); + tile.setBlockState(BlockBean.BlockState.FREE); + tile.setArrivalSuffix(null); freeBlockCounter++; } case OUTBOUND -> { - block.setBlockState(BlockBean.BlockState.OCCUPIED); - block.setArrivalSuffix(null); + tile.setBlockState(BlockBean.BlockState.OCCUPIED); + tile.setArrivalSuffix(null); occupiedBlockCounter++; } default -> { if (BlockBean.BlockState.OCCUPIED == block.getBlockState()) { - block.setArrivalSuffix(null); + tile.setArrivalSuffix(null); occupiedBlockCounter++; } } } } } else { - block.setBlockState(BlockBean.BlockState.FREE); + tile.setBlockState(BlockBean.BlockState.FREE); freeBlockCounter++; } - PersistenceFactory.getService().persist(block); - TileEvent tileEvent = new TileEvent(block); - //TileCache.fireTileEventListener(tileEvent); + PersistenceFactory.getService().persist(tile.getBlockBean()); } JCS.getJcsCommandStation().switchPower(true); - Logger.debug("Occupied blocks: " + occupiedBlockCounter + " Free blocks " + freeBlockCounter + " of total " + blocks.size() + " blocks"); } @@ -368,12 +367,12 @@ public static List getOnTrackLocomotives() { } } - //if (Logger.isDebugEnabled()) { - // Logger.trace("There are " + activeLocomotives.size() + " Locomotives on the track: "); - for (LocomotiveBean loc : activeLocomotives) { - Logger.trace(loc); + if (Logger.isTraceEnabled()) { + // Logger.trace("There are " + activeLocomotives.size() + " Locomotives on the track: "); + for (LocomotiveBean loc : activeLocomotives) { + Logger.trace(loc); + } } - //} return new ArrayList<>(activeLocomotives); } @@ -392,29 +391,28 @@ private static void handleGhost(SensorEvent event) { List blocks = PersistenceFactory.getService().getBlocks(); String sensorId = event.getId(); for (BlockBean block : blocks) { + Tile tile = TileCache.findTile(block.getTileId()); + if ((block.getMinSensorId().equals(sensorId) || block.getPlusSensorId().equals(sensorId)) && block.getLocomotiveId() == null) { if (event.getSensorBean().isActive()) { block.setBlockState(BlockBean.BlockState.GHOST); + tile.setBlockState(BlockBean.BlockState.GHOST); //Also persist PersistenceFactory.getService().persist(block); - Logger.warn("Ghost Detected! @ Sensor " + sensorId + " in block " + block.getId()); //Switch power OFF! JCS.getJcsCommandStation().switchPower(false); - - TileEvent tileEvent = new TileEvent(block); - //TileCache.fireTileEventListener(tileEvent); } else { if (block.getLocomotiveId() != null) { //keep state as is } else { block.setBlockState(BlockBean.BlockState.FREE); + tile.setBlockState(BlockBean.BlockState.FREE); } } break; } } - } static void handleSensorEvent(SensorEvent event) { diff --git a/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java b/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java index 715e54dc..0c06c18e 100644 --- a/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java +++ b/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java @@ -34,6 +34,7 @@ import jcs.persistence.PersistenceFactory; import jcs.ui.layout.tiles.TileCache; import jcs.ui.layout.events.TileEvent; +import jcs.ui.layout.tiles.Tile; import org.tinylog.Logger; /** @@ -189,7 +190,7 @@ BlockBean getDepartureBlock() { return PersistenceFactory.getService().getBlockByTileId(departureBlockId); } else { BlockBean departureBlock = PersistenceFactory.getService().getBlockByLocomotiveId(locomotiveBean.getId()); - this.departureBlockId = departureBlock.getTileId(); + departureBlockId = departureBlock.getTileId(); return departureBlock; } } @@ -289,7 +290,6 @@ public void onIgnoreEvent(SensorEvent event) { this.exitSensorId = null; } } - } //Logger.trace("Event for a ignored listener: " + event.getId() + " Changed: " + event.isChanged() + ", active: " + event.getSensorBean().isActive()); } @@ -326,32 +326,52 @@ public static void resetRoute(RouteBean route) { List routeElements = route.getRouteElements(); for (RouteElementBean re : routeElements) { String tileId = re.getTileId(); - TileEvent tileEvent = new TileEvent(tileId, false); - //TileCache.fireTileEventListener(tileEvent); + Tile tile = TileCache.findTile(tileId); + + if (tile.isBlock()) { + if (tile.getLocomotive() != null) { + tile.setBlockState(BlockBean.BlockState.OCCUPIED); + } else { + tile.setBlockState(BlockBean.BlockState.FREE); + } + } + if (tile.isJunction()) { + tile.setRouteValue(AccessoryBean.AccessoryValue.OFF); + } + tile.setShowRoute(false); } } void showBlockState(BlockBean blockBean) { Logger.trace("Show block " + blockBean); - TileEvent tileEvent = new TileEvent(blockBean); - //TileCache.fireTileEventListener(tileEvent); + Tile tile = TileCache.findTile(blockBean.getTileId()); + tile.setBlockBean(blockBean); } void showRoute(RouteBean routeBean, Color routeColor) { Logger.trace("Show route " + routeBean.toLogString()); List routeElements = routeBean.getRouteElements(); + for (RouteElementBean re : routeElements) { String tileId = re.getTileId(); TileBean.Orientation incomingSide = re.getIncomingOrientation(); - TileEvent tileEvent; + Tile tile = TileCache.findTile(tileId); + tile.setIncomingSide(incomingSide); + tile.setTrackRouteColor(Tile.DEFAULT_ROUTE_TRACK_COLOR); + if (re.isTurnout()) { AccessoryBean.AccessoryValue routeState = re.getAccessoryValue(); - tileEvent = new TileEvent(tileId, true, incomingSide, routeState, routeColor); - } else { - tileEvent = new TileEvent(tileId, true, incomingSide, routeColor); + tile.setRouteValue(routeState); + } else if (re.isBlock()) { + if (re.getTileId().equals(routeBean.getFromTileId())) { + //departure block + tile.setBlockState(BlockBean.BlockState.OUTBOUND); + } else { + tile.setBlockState(BlockBean.BlockState.INBOUND); + } } - //TileCache.fireTileEventListener(tileEvent); + tile.setShowRoute(true); } } diff --git a/src/main/java/jcs/commandStation/autopilot/state/EnterBlockState.java b/src/main/java/jcs/commandStation/autopilot/state/EnterBlockState.java index 1d21e6aa..18583f41 100644 --- a/src/main/java/jcs/commandStation/autopilot/state/EnterBlockState.java +++ b/src/main/java/jcs/commandStation/autopilot/state/EnterBlockState.java @@ -32,7 +32,6 @@ class EnterBlockState extends DispatcherState implements SensorEventListener { private boolean locomotiveBraking = false; private boolean canAdvanceToNextState = false; private String inSensorId; - //private Dispatcher dispatcher; @Override DispatcherState execute(Dispatcher dispatcher) { @@ -53,7 +52,6 @@ DispatcherState execute(Dispatcher dispatcher) { dispatcher.setWaitForSensorid(inSensorId); //Register this state as a SensorEventListener - //this.dispatcher = dispatcher; JCS.getJcsCommandStation().addSensorEventListener(this); Logger.trace("Destination block " + destinationBlock.getId() + " In SensorId: " + inSensorId); @@ -67,19 +65,16 @@ DispatcherState execute(Dispatcher dispatcher) { destinationBlock.setBlockState(BlockBean.BlockState.INBOUND); PersistenceFactory.getService().persist(departureBlock); + PersistenceFactory.getService().persist(destinationBlock); + dispatcher.showBlockState(departureBlock); - dispatcher.showRoute(route, Color.magenta); - - PersistenceFactory.getService().persist(destinationBlock); dispatcher.showBlockState(destinationBlock); //Switch the departure block sensors on again - //dispatcher.clearDepartureIgnoreEventHandlers(); - - //dispatcher.setOccupationSensorId(null); + //dispatcher.clearDepartureIgnoreEventHandlers(); + //dispatcher.setOccupationSensorId(null); //dispatcher.setExitSensorId(null); - Logger.trace("Now Waiting for the IN event from SensorId: " + this.inSensorId + " Running loco: " + locomotive.getName() + " [" + locomotive.getDecoderType().getDecoderType() + " (" + locomotive.getAddress() + ")] Direction: " + locomotive.getDirection().getDirection() + " current velocity: " + locomotive.getVelocity()); } @@ -117,5 +112,4 @@ public void onSensorChange(SensorEvent sensorEvent) { } } } - } diff --git a/src/main/java/jcs/commandStation/autopilot/state/PrepareRouteState.java b/src/main/java/jcs/commandStation/autopilot/state/PrepareRouteState.java index c23b62e2..55ea53c3 100644 --- a/src/main/java/jcs/commandStation/autopilot/state/PrepareRouteState.java +++ b/src/main/java/jcs/commandStation/autopilot/state/PrepareRouteState.java @@ -103,7 +103,7 @@ boolean searchRoute(Dispatcher dispatcher) { Direction newDirection = LocomotiveBean.toggle(oldDirection); Logger.trace("Reversing Locomotive, from " + oldDirection + " to " + newDirection + "..."); - this.swapLocomotiveDirection = true; + swapLocomotiveDirection = true; //Do NOT persist the direction yet, just test.... //locomotive.setDispatcherDirection(newDirection); departureBlock.setLogicalDirection(newDirection.getDirection()); diff --git a/src/main/java/jcs/ui/JCSFrame.form b/src/main/java/jcs/ui/JCSFrame.form index 65291d38..4da3c4b3 100755 --- a/src/main/java/jcs/ui/JCSFrame.form +++ b/src/main/java/jcs/ui/JCSFrame.form @@ -172,6 +172,9 @@ + + + @@ -181,11 +184,6 @@ - - - - - @@ -195,7 +193,7 @@ - + diff --git a/src/main/java/jcs/ui/JCSFrame.java b/src/main/java/jcs/ui/JCSFrame.java index 8db050af..4988a9c7 100755 --- a/src/main/java/jcs/ui/JCSFrame.java +++ b/src/main/java/jcs/ui/JCSFrame.java @@ -162,13 +162,14 @@ public void actionPerformed(ActionEvent e) { public void showExtraToolbar(JToolBar toolbar) { this.jcsToolBar.add(toolbar); jcsToolBar.doLayout(); - this.repaint(); + this.toolbarPanel.repaint(); } public void hideExtraToolbar(JToolBar toolbar) { this.jcsToolBar.remove(toolbar); jcsToolBar.doLayout(); - this.repaint(); + this.toolbarPanel.repaint(); + //this.repaint(); } public void showOverviewPanel() { @@ -336,18 +337,16 @@ public void windowClosing(WindowEvent evt) { }); toolbarPanel.setName("toolbarPanel"); // NOI18N + toolbarPanel.setPreferredSize(new Dimension(1350, 52)); FlowLayout flowLayout8 = new FlowLayout(FlowLayout.LEFT); flowLayout8.setAlignOnBaseline(true); toolbarPanel.setLayout(flowLayout8); - jcsToolBar.setBorderPainted(false); - jcsToolBar.setDoubleBuffered(true); - jcsToolBar.setMargin(new Insets(1, 1, 1, 1)); jcsToolBar.setMaximumSize(new Dimension(1050, 42)); jcsToolBar.setMinimumSize(new Dimension(1000, 42)); jcsToolBar.setName("ToolBar"); // NOI18N jcsToolBar.setOpaque(false); - jcsToolBar.setPreferredSize(new Dimension(1300, 42)); + jcsToolBar.setPreferredSize(new Dimension(1380, 42)); connectButton.setIcon(new ImageIcon(getClass().getResource("/media/monitor-off-24.png"))); // NOI18N connectButton.setToolTipText("Connect/Disconnect with Central Station"); diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.java b/src/main/java/jcs/ui/layout/LayoutCanvas.java index a42424c7..daad3415 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.java +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.java @@ -37,9 +37,7 @@ import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.SwingUtilities; -import jcs.JCS; import jcs.commandStation.autopilot.AutoPilot; -import jcs.entities.AccessoryBean; import jcs.entities.BlockBean; import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; @@ -121,7 +119,6 @@ public LayoutCanvas(boolean readonly) { setDoubleBuffered(true); this.readonly = readonly; -// this.selectedRouteElements = new HashMap<>(); this.executor = Executors.newSingleThreadExecutor(); //this.executor = Executors.newCachedThreadPool(); @@ -433,23 +430,10 @@ private void mouseDragAction(MouseEvent evt) { private void mouseReleasedAction(MouseEvent evt) { Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); - //if (selectedTile != null) { - // Logger.trace(selectedTile.getId() + " sp: (" + snapPoint.x + "," + snapPoint.y + ")"); - //} else { - // Logger.trace("No Tile @ (" + snapPoint.x + "," + snapPoint.y + ")"); - //} - if (!Mode.CONTROL.equals(mode) && MouseEvent.BUTTON1 == evt.getButton() && selectedTile != null) { if (TileCache.canMoveTo(selectedTile, snapPoint)) { TileCache.moveTo(selectedTile, snapPoint); } else { - //Tile occ = TileCache.findTile(snapPoint); - //String occtile = ""; - //if (occ != null) { - // occtile = " Is occupied by " + occ.getId(); - //} - //Logger.trace("Can't Move tile " + selectedTile.getId() + " from " + selectedTile.xyToString() + " to (" + snapPoint.x + "," + snapPoint.y + ")" + occtile); - selectedTile.setSelectedColor(Tile.DEFAULT_SELECTED_COLOR); selectedTile.setBounds(selectedTile.getTileBounds()); } @@ -472,6 +456,9 @@ private void executeControlActionForTile(Tile tile, Point p) { Block block = (Block) tile; BlockControlDialog bcd = new BlockControlDialog(getParentFrame(), block); bcd.setVisible(true); + + Logger.trace("Block properties closed"); + this.repaint(block.getTileBounds()); } case SIGNAL -> { //this.executor.execute(() -> toggleSignal((Signal) tile)); @@ -487,18 +474,6 @@ private void executeControlActionForTile(Tile tile, Point p) { } } - private void toggleSignal(Signal signal) { - if (signal.getAccessoryBean() != null) { - AccessoryBean ab = signal.getAccessoryBean(); - ab.toggle(); - Logger.trace("A: " + ab.getAddress() + " S: " + ab.getStates() + " P: " + ab.getState()); - - JCS.getJcsCommandStation().switchAccessory(ab, ab.getAccessoryValue()); - } else { - Logger.trace("No AccessoryBean configured for Signal: " + signal.getId()); - } - } - private void editSelectedTileProperties() { //the first tile should be the selected one boolean showProperties = false; @@ -678,19 +653,19 @@ void routeLayout() { private void routeLayoutWithAStar() { //Make sure the layout is saved - TileCache.saveTiles(); + TileCache.persistAllTiles(); AStar astar = new AStar(); astar.buildGraph(TileCache.getTiles()); astar.routeAll(); astar.persistRoutes(); - if (this.routesDialog.isVisible()) { - this.routesDialog.loadRoutes(); + if (routesDialog.isVisible()) { + routesDialog.loadRoutes(); } } void showRoutesDialog() { - this.routesDialog.setVisible(true); + routesDialog.setVisible(true); } /** @@ -983,20 +958,16 @@ private void formMouseDragged(MouseEvent evt) {//GEN-FIRST:event_formMouseDragge private void startLocomotiveMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_startLocomotiveMIActionPerformed if (this.selectedTile != null) { Block block = (Block) selectedTile; - LocomotiveBean locomotive = block.getBlockBean().getLocomotive(); - - this.executor.execute(() -> AutoPilot.startStopLocomotive(locomotive, true)); - repaint(); + LocomotiveBean locomotive = block.getLocomotive(); + executor.execute(() -> AutoPilot.startStopLocomotive(locomotive, true)); } }//GEN-LAST:event_startLocomotiveMIActionPerformed private void stopLocomotiveMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_stopLocomotiveMIActionPerformed - if (this.selectedTile != null) { + if (selectedTile != null) { Block block = (Block) selectedTile; - LocomotiveBean locomotive = block.getBlockBean().getLocomotive(); - - this.executor.execute(() -> AutoPilot.startStopLocomotive(locomotive, false)); - repaint(); + LocomotiveBean locomotive = block.getLocomotive(); + executor.execute(() -> AutoPilot.startStopLocomotive(locomotive, false)); } }//GEN-LAST:event_stopLocomotiveMIActionPerformed @@ -1013,19 +984,16 @@ private void resetDispatcherMIActionPerformed(ActionEvent evt) {//GEN-FIRST:even }//GEN-LAST:event_resetDispatcherMIActionPerformed private void removeLocMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_removeLocMIActionPerformed - if (this.selectedTile != null) { + if (selectedTile != null) { Block block = (Block) selectedTile; - LocomotiveBean locomotive = block.getBlockBean().getLocomotive(); + LocomotiveBean locomotive = block.getLocomotive(); locomotive.setDispatcherDirection(null); - block.getBlockBean().setLocomotive(null); - block.setBlockState(BlockState.FREE); - block.getBlockBean().setArrivalSuffix(null); + block.setLocomotive(null); - this.executor.execute(() -> { + executor.execute(() -> { PersistenceFactory.getService().persist(block.getBlockBean()); PersistenceFactory.getService().persist(locomotive); - repaint(); }); } }//GEN-LAST:event_removeLocMIActionPerformed @@ -1036,8 +1004,7 @@ private void blockPropertiesMIActionPerformed(ActionEvent evt) {//GEN-FIRST:even Block block = (Block) selectedTile; BlockControlDialog bcd = new BlockControlDialog(getParentFrame(), block); bcd.setVisible(true); - - this.repaint(block.getX(), block.getY(), block.getWidth(), block.getHeight()); + repaint(block.getTileBounds()); } }//GEN-LAST:event_blockPropertiesMIActionPerformed @@ -1045,13 +1012,13 @@ private void reverseArrivalSideMIActionPerformed(ActionEvent evt) {//GEN-FIRST:e if (this.selectedTile != null) { Block block = (Block) selectedTile; - String suffix = block.getBlockBean().getArrivalSuffix(); + String suffix = block.getArrivalSuffix(); if ("+".equals(suffix)) { - block.getBlockBean().setArrivalSuffix("-"); + block.setArrivalSuffix("-"); } else { - block.getBlockBean().setArrivalSuffix("+"); + block.setArrivalSuffix("+"); } - block.getBlockBean().setReverseArrival(!block.getBlockBean().isReverseArrival()); + block.setReverseArrival(!block.isReverseArrival()); this.executor.execute(() -> { PersistenceFactory.getService().persist(block.getBlockBean()); }); @@ -1059,18 +1026,19 @@ private void reverseArrivalSideMIActionPerformed(ActionEvent evt) {//GEN-FIRST:e }//GEN-LAST:event_reverseArrivalSideMIActionPerformed private void toggleLocomotiveDirectionMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_toggleLocomotiveDirectionMIActionPerformed - if (this.selectedTile != null) { + if (selectedTile != null) { Block block = (Block) selectedTile; - LocomotiveBean locomotive = block.getBlockBean().getLocomotive(); + LocomotiveBean locomotive = block.getLocomotive(); + LocomotiveBean.Direction curDir; - if (block.getBlockBean().getLogicalDirection() != null) { - curDir = LocomotiveBean.Direction.get(block.getBlockBean().getLogicalDirection()); + if (block.getLogicalDirection() != null) { + curDir = block.getLogicalDirection(); } else { curDir = locomotive.getDirection(); } LocomotiveBean.Direction newDir = LocomotiveBean.toggle(curDir); - block.getBlockBean().setLogicalDirection(newDir.getDirection()); - Logger.trace(block.getId() + " Logical changed from " + curDir + " to " + newDir + " for " + locomotive.getName()); + block.setLogicalDirection(newDir); + Logger.trace(block.getId() + " LogicalDir changed from " + curDir + " to " + newDir + " for " + locomotive.getName()); this.executor.execute(() -> { PersistenceFactory.getService().persist(block.getTileBean()); @@ -1088,7 +1056,7 @@ private void toggleOutOfOrderMIActionPerformed(ActionEvent evt) {//GEN-FIRST:eve block.setBlockState(BlockState.FREE); } - if (currentState != block.getBlockState()) { //getRouteBlockState()) { + if (currentState != block.getBlockState()) { this.executor.execute(() -> { PersistenceFactory.getService().persist(block.getBlockBean()); }); @@ -1102,7 +1070,7 @@ private void resetGhostMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_res BlockBean.BlockState currentState = block.getBlockState(); if (BlockBean.BlockState.GHOST == currentState) { - if (block.getBlockBean().getLocomotiveId() != null) { + if (block.getLocomotive() != null) { block.setBlockState(BlockBean.BlockState.OCCUPIED); } else { block.setBlockState(BlockBean.BlockState.FREE); diff --git a/src/main/java/jcs/ui/layout/LayoutPanel.form b/src/main/java/jcs/ui/layout/LayoutPanel.form index 158b41a2..1942d961 100755 --- a/src/main/java/jcs/ui/layout/LayoutPanel.form +++ b/src/main/java/jcs/ui/layout/LayoutPanel.form @@ -163,10 +163,6 @@ - - - - @@ -175,7 +171,7 @@ - + diff --git a/src/main/java/jcs/ui/layout/LayoutPanel.java b/src/main/java/jcs/ui/layout/LayoutPanel.java index df6383c0..20ae29ef 100755 --- a/src/main/java/jcs/ui/layout/LayoutPanel.java +++ b/src/main/java/jcs/ui/layout/LayoutPanel.java @@ -336,12 +336,10 @@ public void componentShown(ComponentEvent evt) { flowLayout1.setAlignOnBaseline(true); topPanel.setLayout(flowLayout1); - toolBar.setDoubleBuffered(true); - toolBar.setMargin(new Insets(1, 1, 1, 1)); toolBar.setMaximumSize(new Dimension(1200, 42)); toolBar.setMinimumSize(new Dimension(1150, 42)); toolBar.setName(""); // NOI18N - toolBar.setPreferredSize(new Dimension(1100, 42)); + toolBar.setPreferredSize(new Dimension(1000, 42)); loadBtn.setIcon(new ImageIcon(getClass().getResource("/media/load-24.png"))); // NOI18N loadBtn.setToolTipText("Load"); diff --git a/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java b/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java index 3ea13750..22d0953c 100644 --- a/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java +++ b/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java @@ -24,18 +24,17 @@ import jcs.entities.BlockBean; import jcs.entities.LocomotiveBean; import jcs.persistence.PersistenceFactory; -import jcs.ui.layout.events.TileEvent; import jcs.ui.layout.tiles.Block; +import jcs.ui.layout.tiles.TileCache; import org.tinylog.Logger; /** * - * @author fransjacobs */ public class BlockControlDialog extends javax.swing.JDialog { - + private final Block block; - + private ComboBoxModel locomotiveComboBoxModel; /** @@ -48,25 +47,26 @@ public BlockControlDialog(java.awt.Frame parent, Block block) { super(parent, true); this.block = block; initComponents(); - + postInit(); } - + private void postInit() { setLocationRelativeTo(null); - String text = this.headingLbl.getText() + " " + this.block.getId(); - this.headingLbl.setText(text); - - if (this.block != null) { + if (block != null) { + String text = headingLbl.getText() + " " + block.getId(); + headingLbl.setText(text); + List locos = new LinkedList<>(); LocomotiveBean emptyBean = new LocomotiveBean(); locos.add(emptyBean); locos.addAll(PersistenceFactory.getService().getLocomotives(true)); + //Only Loc's which should be shown locomotiveComboBoxModel = new DefaultComboBoxModel(locos.toArray()); - this.locomotiveCB.setModel(locomotiveComboBoxModel); - - BlockBean bb = this.block.getBlockBean(); + locomotiveCB.setModel(locomotiveComboBoxModel); + + BlockBean bb = block.getBlockBean(); if (bb == null) { bb = PersistenceFactory.getService().getBlockByTileId(block.getId()); if (bb == null) { @@ -79,55 +79,55 @@ private void postInit() { bb.setMaxWaitTime(0); bb.setMinWaitTime(10); } - this.block.setBlockBean(bb); + block.setBlockBean(bb); } - - this.blockIdTF.setText(block.getId()); - this.blockNameTF.setText(bb.getDescription()); - + + blockIdTF.setText(block.getId()); + blockNameTF.setText(bb.getDescription()); + if (bb.getLocomotiveId() != null && bb.getLocomotive() == null) { bb.setLocomotive(PersistenceFactory.getService().getLocomotive(bb.getLocomotiveId())); - this.startLocButton.setEnabled(true); + startLocButton.setEnabled(true); } - + if (bb.getMinWaitTime() != null) { - this.minWaitSpinner.setValue(bb.getMinWaitTime()); + minWaitSpinner.setValue(bb.getMinWaitTime()); } - + if (bb.getMaxWaitTime() != null) { - this.maxWaitSpinner.setValue(bb.getMaxWaitTime()); + maxWaitSpinner.setValue(bb.getMaxWaitTime()); } - - this.alwaysStopCB.setSelected(bb.isAlwaysStop()); - this.randomWaitCB.setSelected(bb.isRandomWait()); - + + alwaysStopCB.setSelected(bb.isAlwaysStop()); + randomWaitCB.setSelected(bb.isRandomWait()); + if (bb.getLocomotive() != null) { - this.locomotiveCB.setSelectedItem(bb.getLocomotive()); + locomotiveCB.setSelectedItem(bb.getLocomotive()); if (bb.getBlockState() == null) { bb.setBlockState(BlockBean.BlockState.OCCUPIED); } - + if (bb.getLocomotive().getLocIcon() != null) { - this.locomotiveIconLbl.setIcon(new ImageIcon(bb.getLocomotive().getLocIcon())); - this.locomotiveIconLbl.setText(null); + locomotiveIconLbl.setIcon(new ImageIcon(bb.getLocomotive().getLocIcon())); + locomotiveIconLbl.setText(null); } else { - this.locomotiveIconLbl.setText(bb.getLocomotive().getName()); + locomotiveIconLbl.setText(bb.getLocomotive().getName()); } - + if (LocomotiveBean.Direction.BACKWARDS == bb.getLocomotive().getDirection()) { - this.backwardsRB.setSelected(true); + backwardsRB.setSelected(true); } else { - this.forwardsRB.setSelected(true); + forwardsRB.setSelected(true); } - - this.startLocButton.setEnabled(AutoPilot.isAutoModeActive()); - this.startLocButton.setSelected(AutoPilot.isRunning(bb.getLocomotive())); + + startLocButton.setEnabled(AutoPilot.isAutoModeActive()); + startLocButton.setSelected(AutoPilot.isRunning(bb.getLocomotive())); } else { - this.locomotiveCB.setSelectedItem(emptyBean); - this.startLocButton.setEnabled(false); - - if (bb.getBlockState() == null) { - bb.setBlockState(BlockBean.BlockState.FREE); + locomotiveCB.setSelectedItem(emptyBean); + startLocButton.setEnabled(false); + + if (block.getBlockState() == null) { + block.setBlockState(BlockBean.BlockState.FREE); } } } @@ -412,50 +412,64 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { }// //GEN-END:initComponents private void saveExitBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveExitBtnActionPerformed - if (this.block != null && this.block.getBlockBean() != null) { - BlockBean bb = this.block.getBlockBean(); + if (block != null && block.getBlockBean() != null) { + BlockBean bb = block.getBlockBean(); + bb.setLocomotive(block.getLocomotive()); + if (bb.getLocomotive() == null) { + bb.setBlockState(BlockBean.BlockState.FREE); + } else { + bb.setBlockState(block.getBlockState()); + } + if (block.getLogicalDirection() != null) { + bb.setLogicalDirection(block.getLogicalDirection().getDirection()); + } else { + bb.setLogicalDirection(null); + } + bb.setReverseArrival(block.isReverseArrival()); + bb.setArrivalSuffix(block.getArrivalSuffix()); + PersistenceFactory.getService().persist(bb); + if (bb.getLocomotive() != null && bb.getLocomotive().getName() != null) { LocomotiveBean loc = bb.getLocomotive(); PersistenceFactory.getService().persist(loc); } - TileEvent tileEvent = new TileEvent(bb); - //TileFactory.fireTileEventListener(tileEvent); - //TileCache.fireTileEventListener(tileEvent); - + + TileCache.findTile(bb.getTileId()).setBlockBean(bb); } - - this.setVisible(false); - this.dispose(); + + setVisible(false); + dispose(); Logger.trace(evt.getActionCommand() + "Block " + block.getId() + " Locomotive: " + this.block.getBlockBean().getLocomotive()); }//GEN-LAST:event_saveExitBtnActionPerformed private void locomotiveCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_locomotiveCBActionPerformed - Logger.trace(evt.getActionCommand() + " -> " + this.locomotiveComboBoxModel.getSelectedItem()); - - LocomotiveBean selected = (LocomotiveBean) this.locomotiveComboBoxModel.getSelectedItem(); - - block.getBlockBean().setLocomotive(selected); - if (block.getBlockBean().getLocomotiveId() != null) { - block.getBlockBean().setBlockState(BlockBean.BlockState.OCCUPIED); - } else { - block.getBlockBean().setBlockState(BlockBean.BlockState.FREE); - } - + Logger.trace(evt.getActionCommand() + " -> " + locomotiveComboBoxModel.getSelectedItem()); + + LocomotiveBean selected = (LocomotiveBean) locomotiveComboBoxModel.getSelectedItem(); + + block.setLocomotive(selected); + //block.getBlockBean().setLocomotive(selected); + //if (block.getBlockBean().getLocomotiveId() != null) { + // block.getBlockBean().setBlockState(BlockBean.BlockState.OCCUPIED); + //} else { + // block.getBlockBean().setBlockState(BlockBean.BlockState.FREE); + //} + if (selected.getLocIcon() != null) { locomotiveIconLbl.setIcon(new ImageIcon(selected.getLocIcon())); locomotiveIconLbl.setText(null); } else { locomotiveIconLbl.setText(selected.getName()); } - + if (LocomotiveBean.Direction.BACKWARDS == selected.getDirection()) { - this.backwardsRB.setSelected(true); + backwardsRB.setSelected(true); } else { - this.forwardsRB.setSelected(true); + forwardsRB.setSelected(true); } - - if (block.getBlockBean().getLocomotiveId() != null) { + + if (block.getLocomotive() != null) { startLocButton.setEnabled(true); } else { startLocButton.setEnabled(false); @@ -463,44 +477,44 @@ private void locomotiveCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN- }//GEN-LAST:event_locomotiveCBActionPerformed private void startLocButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_startLocButtonActionPerformed - LocomotiveBean loc = this.block.getBlockBean().getLocomotive(); + LocomotiveBean loc = block.getLocomotive(); if (loc != null) { - AutoPilot.startStopLocomotive(loc, this.startLocButton.isSelected()); + AutoPilot.startStopLocomotive(loc, startLocButton.isSelected()); } }//GEN-LAST:event_startLocButtonActionPerformed private void reverseArrivalBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_reverseArrivalBtnActionPerformed - String suffix = block.getBlockBean().getArrivalSuffix(); + String suffix = block.getArrivalSuffix(); if ("+".equals(suffix)) { - block.getBlockBean().setArrivalSuffix("-"); + block.setArrivalSuffix("-"); } else { - block.getBlockBean().setArrivalSuffix("+"); + block.setArrivalSuffix("+"); } - block.getBlockBean().setReverseArrival(!block.getBlockBean().isReverseArrival()); + block.setReverseArrival(!block.isReverseArrival()); }//GEN-LAST:event_reverseArrivalBtnActionPerformed private void backwardsRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_backwardsRBActionPerformed - block.getBlockBean().setLogicalDirection(LocomotiveBean.Direction.BACKWARDS.getDirection()); + block.setLogicalDirection(LocomotiveBean.Direction.BACKWARDS); }//GEN-LAST:event_backwardsRBActionPerformed private void forwardsRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_forwardsRBActionPerformed - block.getBlockBean().setLogicalDirection(LocomotiveBean.Direction.FORWARDS.getDirection()); + block.setLogicalDirection(LocomotiveBean.Direction.FORWARDS); }//GEN-LAST:event_forwardsRBActionPerformed private void alwaysStopCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_alwaysStopCBActionPerformed - this.block.getBlockBean().setAlwaysStop(this.alwaysStopCB.isSelected()); + block.getBlockBean().setAlwaysStop(alwaysStopCB.isSelected()); }//GEN-LAST:event_alwaysStopCBActionPerformed private void randomWaitCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_randomWaitCBActionPerformed - this.block.getBlockBean().setRandomWait(this.randomWaitCB.isSelected()); + block.getBlockBean().setRandomWait(randomWaitCB.isSelected()); }//GEN-LAST:event_randomWaitCBActionPerformed private void minWaitSpinnerStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_minWaitSpinnerStateChanged - this.block.getBlockBean().setMinWaitTime((Integer) this.minWaitSpinner.getValue()); + block.getBlockBean().setMinWaitTime((Integer) minWaitSpinner.getValue()); }//GEN-LAST:event_minWaitSpinnerStateChanged private void maxWaitSpinnerStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_maxWaitSpinnerStateChanged - this.block.getBlockBean().setMaxWaitTime((Integer) this.maxWaitSpinner.getValue()); + block.getBlockBean().setMaxWaitTime((Integer) maxWaitSpinner.getValue()); }//GEN-LAST:event_maxWaitSpinnerStateChanged // Variables declaration - do not modify//GEN-BEGIN:variables diff --git a/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java b/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java index 7aabdfd7..66ad1089 100644 --- a/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java +++ b/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java @@ -23,6 +23,7 @@ import javax.swing.event.EventListenerList; import jcs.entities.AccessoryBean.AccessoryValue; import jcs.entities.AccessoryBean.SignalValue; +import jcs.entities.BlockBean; import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; import jcs.entities.TileBean.Orientation; @@ -54,12 +55,12 @@ public class DefaultTileModel implements TileModel { protected boolean showOutline = false; - protected BlockState blockState; protected boolean reverseArrival; protected String arrivalSuffix; protected boolean overlayImage = false; - protected LocomotiveBean.Direction logicalDirection; + protected BlockState blockState; protected LocomotiveBean locomotive; + protected LocomotiveBean.Direction logicalDirection; public DefaultTileModel() { this(Orientation.EAST); @@ -68,6 +69,7 @@ public DefaultTileModel() { public DefaultTileModel(Orientation orientation) { this.tileOrienation = orientation; this.selectedColor = Tile.DEFAULT_SELECTED_COLOR; + this.blockState = BlockState.FREE; } @Override @@ -159,6 +161,16 @@ public boolean isShowBlockState() { return showBlockState; } + //Set all block properties is one go + @Override + public void setBlockBean(BlockBean blockBean) { + locomotive = blockBean.getLocomotive(); + logicalDirection = LocomotiveBean.Direction.get(blockBean.getLogicalDirection()); + arrivalSuffix = blockBean.getArrivalSuffix(); + reverseArrival = blockBean.isReverseArrival(); + setBlockState(blockBean.getBlockState()); + } + @Override public void setShowBlockState(boolean showBlockState) { this.showBlockState = showBlockState; @@ -242,6 +254,14 @@ public BlockState getBlockState() { @Override public void setBlockState(BlockState blockState) { this.blockState = blockState; + overlayImage = locomotive != null + && locomotive.getLocIcon() != null + && (BlockState.OCCUPIED == blockState || BlockState.INBOUND == blockState || BlockState.OUTBOUND == blockState); + + if (BlockState.FREE == blockState || BlockState.OCCUPIED == blockState) { + arrivalSuffix = null; + } + fireStateChanged(); } @@ -314,6 +334,17 @@ public LocomotiveBean getLocomotive() { @Override public void setLocomotive(LocomotiveBean locomotive) { this.locomotive = locomotive; + if (locomotive != null) { + blockState = BlockState.OCCUPIED; + } else { + blockState = BlockState.FREE; + arrivalSuffix = null; + } + + this.overlayImage = locomotive != null + && locomotive.getLocIcon() != null + && (BlockState.OCCUPIED == blockState || BlockState.INBOUND == blockState || BlockState.OUTBOUND == blockState); + fireStateChanged(); } diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java index 9242f325..e5ed6a7d 100755 --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -40,7 +40,6 @@ import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.AccessoryValue; import jcs.entities.AccessoryBean.SignalType; -import jcs.entities.AccessoryBean.SignalValue; import jcs.entities.BlockBean; import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; @@ -52,6 +51,7 @@ import jcs.ui.layout.LayoutUtil; import static jcs.ui.layout.tiles.Block.BLOCK_HEIGHT; import static jcs.ui.layout.tiles.Block.BLOCK_WIDTH; +import org.tinylog.Logger; /** * Basic graphic element to display a track, turnout, etc on the screen.
@@ -431,12 +431,12 @@ public BlockState getBlockState() { } public void setBlockState(BlockState blockState) { + model.setBlockState(blockState); if (blockBean != null) { blockBean.setBlockState(blockState); - LocomotiveBean locomotive = model.getLocomotive(); - model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (blockState == BlockState.OCCUPIED || blockState == BlockState.INBOUND || blockState == BlockState.OUTBOUND)); + } else { + Logger.warn("Blockbean for " + id + " is NOT set!"); } - model.setBlockState(blockState); } public String getDepartureSuffix() { @@ -444,10 +444,12 @@ public String getDepartureSuffix() { } public void setDepartureSuffix(String suffix) { + model.setDepartureSuffix(suffix); if (blockBean != null) { blockBean.setDepartureSuffix(suffix); + } else { + Logger.warn("Blockbean for " + id + " is NOT set!"); } - model.setDepartureSuffix(suffix); } public boolean isReverseArrival() { @@ -455,10 +457,12 @@ public boolean isReverseArrival() { } public void setReverseArrival(boolean reverseArrival) { + model.setReverseArrival(reverseArrival); if (blockBean != null) { blockBean.setReverseArrival(reverseArrival); + } else { + Logger.warn("Blockbean for " + id + " is NOT set!"); } - model.setReverseArrival(reverseArrival); } public LocomotiveBean.Direction getLogicalDirection() { @@ -466,10 +470,12 @@ public LocomotiveBean.Direction getLogicalDirection() { } public void setLogicalDirection(LocomotiveBean.Direction logicalDirection) { + model.setLogicalDirection(logicalDirection); if (blockBean != null) { blockBean.setLogicalDirection(logicalDirection.getDirection()); + } else { + Logger.warn("Blockbean for " + id + " is NOT set!"); } - model.setLogicalDirection(logicalDirection); } public LocomotiveBean getLocomotive() { @@ -477,12 +483,25 @@ public LocomotiveBean getLocomotive() { } public void setLocomotive(LocomotiveBean locomotive) { + model.setLocomotive(locomotive); if (blockBean != null) { blockBean.setLocomotive(locomotive); - model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (model.getBlockState() == BlockState.OCCUPIED || model.getBlockState() == BlockState.INBOUND || model.getBlockState() == BlockState.OUTBOUND)); + } else { + Logger.warn("Blockbean for " + id + " is NOT set!"); } + } - model.setLocomotive(locomotive); + public String getArrivalSuffix() { + return model.getArrivalSuffix(); + } + + public void setArrivalSuffix(String arrivalSuffix) { + model.setArrivalSuffix(arrivalSuffix); + if (blockBean != null) { + blockBean.setArrivalSuffix(arrivalSuffix); + } else { + Logger.warn("Blockbean for " + id + " is NOT set!"); + } } public AccessoryBean getAccessoryBean() { @@ -556,6 +575,7 @@ public BlockBean getBlockBean() { public void setBlockBean(BlockBean blockBean) { this.blockBean = blockBean; + this.model.setBlockBean(blockBean); } public int getRenderOffsetX() { diff --git a/src/main/java/jcs/ui/layout/tiles/TileCache.java b/src/main/java/jcs/ui/layout/tiles/TileCache.java index 528b637c..02c347a6 100644 --- a/src/main/java/jcs/ui/layout/tiles/TileCache.java +++ b/src/main/java/jcs/ui/layout/tiles/TileCache.java @@ -16,30 +16,27 @@ package jcs.ui.layout.tiles; import java.awt.Point; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.stream.Collectors; -import jcs.JCS; -import jcs.commandStation.FeedbackController; import jcs.entities.TileBean; import jcs.persistence.PersistenceFactory; import org.tinylog.Logger; import jcs.commandStation.events.JCSActionEvent; -import jcs.commandStation.events.SensorEvent; /** - * Factory object to create Tiles and cache tiles + * Factory object to create Tiles and cache pointMap * * @author frans */ public class TileCache { - static final Map tiles = new HashMap<>(); - static final Map tileAltPoints = new HashMap<>(); - static final Map points = new HashMap<>(); + static final Map idMap = new ConcurrentHashMap<>(); + static final Map pointMap = new ConcurrentHashMap<>(); + static final Map altPointMap = new ConcurrentHashMap<>(); private static final ConcurrentLinkedQueue eventsQueue = new ConcurrentLinkedQueue(); @@ -57,125 +54,120 @@ public static List loadTiles() { } public static List loadTiles(boolean showvalues) { - tileAltPoints.clear(); - points.clear(); - tiles.clear(); + altPointMap.clear(); + pointMap.clear(); + idMap.clear(); List tileBeans = PersistenceFactory.getService().getTileBeans(); for (TileBean tb : tileBeans) { Tile tile = TileFactory.createTile(tb, showvalues); - tiles.put(tile.getCenter(), tile); - points.put(tile.getId(), tile.getCenter()); - //Alternative point(s) to be able to find all points + idMap.put(tile.id, tile); + pointMap.put(tile.getCenter(), tile); + //Alternative point(s) to be able to find all pointIds if (!tile.getAltPoints().isEmpty()) { Set alt = tile.getAltPoints(); for (Point ap : alt) { - tileAltPoints.put(ap, tile); + altPointMap.put(ap, tile); } } - //Extra actions for some tile of tiles - } - Logger.trace("Loaded " + tiles.size() + " Tiles..."); - return tiles.values().stream().collect(Collectors.toList()); + Logger.trace("Loaded " + idMap.size() + " Tiles..."); + return idMap.values().stream().collect(Collectors.toList()); } public static List getTiles() { - return tiles.values().stream().collect(Collectors.toList()); + return idMap.values().stream().collect(Collectors.toList()); } public static Tile addAndSaveTile(Tile tile) { - tiles.put(tile.getCenter(), tile); - points.put(tile.getId(), tile.getCenter()); + if (tile == null) { + throw new IllegalArgumentException("Tile cannot be null"); + } + + pointMap.put(tile.getCenter(), tile); + idMap.put(tile.getId(), tile); - //Alternative point(s) to be able to find all points + //Alternative point(s) to be able to find all pointIds if (!tile.getAltPoints().isEmpty()) { Set alt = tile.getAltPoints(); for (Point ap : alt) { - tileAltPoints.put(ap, tile); + altPointMap.put(ap, tile); } } - saveTile(tile); - //Logger.trace("Added " + tile + " There are now " + tiles.size() + " tiles..."); + persistTile(tile); + //Logger.trace("Added " + tile + " There are now " + pointMap.size() + " pointMap..."); return tile; } - public static void saveTile(final Tile tile) { - if (tile != null) { - TileBean tb = tile.getTileBean(); - PersistenceFactory.getService().persist(tb); - } else { - Logger.warn("Tile is null?"); + public static void persistTile(final Tile tile) { + if (tile == null) { + throw new IllegalArgumentException("Tile cannot be null"); } + TileBean tb = tile.getTileBean(); + PersistenceFactory.getService().persist(tb); } - public static void saveTiles() { - for (Tile tile : tiles.values()) { - saveTile(tile); + public static void persistAllTiles() { + for (Tile tile : idMap.values()) { + persistTile(tile); } } public static void deleteTile(final Tile tile) { - if (tile != null) { - if (tiles.containsKey(tile.getCenter())) { - Set rps = tile.getAltPoints(); - //Also remove alt points - for (Point ap : rps) { - tileAltPoints.remove(ap); - } - points.remove(tile.getId()); - tiles.remove(tile.getCenter()); - - TileBean tb = tile.getTileBean(); - PersistenceFactory.getService().remove(tb); - Logger.trace("Deleted " + tile.getId()); - } else { - Logger.warn("Tile " + tile.getId() + " not found in cache"); + if (tile == null) { + throw new IllegalArgumentException("Tile cannot be null"); + } + if (idMap.containsKey(tile.id)) { + Set rps = tile.getAltPoints(); + //Also remove alt pointIds + for (Point ap : rps) { + altPointMap.remove(ap); } + pointMap.remove(tile.getCenter()); + idMap.remove(tile.id); + TileBean tb = tile.getTileBean(); + PersistenceFactory.getService().remove(tb); + Logger.trace("Deleted " + tile.getId()); } else { - Logger.warn("Tile is null?"); + Logger.warn("Tile " + tile.getId() + " not found in cache"); } } public static Tile findTile(Point cp) { - Tile result = tiles.get(cp); + Tile result = pointMap.get(cp); if (result == null) { - result = tileAltPoints.get(cp); + result = altPointMap.get(cp); } return result; } public static Tile findTile(String id) { - Point p = points.get(id); - if (p != null) { - return findTile(p); - } else { - return null; - } + Tile tile = idMap.get(id); + return tile; } public static boolean canMoveTo(Tile tile, Point p) { //check if a tile exist with point p //Check if the cache contains a Cp of a tile on p //Logger.trace("Checking " + tile.id + " New Point (" + p.x + "," + p.y + ")"); - if (tiles.containsKey(p) && !tile.getCenter().equals(p) && !tile.getAltPoints().contains(p)) { + if (pointMap.containsKey(p) && !tile.getCenter().equals(p) && !tile.getAltPoints().contains(p)) { return false; } //Check if the cache contains a Cp on any of the Alt point is case of a Block or Cross - if (tileAltPoints.containsKey(p) && !tile.getAltPoints().contains(p)) { + if (altPointMap.containsKey(p) && !tile.getAltPoints().contains(p)) { return false; } - //Check with the tile on the new Cp with the new alt points if that is also free... + //Check with the tile on the new Cp with the new alt pointIds if that is also free... Set altPoints = tile.getAltPoints(p); for (Point ap : altPoints) { - if (tiles.containsKey(ap) && !tile.getCenter().equals(ap) && !tile.getAltPoints().contains(ap)) { + if (pointMap.containsKey(ap) && !tile.getCenter().equals(ap) && !tile.getAltPoints().contains(ap)) { return false; } - if (tileAltPoints.containsKey(ap) && !tile.getAltPoints().contains(ap)) { + if (altPointMap.containsKey(ap) && !tile.getAltPoints().contains(ap)) { return false; } } @@ -184,19 +176,23 @@ public static boolean canMoveTo(Tile tile, Point p) { } public static void moveTo(Tile tile, Point p) { + if (tile == null || p == null) { + throw new IllegalArgumentException("Tile or new Center Point cannot be null"); + } + if (canMoveTo(tile, p)) { //Logger.trace("Moving " + tile.getId() + " from " + tile.xyToString() + " to (" + p.x + "," + p.y + ")"); Set rps = tile.getAltPoints(); - //remove alt points + //remove alt pointIds for (Point ap : rps) { - tileAltPoints.remove(ap); + altPointMap.remove(ap); } - points.remove(tile.getId()); - tiles.remove(tile.getCenter()); + //pointIds.remove(tile.getId()); + idMap.remove(tile.id); + pointMap.remove(tile.getCenter()); tile.setCenter(p); - Tile t = addAndSaveTile(tile); - //Logger.trace("Moved " + t.id + " to " + t.xyToString()); + addAndSaveTile(tile); } else { Tile occ = findTile(p); Logger.trace("Can't Move tile " + tile.id + " from " + tile.xyToString() + " to (" + p.x + "," + p.y + ") Is occupied by " + occ.id); @@ -204,24 +200,25 @@ public static void moveTo(Tile tile, Point p) { } public static Tile rotateTile(Tile tile) { - if (!tiles.containsKey(tile.getCenter())) { + if (!pointMap.containsKey(tile.getCenter())) { Logger.warn("Tile " + tile.getId() + " NOT in cache!"); } - //Remove the alternative or extra points... + //Remove the alternative or extra pointIds... for (Point ep : tile.getAltPoints()) { - tileAltPoints.remove(ep); + altPointMap.remove(ep); } tile.rotate(); //update - tiles.put(tile.getCenter(), tile); + pointMap.put(tile.getCenter(), tile); for (Point ep : tile.getAltPoints()) { - tileAltPoints.put(ep, tile); + altPointMap.put(ep, tile); } + idMap.put(tile.id, tile); - saveTile(tile); + persistTile(tile); return tile; } @@ -234,13 +231,13 @@ public static Tile flipVertical(Tile tile) { } private static Tile flipTile(Tile tile, boolean horizontal) { - if (!tiles.containsKey(tile.getCenter())) { + if (!pointMap.containsKey(tile.getCenter())) { Logger.warn("Tile " + tile.getId() + " NOT in cache!"); } - //Remove the alternative or extra points... + //Remove the alternative or extra pointIds... for (Point ep : tile.getAltPoints()) { - tileAltPoints.remove(ep); + altPointMap.remove(ep); } if (horizontal) { @@ -249,12 +246,13 @@ private static Tile flipTile(Tile tile, boolean horizontal) { tile.flipVertical(); } //update - tiles.put(tile.getCenter(), tile); + pointMap.put(tile.getCenter(), tile); for (Point ep : tile.getAltPoints()) { - tileAltPoints.put(ep, tile); + altPointMap.put(ep, tile); } + idMap.put(tile.id, tile); - saveTile(tile); + persistTile(tile); return tile; } @@ -265,4 +263,21 @@ public static void enqueTileAction(JCSActionEvent jcsEvent) { } } + public static void repaintTile(Tile tile) { + repaintTile(tile.id); + } + + public static void repaintTile(String tileId) { + if (tileId == null) { + throw new IllegalArgumentException("TileId cannot be null"); + } + + if (idMap.containsKey(tileId)) { + Tile tile = idMap.get(tileId); + tile.repaint(); + } else { + Logger.warn("Can't find a Tile with Id: " + tileId + " in the cache"); + } + } + } diff --git a/src/main/java/jcs/ui/layout/tiles/TileModel.java b/src/main/java/jcs/ui/layout/tiles/TileModel.java index 4266b0e7..84900940 100644 --- a/src/main/java/jcs/ui/layout/tiles/TileModel.java +++ b/src/main/java/jcs/ui/layout/tiles/TileModel.java @@ -60,6 +60,8 @@ public interface TileModel extends Serializable { boolean isShowBlockState(); + void setBlockBean(BlockBean blockBean); + public void setShowBlockState(boolean showBlockState); boolean isShowLocomotiveImage(); diff --git a/src/main/java/jcs/ui/layout/tiles/ui/BlockUI.java b/src/main/java/jcs/ui/layout/tiles/ui/BlockUI.java index 41ac8b24..44d9b3b5 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/BlockUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/BlockUI.java @@ -59,9 +59,6 @@ public static ComponentUI createUI(JComponent c) { return new BlockUI(); } -// Color getBlockStateColor() { -// return getBlockStateColor(this.model.getBlockState()); -// } protected Color getBlockStateColor(BlockBean.BlockState blockState) { return switch (blockState) { case GHOST -> From f7ffd046d1364b3e5315eafc8b98f6105bb062f0 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Thu, 13 Feb 2025 20:38:32 +0100 Subject: [PATCH 21/70] More refactoring TileFactory and duplicate TileCache removed --- .../autopilot/state/Dispatcher.java | 169 ++++----- src/main/java/jcs/ui/layout/LayoutCanvas.java | 5 +- .../ui/layout/dialogs/BlockControlDialog.java | 12 +- .../ui/layout/pathfinding/astar/AStar.java | 28 +- .../layout/pathfinding/astar/TileCache.java | 90 ----- .../jcs/ui/layout/tiles/DefaultTileModel.java | 12 +- .../java/jcs/ui/layout/tiles/TileCache.java | 279 ++++++++++++++- .../java/jcs/ui/layout/tiles/TileFactory.java | 320 ------------------ .../java/jcs/ui/layout/tiles/ui/CurvedUI.java | 1 - .../java/jcs/ui/layout/tiles/ui/EndUI.java | 1 - .../java/jcs/ui/layout/tiles/ui/SensorUI.java | 1 - .../java/jcs/ui/layout/tiles/ui/TileUI.java | 1 - .../autopilot/AutoPilotTest.java | 7 +- src/test/java/jcs/ui/layout/TileTest.java | 285 ++++++++-------- .../pathfinding/astar/AStarCrossLeftEast.java | 23 +- .../astar/AStarCrossLeftSouth.java | 16 +- .../astar/AStarCrossRightEast.java | 16 +- .../astar/AStarCrossRightSouth.java | 16 +- .../pathfinding/astar/AStarCrossingTest.java | 19 +- .../astar/AStarSwitchLeftEast.java | 22 +- .../astar/AStarSwitchLeftNorth.java | 16 +- .../astar/AStarSwitchLeftSouth.java | 18 +- .../astar/AStarSwitchLeftWest.java | 17 +- .../layout/pathfinding/astar/AStarTest.java | 14 +- .../astar/AStarTestWithDirection.java | 16 +- .../jcs/ui/layout/tiles/TileTesterFrame.java | 2 +- 26 files changed, 631 insertions(+), 775 deletions(-) delete mode 100644 src/main/java/jcs/ui/layout/pathfinding/astar/TileCache.java delete mode 100755 src/main/java/jcs/ui/layout/tiles/TileFactory.java diff --git a/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java b/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java index 0c06c18e..b9f9f44a 100644 --- a/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java +++ b/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java @@ -43,14 +43,14 @@ * */ public class Dispatcher { - + private final LocomotiveBean locomotiveBean; - + private RouteBean routeBean; - + private String departureBlockId; private String destinationBlockId; - + private String waitingForSensorId; //Enter Sensor of the destination private String enterSensorId; @@ -61,13 +61,13 @@ public class Dispatcher { private String occupationSensorId; //The exit of the departure private String exitSensorId; - + private final List stateEventListeners; - + private final ThreadGroup parent; - + private StateMachineThread stateMachineThread; - + public Dispatcher(ThreadGroup parent, LocomotiveBean locomotiveBean) { this.parent = parent; this.locomotiveBean = locomotiveBean; @@ -76,27 +76,27 @@ public Dispatcher(ThreadGroup parent, LocomotiveBean locomotiveBean) { this.stateEventListeners = new LinkedList<>(); this.stateMachineThread = new StateMachineThread(parent, this); } - + StateMachineThread getStateMachineThread() { return stateMachineThread; } - + public Long getId() { return this.locomotiveBean.getId(); } - + public String getName() { return this.locomotiveBean.getName(); } - + public LocomotiveBean getLocomotiveBean() { return locomotiveBean; } - + RouteBean getRouteBean() { return routeBean; } - + void setRouteBean(RouteBean routeBean) { this.routeBean = routeBean; if (routeBean == null) { @@ -107,11 +107,11 @@ void setRouteBean(RouteBean routeBean) { this.destinationBlockId = routeBean.getToTileId(); } } - + public boolean isLocomotiveAutomodeOn() { return this.stateMachineThread.isEnableAutomode(); } - + public boolean startLocomotiveAutomode() { //Only when the Autopilot is ON! if (AutoPilot.isAutoModeActive()) { @@ -121,30 +121,30 @@ public boolean startLocomotiveAutomode() { } return this.stateMachineThread.isEnableAutomode(); } - + public void stopLocomotiveAutomode() { stateMachineThread.setEnableAutomode(false); } - + void startRunning() { if (this.stateMachineThread != null && this.stateMachineThread.isThreadRunning()) { return; } - + if (this.stateMachineThread == null || !this.stateMachineThread.isAlive()) { stateMachineThread = new StateMachineThread(this.parent, this); } - + this.stateMachineThread.setEnableAutomode(true); if (!this.stateMachineThread.isThreadRunning()) { this.stateMachineThread.start(); } } - + public void stopRunning() { if (stateMachineThread != null && stateMachineThread.isThreadRunning()) { stateMachineThread.stopRunningThread(); - + try { Logger.trace(this.getName() + " Thread Joining..."); stateMachineThread.join(); @@ -154,7 +154,7 @@ public void stopRunning() { Logger.trace(this.getName() + " Thread Joined!"); } } - + void resetDispatcher() { this.routeBean = null; this.departureBlockId = null; @@ -166,13 +166,13 @@ void resetDispatcher() { this.stateEventListeners.clear(); this.locomotiveBean.setDispatcherDirection(Direction.SWITCH); } - + public void reset() { Logger.trace("Resetting dispatcher " + getName() + " StateMachine..."); this.stateMachineThread.reset(); resetDispatcher(); } - + public boolean isRunning() { if (stateMachineThread != null) { return stateMachineThread.isThreadRunning(); @@ -194,7 +194,7 @@ BlockBean getDepartureBlock() { return departureBlock; } } - + BlockBean getDestinationBlock() { if (destinationBlockId != null) { return PersistenceFactory.getService().getBlockByTileId(destinationBlockId); @@ -205,7 +205,7 @@ BlockBean getDestinationBlock() { return null; } } - + public String getStateName() { if (stateMachineThread != null) { return stateMachineThread.getDispatcherStateName(); @@ -213,47 +213,47 @@ public String getStateName() { return "#Idle"; } } - + void setWaitForSensorid(String sensorId) { this.waitingForSensorId = sensorId; } - + public String getWaitingForSensorId() { return waitingForSensorId; } - + public String getEnterSensorId() { return enterSensorId; } - + void setEnterSensorId(String enterSensorId) { this.enterSensorId = enterSensorId; } - + public String getInSensorId() { return inSensorId; } - + void setInSensorId(String inSensorId) { this.inSensorId = inSensorId; } - + public String getOccupationSensorId() { return occupationSensorId; } - + void setOccupationSensorId(String occupationSensorId) { this.occupationSensorId = occupationSensorId; } - + public String getExitSensorId() { return exitSensorId; } - + void setExitSensorId(String exitSensorId) { this.exitSensorId = exitSensorId; } - + void clearDepartureIgnoreEventHandlers() { if (departureBlockId != null) { BlockBean departureBlock = getDepartureBlock(); @@ -263,7 +263,7 @@ void clearDepartureIgnoreEventHandlers() { AutoPilot.removeHandler(plusSensorId); } } - + public void onIgnoreEvent(SensorEvent event) { //Only in Simulator mode if (JCS.getJcsCommandStation().getCommandStationBean().isVirtual()) { @@ -272,19 +272,19 @@ public void onIgnoreEvent(SensorEvent event) { this.waitingForSensorId = null; } } - + if (this.enterSensorId != null && this.enterSensorId.equals(event.getId())) { if (!event.isActive()) { this.enterSensorId = null; } } - + if (this.inSensorId != null && this.inSensorId.equals(event.getId())) { if (!event.isActive()) { this.inSensorId = null; } } - + if (this.exitSensorId != null && this.exitSensorId.equals(event.getId())) { if (!event.isActive()) { this.exitSensorId = null; @@ -293,100 +293,107 @@ public void onIgnoreEvent(SensorEvent event) { } //Logger.trace("Event for a ignored listener: " + event.getId() + " Changed: " + event.isChanged() + ", active: " + event.getSensorBean().isActive()); } - + synchronized void switchAccessory(AccessoryBean accessory, AccessoryValue value) { JCS.getJcsCommandStation().switchAccessory(accessory, value); } - + synchronized void changeLocomotiveVelocity(LocomotiveBean locomotive, int velocity) { JCS.getJcsCommandStation().changeLocomotiveSpeed(velocity, locomotive); locomotiveBean.setVelocity(velocity); } - + synchronized void changeLocomotiveDirection(LocomotiveBean locomotive, Direction newDirection) { JCS.getJcsCommandStation().changeLocomotiveDirection(newDirection, locomotive); locomotiveBean.setDirection(newDirection); } - + void fireStateListeners(String s) { for (StateEventListener sel : stateEventListeners) { sel.onStateChange(this); } } - + public void addStateEventListener(StateEventListener listener) { stateEventListeners.add(listener); } - + public void removeStateEventListener(StateEventListener listener) { stateEventListeners.remove(listener); } - + public static void resetRoute(RouteBean route) { List routeElements = route.getRouteElements(); for (RouteElementBean re : routeElements) { String tileId = re.getTileId(); Tile tile = TileCache.findTile(tileId); - - if (tile.isBlock()) { - if (tile.getLocomotive() != null) { - tile.setBlockState(BlockBean.BlockState.OCCUPIED); - } else { - tile.setBlockState(BlockBean.BlockState.FREE); + if (tile != null) { + if (tile.isBlock()) { + if (tile.getLocomotive() != null) { + tile.setBlockState(BlockBean.BlockState.OCCUPIED); + } else { + tile.setBlockState(BlockBean.BlockState.FREE); + } } + if (tile.isJunction()) { + tile.setRouteValue(AccessoryBean.AccessoryValue.OFF); + } + tile.setShowRoute(false); + } else { + Logger.warn(("Tile with id " + tileId + " NOT in TileCache!")); } - if (tile.isJunction()) { - tile.setRouteValue(AccessoryBean.AccessoryValue.OFF); - } - tile.setShowRoute(false); } } - + void showBlockState(BlockBean blockBean) { Logger.trace("Show block " + blockBean); Tile tile = TileCache.findTile(blockBean.getTileId()); - tile.setBlockBean(blockBean); + tile.setBlockBean(blockBean); } - + void showRoute(RouteBean routeBean, Color routeColor) { Logger.trace("Show route " + routeBean.toLogString()); List routeElements = routeBean.getRouteElements(); - + for (RouteElementBean re : routeElements) { String tileId = re.getTileId(); - TileBean.Orientation incomingSide = re.getIncomingOrientation(); - Tile tile = TileCache.findTile(tileId); - tile.setIncomingSide(incomingSide); - tile.setTrackRouteColor(Tile.DEFAULT_ROUTE_TRACK_COLOR); - - if (re.isTurnout()) { - AccessoryBean.AccessoryValue routeState = re.getAccessoryValue(); - tile.setRouteValue(routeState); - } else if (re.isBlock()) { - if (re.getTileId().equals(routeBean.getFromTileId())) { - //departure block - tile.setBlockState(BlockBean.BlockState.OUTBOUND); - } else { - tile.setBlockState(BlockBean.BlockState.INBOUND); + if (tile != null) { + TileBean.Orientation incomingSide = re.getIncomingOrientation(); + + tile.setIncomingSide(incomingSide); + tile.setTrackRouteColor(Tile.DEFAULT_ROUTE_TRACK_COLOR); + + if (re.isTurnout()) { + AccessoryBean.AccessoryValue routeState = re.getAccessoryValue(); + tile.setRouteValue(routeState); + } else if (re.isBlock()) { + if (re.getTileId().equals(routeBean.getFromTileId())) { + //departure block + tile.setBlockState(BlockBean.BlockState.OUTBOUND); + } else { + tile.setBlockState(BlockBean.BlockState.INBOUND); + } } + tile.setShowRoute(true); + } else { + Logger.warn("Tile with id " + tileId + " NOT in TileCache!"); } - tile.setShowRoute(true); } } - + int getRandomNumber(int min, int max) { Random random = new Random(); return random.ints(min, max).findFirst().getAsInt(); } - + @Override public int hashCode() { int hash = 7; hash = 37 * hash + Objects.hashCode(locomotiveBean.getId()); return hash; } - + @Override public boolean equals(Object obj) { if (this == obj) { diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.java b/src/main/java/jcs/ui/layout/LayoutCanvas.java index daad3415..8e3672ef 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.java +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.java @@ -68,7 +68,6 @@ import jcs.ui.layout.tiles.Signal; import jcs.ui.layout.tiles.Switch; import jcs.ui.layout.tiles.Tile; -import jcs.ui.layout.tiles.TileFactory; import jcs.ui.layout.tiles.TileCache; import org.tinylog.Logger; @@ -348,7 +347,7 @@ private void mousePressedAction(MouseEvent evt) { private Tile addTile(Point p, TileType tileType, Orientation orientation, Direction direction, boolean selected, boolean showCenter) { Logger.trace("Adding: " + tileType + " @ " + p + " O: " + orientation + " D: " + direction); - Tile tile = TileFactory.createTile(tileType, orientation, direction, p); + Tile tile = TileCache.createTile(tileType, orientation, direction, p); if (TileCache.canMoveTo(tile, p)) { tile.setSelected(selected); @@ -359,7 +358,7 @@ private Tile addTile(Point p, TileType tileType, Orientation orientation, Direct } else { Tile occ = TileCache.findTile(p); Logger.trace("Can't add tile " + tile.getId() + " on " + tile.xyToString() + " Is occupied by " + occ.getId()); - TileFactory.rollback(tile); + TileCache.rollback(tile); return null; } } diff --git a/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java b/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java index 22d0953c..88409cd5 100644 --- a/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java +++ b/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java @@ -448,13 +448,11 @@ private void locomotiveCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN- LocomotiveBean selected = (LocomotiveBean) locomotiveComboBoxModel.getSelectedItem(); - block.setLocomotive(selected); - //block.getBlockBean().setLocomotive(selected); - //if (block.getBlockBean().getLocomotiveId() != null) { - // block.getBlockBean().setBlockState(BlockBean.BlockState.OCCUPIED); - //} else { - // block.getBlockBean().setBlockState(BlockBean.BlockState.FREE); - //} + if (selected.getId() != null) { + block.setLocomotive(selected); + } else { + block.setLocomotive(null); + } if (selected.getLocIcon() != null) { locomotiveIconLbl.setIcon(new ImageIcon(selected.getLocIcon())); diff --git a/src/main/java/jcs/ui/layout/pathfinding/astar/AStar.java b/src/main/java/jcs/ui/layout/pathfinding/astar/AStar.java index a3f84a64..66e5f71c 100644 --- a/src/main/java/jcs/ui/layout/pathfinding/astar/AStar.java +++ b/src/main/java/jcs/ui/layout/pathfinding/astar/AStar.java @@ -29,7 +29,7 @@ import jcs.entities.RouteElementBean; import jcs.persistence.PersistenceFactory; import jcs.ui.layout.tiles.Tile; -import jcs.ui.layout.tiles.TileFactory; +import jcs.ui.layout.tiles.TileCache; import org.tinylog.Logger; /** @@ -39,13 +39,13 @@ */ public class AStar { - private final TileCache tileCache; + //private final TileCache tileCache; private final Graph graph; private final Map routes; public AStar() { - this.tileCache = new TileCache(); + //this.tileCache = new TileCache(); this.routes = new HashMap<>(); this.graph = new Graph(); } @@ -53,8 +53,8 @@ public AStar() { public List> getAllBlockToBlockNodes() { List> fromToList = new ArrayList<>(); - List fromNodes = this.graph.getBlockNodes(); - List toNodes = this.graph.getBlockNodes(); + List fromNodes = graph.getBlockNodes(); + List toNodes = graph.getBlockNodes(); for (Node from : fromNodes) { boolean fromBlock = from.isBlock(); @@ -186,7 +186,7 @@ public List findPath(Node from, String fromSuffix, Node to, String toSuffi } public List routeAll() { - this.routes.clear(); + routes.clear(); List> blockToBlockList = getAllBlockToBlockNodes(); Logger.trace("Try to route " + blockToBlockList.size() * 2 * 2 + " Possible block to block routes"); Logger.trace("============================================================================="); @@ -216,7 +216,7 @@ public List routeAll() { Logger.debug("No Path from " + fid + " to " + tid); } else { RouteBean routeBean = createRouteBeanFromNodePath(path); - this.routes.put(routeBean.getId(), routeBean); + routes.put(routeBean.getId(), routeBean); } //} @@ -231,7 +231,7 @@ public List routeAll() { } public void buildGraph(List tiles) { - this.tileCache.reload(tiles); + //this.tileCache.reload(tiles); this.graph.clear(); //Every Tile becomes a node @@ -248,8 +248,10 @@ public void buildGraph(List tiles) { Logger.trace("Node: " + node.getId() + " has " + neighborPoints.size() + " neighbors " + (node.isBlock() ? "[Block]" : "") + (node.isJunction() ? "[Junction]" : "")); for (Point p : neighborPoints) { - if (tileCache.contains(p)) { - Node neighbor = graph.getNode(tileCache.getTileId(p)); + //if (tileCache.contains(p)) { + if (TileCache.contains(p)) { + //Node neighbor = graph.getNode(tileCache.getTileId(p)); + Node neighbor = graph.getNode(TileCache.findTile(p).getId()); if (node.getTile().isAdjacent(neighbor.getTile())) { double distance; @@ -267,7 +269,7 @@ public void buildGraph(List tiles) { } } //Logger.trace("Neighbor: " + neighbor.getId() + " Distance: " + distance); - this.graph.link(node, neighbor, distance); + graph.link(node, neighbor, distance); } } } @@ -275,11 +277,11 @@ public void buildGraph(List tiles) { } public List getNodes() { - return this.graph.getNodes(); + return graph.getNodes(); } public static void main(String[] a) { - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = TileCache.loadTiles(); AStar gb = new AStar(); gb.buildGraph(tiles); diff --git a/src/main/java/jcs/ui/layout/pathfinding/astar/TileCache.java b/src/main/java/jcs/ui/layout/pathfinding/astar/TileCache.java deleted file mode 100644 index 9ce7f707..00000000 --- a/src/main/java/jcs/ui/layout/pathfinding/astar/TileCache.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2023 frans. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout.pathfinding.astar; - -import java.awt.Point; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import jcs.ui.layout.tiles.Tile; -import org.tinylog.Logger; - -/** - * - * @author frans - */ -public class TileCache { - - private final Map tilePointMap; - private final Map tileIdMap; - - public TileCache() { - this(null); - } - - public TileCache(List tiles) { - this.tilePointMap = new HashMap<>(); - this.tileIdMap = new HashMap<>(); - reload(tiles); - } - - public final synchronized void reload(List tiles) { - this.tilePointMap.clear(); - this.tileIdMap.clear(); - - if (tiles != null && !tiles.isEmpty()) { - for (Tile tile : tiles) { - if (tile.isBlock()) { - //A block is s rectangle which fils the space of 3 tiles hence there are 3 "center" points. - for (Point p : tile.getAltPoints()) { - this.tilePointMap.put(p, tile); - } - } else { - //A tile is a square, center is the point too look for - this.tilePointMap.put(tile.getCenter(), tile); - } - - this.tileIdMap.put(tile.getId(), tile); - } - Logger.trace("Loaded " + tiles.size() + " tiles"); - } - } - - public Tile getTile(String id) { - return this.tileIdMap.get(id); - } - - public boolean contains(String id) { - return this.tileIdMap.containsKey(id); - } - - public Tile getTile(Point p) { - return this.tilePointMap.get(p); - } - - public String getTileId(Point p) { - if (this.tilePointMap.containsKey(p)) { - return this.tilePointMap.get(p).getId(); - } else { - return null; - } - } - - public boolean contains(Point p) { - return this.tilePointMap.containsKey(p); - } - -} diff --git a/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java b/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java index 66ad1089..d904fcd5 100644 --- a/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java +++ b/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java @@ -164,11 +164,13 @@ public boolean isShowBlockState() { //Set all block properties is one go @Override public void setBlockBean(BlockBean blockBean) { - locomotive = blockBean.getLocomotive(); - logicalDirection = LocomotiveBean.Direction.get(blockBean.getLogicalDirection()); - arrivalSuffix = blockBean.getArrivalSuffix(); - reverseArrival = blockBean.isReverseArrival(); - setBlockState(blockBean.getBlockState()); + if (blockBean != null) { + locomotive = blockBean.getLocomotive(); + logicalDirection = LocomotiveBean.Direction.get(blockBean.getLogicalDirection()); + arrivalSuffix = blockBean.getArrivalSuffix(); + reverseArrival = blockBean.isReverseArrival(); + setBlockState(blockBean.getBlockState()); + } } @Override diff --git a/src/main/java/jcs/ui/layout/tiles/TileCache.java b/src/main/java/jcs/ui/layout/tiles/TileCache.java index 02c347a6..825c3987 100644 --- a/src/main/java/jcs/ui/layout/tiles/TileCache.java +++ b/src/main/java/jcs/ui/layout/tiles/TileCache.java @@ -16,16 +16,31 @@ package jcs.ui.layout.tiles; import java.awt.Point; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.stream.Collectors; +import jcs.JCS; +import jcs.commandStation.events.AccessoryEventListener; import jcs.entities.TileBean; import jcs.persistence.PersistenceFactory; import org.tinylog.Logger; import jcs.commandStation.events.JCSActionEvent; +import jcs.commandStation.events.SensorEventListener; +import jcs.entities.AccessoryBean; +import jcs.entities.SensorBean; +import static jcs.entities.TileBean.TileType.BLOCK; +import static jcs.entities.TileBean.TileType.CROSS; +import static jcs.entities.TileBean.TileType.CROSSING; +import static jcs.entities.TileBean.TileType.CURVED; +import static jcs.entities.TileBean.TileType.END; +import static jcs.entities.TileBean.TileType.SENSOR; +import static jcs.entities.TileBean.TileType.SIGNAL; +import static jcs.entities.TileBean.TileType.STRAIGHT; +import static jcs.entities.TileBean.TileType.STRAIGHT_DIR; +import static jcs.entities.TileBean.TileType.SWITCH; /** * Factory object to create Tiles and cache pointMap @@ -34,12 +49,23 @@ */ public class TileCache { - static final Map idMap = new ConcurrentHashMap<>(); - static final Map pointMap = new ConcurrentHashMap<>(); - static final Map altPointMap = new ConcurrentHashMap<>(); + // Keep the records of the used id sequence number + private static int straightIdSeq; + private static int crossingIdSeq; + private static int curvedIdSeq; + private static int switchIdSeq; + private static int crossIdSeq; + private static int signalIdSeq; + private static int sensorIdSeq; + private static int blockIdSeq; + private static int straightDirectionIdSeq; + private static int endIdSeq; + + static final Map idMap = new HashMap<>(); + static final Map pointMap = new HashMap<>(); + static final Map altPointMap = new HashMap<>(); private static final ConcurrentLinkedQueue eventsQueue = new ConcurrentLinkedQueue(); - private static final TileActionEventHandler actionEventQueueHandler = new TileActionEventHandler(eventsQueue); static { @@ -49,6 +75,243 @@ public class TileCache { private TileCache() { } + private static int nextIdSeq(String id) { + String idnr = id.substring(3); + int idSeq = Integer.parseInt(idnr); + return idSeq; + } + + private static String nextTileId(TileBean.TileType tileType) { + switch (tileType) { + case STRAIGHT -> { + straightIdSeq++; + return "st-" + straightIdSeq; + } + case CROSSING -> { + crossingIdSeq++; + return "cr-" + crossingIdSeq; + } + case CURVED -> { + curvedIdSeq++; + return "ct-" + curvedIdSeq; + } + case SWITCH -> { + switchIdSeq++; + return "sw-" + switchIdSeq; + } + case CROSS -> { + crossIdSeq++; + return "cs-" + crossIdSeq; + } + case SIGNAL -> { + signalIdSeq++; + return "si-" + signalIdSeq; + } + case SENSOR -> { + sensorIdSeq++; + return "se-" + sensorIdSeq; + } + case BLOCK -> { + blockIdSeq++; + return "bk-" + blockIdSeq; + } + case STRAIGHT_DIR -> { + straightDirectionIdSeq++; + return "sd-" + straightDirectionIdSeq; + } + case END -> { + endIdSeq++; + return "et-" + endIdSeq; + } + default -> { + Logger.warn("Unknown Tile Type " + tileType); + return null; + } + } + } + + private static int maxIdSeq(int currentId, int newId) { + if (currentId < newId) { + return newId; + } else { + return currentId; + } + } + + public static Tile createTile(TileBean tileBean, boolean showValues) { + if (tileBean == null) { + return null; + } + + TileBean.TileType tileType = tileBean.getTileType(); + Tile tile = null; + switch (tileType) { + case STRAIGHT -> { + tile = new Straight(tileBean); + straightIdSeq = maxIdSeq(straightIdSeq, nextIdSeq(tileBean.getId())); + } + case CROSSING -> { + tile = new Crossing(tileBean); + crossingIdSeq = maxIdSeq(crossingIdSeq, nextIdSeq(tileBean.getId())); + } + case CURVED -> { + tile = new Curved(tileBean); + curvedIdSeq = maxIdSeq(curvedIdSeq, nextIdSeq(tileBean.getId())); + } + case SWITCH -> { + tile = new Switch(tileBean); + tile.setAccessoryBean(tileBean.getAccessoryBean()); + + switchIdSeq = maxIdSeq(switchIdSeq, nextIdSeq(tileBean.getId())); + if (showValues && tileBean.getAccessoryBean() != null) { + tile.setAccessoryValue((tileBean.getAccessoryBean()).getAccessoryValue()); + } + JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); + } + case CROSS -> { + tile = new Cross(tileBean); + tile.setAccessoryBean(tileBean.getAccessoryBean()); + + crossIdSeq = maxIdSeq(crossIdSeq, nextIdSeq(tileBean.getId())); + if (showValues && tileBean.getAccessoryBean() != null) { + tile.setAccessoryValue((tileBean.getAccessoryBean()).getAccessoryValue()); + } + JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); + } + case SIGNAL -> { + tile = new Signal(tileBean); + tile.setAccessoryBean(tileBean.getAccessoryBean()); + + signalIdSeq = maxIdSeq(signalIdSeq, nextIdSeq(tileBean.getId())); + if (showValues && tileBean.getAccessoryBean() != null) { + ((Signal) tile).setSignalValue(((AccessoryBean) tileBean.getAccessoryBean()).getSignalValue()); + } + JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); + } + case SENSOR -> { + tile = new Sensor(tileBean); + tile.setSensorBean(tileBean.getSensorBean()); + sensorIdSeq = maxIdSeq(sensorIdSeq, nextIdSeq(tileBean.getId())); + + if (showValues && tileBean.getSensorBean() != null) { + ((Sensor) tile).setActive(((SensorBean) tileBean.getSensorBean()).isActive()); + } + JCS.getJcsCommandStation().addSensorEventListener((SensorEventListener) tile); + } + case BLOCK -> { + tile = new Block(tileBean); + tile.setBlockBean(tileBean.getBlockBean()); + blockIdSeq = maxIdSeq(blockIdSeq, nextIdSeq(tileBean.getId())); + } + case STRAIGHT_DIR -> { + tile = new StraightDirection(tileBean); + straightDirectionIdSeq = maxIdSeq(straightDirectionIdSeq, nextIdSeq(tileBean.getId())); + } + case END -> { + tile = new End(tileBean); + endIdSeq = maxIdSeq(endIdSeq, nextIdSeq(tileBean.getId())); + } + default -> + Logger.warn("Unknown Tile Type " + tileType); + } + + return (Tile) tile; + } + + /** + * @param tileType type of type to create + * @param orientation whether the orientation of the Tile is EAST, WEST, NORTH or SOUTH + * @param x the tile center X + * @param y the tile center Y + * @return a Tile object + */ + public static Tile createTile(TileBean.TileType tileType, TileBean.Orientation orientation, int x, int y) { + return createTile(tileType, orientation, TileBean.Direction.CENTER, x, y); + } + + /** + * @param tileType type of type to create + * @param orientation whether the orientation of the Tile is EAST, WEST, NORTH or SOUTH + * @param direction direction plays a role with Turnout tiles whether it goes to the Left or Right + * @param x the tile center X + * @param y the tile center Y + * @return a Tile object + */ + public static Tile createTile(TileBean.TileType tileType, TileBean.Orientation orientation, TileBean.Direction direction, int x, int y) { + return createTile(tileType, orientation, direction, new Point(x, y)); + } + + public static Tile createTile(TileBean.TileType tileType, TileBean.Orientation orientation, TileBean.Direction direction, Point center) { + Tile tile = null; + switch (tileType) { + case STRAIGHT -> { + tile = new Straight(orientation, center); + } + case CROSSING -> { + tile = new Crossing(orientation, center); + } + case CURVED -> + tile = new Curved(orientation, center); + case SWITCH -> + tile = new Switch(orientation, direction, center); + case CROSS -> + tile = new Cross(orientation, direction, center); + case SIGNAL -> + tile = new Signal(orientation, center); + case SENSOR -> + tile = new Sensor(orientation, center); + case BLOCK -> + tile = new Block(orientation, center); + case STRAIGHT_DIR -> + tile = new StraightDirection(orientation, center); + case END -> + tile = new End(orientation, center); + default -> + Logger.warn("Unknown Tile Type " + tileType); + } + + if (tile != null) { + tile.setId(nextTileId(tileType)); + } + + return (Tile) tile; + } + + public static void rollback(Tile tile) { + switch (tile.tileType) { + case STRAIGHT -> { + straightIdSeq--; + } + case CROSSING -> { + crossingIdSeq--; + } + case CURVED -> { + curvedIdSeq--; + } + case SWITCH -> { + switchIdSeq--; + } + case CROSS -> { + crossIdSeq--; + } + case SIGNAL -> { + signalIdSeq--; + } + case SENSOR -> { + sensorIdSeq--; + } + case BLOCK -> { + blockIdSeq--; + } + case STRAIGHT_DIR -> { + straightDirectionIdSeq--; + } + case END -> { + endIdSeq--; + } + } + } + public static List loadTiles() { return loadTiles(false); } @@ -61,7 +324,7 @@ public static List loadTiles(boolean showvalues) { List tileBeans = PersistenceFactory.getService().getTileBeans(); for (TileBean tb : tileBeans) { - Tile tile = TileFactory.createTile(tb, showvalues); + Tile tile = createTile(tb, showvalues); idMap.put(tile.id, tile); pointMap.put(tile.getCenter(), tile); //Alternative point(s) to be able to find all pointIds @@ -149,6 +412,10 @@ public static Tile findTile(String id) { return tile; } + public static boolean contains(Point p) { + return pointMap.containsKey(p); + } + public static boolean canMoveTo(Tile tile, Point p) { //check if a tile exist with point p //Check if the cache contains a Cp of a tile on p diff --git a/src/main/java/jcs/ui/layout/tiles/TileFactory.java b/src/main/java/jcs/ui/layout/tiles/TileFactory.java deleted file mode 100755 index 0e6c6b0d..00000000 --- a/src/main/java/jcs/ui/layout/tiles/TileFactory.java +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Copyright 2023 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout.tiles; - -import java.awt.Point; -import java.util.LinkedList; -import java.util.List; -import jcs.JCS; -import jcs.commandStation.events.AccessoryEventListener; -import jcs.commandStation.events.SensorEventListener; -import jcs.entities.AccessoryBean; -import jcs.entities.SensorBean; -import jcs.entities.TileBean; -import jcs.entities.TileBean.Direction; -import jcs.entities.TileBean.Orientation; -import static jcs.entities.TileBean.TileType.BLOCK; -import static jcs.entities.TileBean.TileType.CROSS; -import static jcs.entities.TileBean.TileType.CROSSING; -import static jcs.entities.TileBean.TileType.CURVED; -import static jcs.entities.TileBean.TileType.END; -import static jcs.entities.TileBean.TileType.SENSOR; -import static jcs.entities.TileBean.TileType.SIGNAL; -import static jcs.entities.TileBean.TileType.STRAIGHT; -import static jcs.entities.TileBean.TileType.STRAIGHT_DIR; -import static jcs.entities.TileBean.TileType.SWITCH; -import org.tinylog.Logger; - -/** - * Factory object to create Tiles and cache tiles - * - * @author frans - */ -public class TileFactory { - - // Keep the records of the used id sequence number - private static int straightIdSeq; - private static int crossingIdSeq; - private static int curvedIdSeq; - private static int switchIdSeq; - private static int crossIdSeq; - private static int signalIdSeq; - private static int sensorIdSeq; - private static int blockIdSeq; - private static int straightDirectionIdSeq; - private static int endIdSeq; - - private TileFactory() { - } - - private static int nextIdSeq(String id) { - String idnr = id.substring(3); - int idSeq = Integer.parseInt(idnr); - return idSeq; - } - - private static String nextTileId(TileBean.TileType tileType) { - switch (tileType) { - case STRAIGHT -> { - straightIdSeq++; - return "st-" + straightIdSeq; - } - case CROSSING -> { - crossingIdSeq++; - return "cr-" + crossingIdSeq; - } - case CURVED -> { - curvedIdSeq++; - return "ct-" + curvedIdSeq; - } - case SWITCH -> { - switchIdSeq++; - return "sw-" + switchIdSeq; - } - case CROSS -> { - crossIdSeq++; - return "cs-" + crossIdSeq; - } - case SIGNAL -> { - signalIdSeq++; - return "si-" + signalIdSeq; - } - case SENSOR -> { - sensorIdSeq++; - return "se-" + sensorIdSeq; - } - case BLOCK -> { - blockIdSeq++; - return "bk-" + blockIdSeq; - } - case STRAIGHT_DIR -> { - straightDirectionIdSeq++; - return "sd-" + straightDirectionIdSeq; - } - case END -> { - endIdSeq++; - return "et-" + endIdSeq; - } - default -> { - Logger.warn("Unknown Tile Type " + tileType); - return null; - } - } - } - - private static int maxIdSeq(int currentId, int newId) { - if (currentId < newId) { - return newId; - } else { - return currentId; - } - } - - public static Tile createTile(String tileId) { - TileBean tileBean = JCS.getPersistenceService().getTileBean(tileId); - return createTile(tileBean); - } - - public static Tile createTile(TileBean tileBean) { - return createTile(tileBean, false); - } - - public static Tile createTile(TileBean tileBean, boolean showValues) { - if (tileBean == null) { - return null; - } - - TileBean.TileType tileType = tileBean.getTileType(); - Tile tile = null; - switch (tileType) { - case STRAIGHT -> { - tile = new Straight(tileBean); - straightIdSeq = maxIdSeq(straightIdSeq, nextIdSeq(tileBean.getId())); - } - case CROSSING -> { - tile = new Crossing(tileBean); - crossingIdSeq = maxIdSeq(crossingIdSeq, nextIdSeq(tileBean.getId())); - } - case CURVED -> { - tile = new Curved(tileBean); - curvedIdSeq = maxIdSeq(curvedIdSeq, nextIdSeq(tileBean.getId())); - } - case SWITCH -> { - tile = new Switch(tileBean); - tile.setAccessoryBean(tileBean.getAccessoryBean()); - - switchIdSeq = maxIdSeq(switchIdSeq, nextIdSeq(tileBean.getId())); - if (showValues && tileBean.getAccessoryBean() != null) { - tile.setAccessoryValue((tileBean.getAccessoryBean()).getAccessoryValue()); - } - JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); - } - case CROSS -> { - tile = new Cross(tileBean); - tile.setAccessoryBean(tileBean.getAccessoryBean()); - - crossIdSeq = maxIdSeq(crossIdSeq, nextIdSeq(tileBean.getId())); - if (showValues && tileBean.getAccessoryBean() != null) { - tile.setAccessoryValue((tileBean.getAccessoryBean()).getAccessoryValue()); - } - JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); - } - case SIGNAL -> { - tile = new Signal(tileBean); - tile.setAccessoryBean(tileBean.getAccessoryBean()); - - signalIdSeq = maxIdSeq(signalIdSeq, nextIdSeq(tileBean.getId())); - if (showValues && tileBean.getAccessoryBean() != null) { - ((Signal) tile).setSignalValue(((AccessoryBean) tileBean.getAccessoryBean()).getSignalValue()); - } - JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); - } - case SENSOR -> { - tile = new Sensor(tileBean); - tile.setSensorBean(tileBean.getSensorBean()); - sensorIdSeq = maxIdSeq(sensorIdSeq, nextIdSeq(tileBean.getId())); - - if (showValues && tileBean.getSensorBean() != null) { - ((Sensor) tile).setActive(((SensorBean) tileBean.getSensorBean()).isActive()); - } - JCS.getJcsCommandStation().addSensorEventListener((SensorEventListener) tile); - } - case BLOCK -> { - tile = new Block(tileBean); - tile.setBlockBean(tileBean.getBlockBean()); - blockIdSeq = maxIdSeq(blockIdSeq, nextIdSeq(tileBean.getId())); - } - case STRAIGHT_DIR -> { - tile = new StraightDirection(tileBean); - straightDirectionIdSeq = maxIdSeq(straightDirectionIdSeq, nextIdSeq(tileBean.getId())); - } - case END -> { - tile = new End(tileBean); - endIdSeq = maxIdSeq(endIdSeq, nextIdSeq(tileBean.getId())); - } - default -> - Logger.warn("Unknown Tile Type " + tileType); - } - - return (Tile) tile; - } - - public static void rollback(Tile tile) { - switch (tile.tileType) { - case STRAIGHT -> { - straightIdSeq--; - } - case CROSSING -> { - crossingIdSeq--; - } - case CURVED -> { - curvedIdSeq--; - } - case SWITCH -> { - switchIdSeq--; - } - case CROSS -> { - crossIdSeq--; - } - case SIGNAL -> { - signalIdSeq--; - } - case SENSOR -> { - sensorIdSeq--; - } - case BLOCK -> { - blockIdSeq--; - } - case STRAIGHT_DIR -> { - straightDirectionIdSeq--; - } - case END -> { - endIdSeq--; - } - } - - } - - /** - * @param tileType type of type to create - * @param orientation whether the orientation of the Tile is EAST, WEST, NORTH or SOUTH - * @param x the tile center X - * @param y the tile center Y - * @return a Tile object - */ - public static Tile createTile(TileBean.TileType tileType, Orientation orientation, int x, int y) { - return createTile(tileType, orientation, Direction.CENTER, x, y); - } - - /** - * @param tileType type of type to create - * @param orientation whether the orientation of the Tile is EAST, WEST, NORTH or SOUTH - * @param direction direction plays a role with Turnout tiles whether it goes to the Left or Right - * @param x the tile center X - * @param y the tile center Y - * @return a Tile object - */ - public static Tile createTile(TileBean.TileType tileType, Orientation orientation, Direction direction, int x, int y) { - return createTile(tileType, orientation, direction, new Point(x, y)); - } - - public static Tile createTile(TileBean.TileType tileType, Orientation orientation, Direction direction, Point center) { - Tile tile = null; - switch (tileType) { - case STRAIGHT -> { - tile = new Straight(orientation, center); - } - case CROSSING -> { - tile = new Crossing(orientation, center); - } - case CURVED -> - tile = new Curved(orientation, center); - case SWITCH -> - tile = new Switch(orientation, direction, center); - case CROSS -> - tile = new Cross(orientation, direction, center); - case SIGNAL -> - tile = new Signal(orientation, center); - case SENSOR -> - tile = new Sensor(orientation, center); - case BLOCK -> - tile = new Block(orientation, center); - case STRAIGHT_DIR -> - tile = new StraightDirection(orientation, center); - case END -> - tile = new End(orientation, center); - default -> - Logger.warn("Unknown Tile Type " + tileType); - } - - if (tile != null) { - tile.setId(nextTileId(tileType)); - } - - return (Tile) tile; - } - - public static List toTiles(List tileBeans, boolean drawOutline, boolean showValues) { - List tileList = new LinkedList<>(); - - for (TileBean tileBean : tileBeans) { - Tile tile = createTile(tileBean, showValues); - tileList.add(tile); - } - return tileList; - } - -} diff --git a/src/main/java/jcs/ui/layout/tiles/ui/CurvedUI.java b/src/main/java/jcs/ui/layout/tiles/ui/CurvedUI.java index 6f176c44..8ceb75f5 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/CurvedUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/CurvedUI.java @@ -19,7 +19,6 @@ import java.awt.Graphics2D; import javax.swing.JComponent; import javax.swing.plaf.ComponentUI; -import jcs.ui.layout.tiles.Tile; public class CurvedUI extends TileUI { diff --git a/src/main/java/jcs/ui/layout/tiles/ui/EndUI.java b/src/main/java/jcs/ui/layout/tiles/ui/EndUI.java index c79b3463..dd84ad21 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/EndUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/EndUI.java @@ -20,7 +20,6 @@ import java.awt.Graphics2D; import javax.swing.JComponent; import javax.swing.plaf.ComponentUI; -import jcs.ui.layout.tiles.Tile; public class EndUI extends TileUI { diff --git a/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java b/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java index da0c54c4..14fda899 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java @@ -33,7 +33,6 @@ import jcs.ui.layout.tiles.Tile; import jcs.ui.layout.tiles.TileCache; import jcs.ui.layout.tiles.TileModel; -import org.tinylog.Logger; public class SensorUI extends StraightUI implements MouseListener, MouseMotionListener { diff --git a/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java b/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java index 3ba5bec9..aa438f1c 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java @@ -33,7 +33,6 @@ import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.ui.layout.LayoutCanvas; -import jcs.ui.layout.LayoutUtil; import jcs.ui.layout.tiles.Tile; import static jcs.ui.layout.tiles.Tile.DEFAULT_BACKGROUND_COLOR; import static jcs.ui.layout.tiles.Tile.DEFAULT_TRACK_COLOR; diff --git a/src/test/java/jcs/commandStation/autopilot/AutoPilotTest.java b/src/test/java/jcs/commandStation/autopilot/AutoPilotTest.java index 930856ec..26470c86 100644 --- a/src/test/java/jcs/commandStation/autopilot/AutoPilotTest.java +++ b/src/test/java/jcs/commandStation/autopilot/AutoPilotTest.java @@ -31,7 +31,7 @@ import jcs.persistence.PersistenceService; import jcs.persistence.util.PersistenceTestHelper; import jcs.ui.layout.tiles.Tile; -import jcs.ui.layout.tiles.TileFactory; +import jcs.ui.layout.tiles.TileCache; import jcs.util.RunUtil; import static org.junit.Assert.assertEquals; import org.junit.jupiter.api.AfterAll; @@ -71,7 +71,7 @@ public AutoPilotTest() { //When running in a batch the default command station could be different.. CommandStationBean virt = ps.getCommandStation("virtual"); ps.changeDefaultCommandStation(virt); - + if (RunUtil.isWindows()) { Logger.info("Skipping tests on Windows!"); skipTest = true; @@ -358,7 +358,8 @@ public void testGetOnTrackLocomotives() { } System.out.println("getOnTrackLocomotives"); //Check is the test script has run well - List tiles = TileFactory.toTiles(ps.getTileBeans(), false, false); + //List tiles = TileFactory.toTiles(ps.getTileBeans(), false, false); + List tiles = TileCache.loadTiles(false); assertEquals(29, tiles.size()); List blocks = ps.getBlocks(); assertEquals(4, blocks.size()); diff --git a/src/test/java/jcs/ui/layout/TileTest.java b/src/test/java/jcs/ui/layout/TileTest.java index cd18f276..75c2fd1a 100644 --- a/src/test/java/jcs/ui/layout/TileTest.java +++ b/src/test/java/jcs/ui/layout/TileTest.java @@ -24,7 +24,7 @@ import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import jcs.ui.layout.tiles.Tile; -import jcs.ui.layout.tiles.TileFactory; +import jcs.ui.layout.tiles.TileCache; import static org.junit.Assert.*; import org.junit.Test; @@ -39,7 +39,7 @@ public TileTest() { @Test public void testgetCenterX() { System.out.println("getCenterX"); - Tile instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 180, 100); + Tile instance = TileCache.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 180, 100); int expResult = 180; int result = instance.getCenterX(); assertEquals(expResult, result); @@ -48,8 +48,7 @@ public void testgetCenterX() { @Test public void testgetCenterXZero() { System.out.println("getCenterX"); - Tile instance - = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 0, 0); + Tile instance = TileCache.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 0, 0); int expResult = 20; int result = instance.getCenterX(); assertEquals(expResult, result); @@ -58,13 +57,13 @@ public void testgetCenterXZero() { @Test public void testGetGridX() { System.out.println("getGridX"); - Tile instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 100, 100); + Tile instance = TileCache.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 100, 100); int expResult = 2; int result = (instance.getTileX() - Tile.GRID) / (Tile.GRID * 2); assertEquals(expResult, result); - instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 220, 220); + instance = TileCache.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 220, 220); expResult = 5; result = (instance.getTileX() - Tile.GRID) / (Tile.GRID * 2); @@ -74,7 +73,7 @@ public void testGetGridX() { @Test public void testgetCenterY() { System.out.println("getCenterY"); - Tile instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 180, 100); + Tile instance = TileCache.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 180, 100); int expResult = 100; int result = instance.getCenterY(); assertEquals(expResult, result); @@ -83,7 +82,7 @@ public void testgetCenterY() { @Test public void testgetCenterYZero() { System.out.println("getCenterY"); - Tile instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 0, 0); + Tile instance = TileCache.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 0, 0); int expResult = 20; int result = instance.getCenterY(); assertEquals(expResult, result); @@ -92,7 +91,7 @@ public void testgetCenterYZero() { @Test public void testGetGridY() { System.out.println("getGridY"); - Tile instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 100, 140); + Tile instance = TileCache.createTile(TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 100, 140); int expResult = 3; int result = (instance.getTileY() - Tile.GRID) / (Tile.GRID * 2); assertEquals(expResult, result); @@ -101,8 +100,7 @@ public void testGetGridY() { @Test public void testGetAllPoints() { System.out.println("getAllPoints"); - Tile instance - = TileFactory.createTile(TileBean.TileType.BLOCK, Orientation.WEST, Direction.CENTER, 220, 220); + Tile instance = TileCache.createTile(TileBean.TileType.BLOCK, Orientation.WEST, Direction.CENTER, 220, 220); Set expResult = new HashSet<>(); expResult.add(new Point(220, 220)); expResult.add(new Point(180, 220)); @@ -116,8 +114,7 @@ public void testGetAllPoints() { @Test public void testGetAltPointsBlock() { System.out.println("getAltPointsBlock"); - Tile instance - = TileFactory.createTile(TileBean.TileType.BLOCK, Orientation.WEST, Direction.CENTER, 220, 220); + Tile instance = TileCache.createTile(TileBean.TileType.BLOCK, Orientation.WEST, Direction.CENTER, 220, 220); Set expResult = new HashSet<>(); expResult.add(new Point(180, 220)); expResult.add(new Point(260, 220)); @@ -128,17 +125,15 @@ public void testGetAltPointsBlock() { @Test public void testGetAltPointsCross() { System.out.println("getAltPointsCross"); - Tile instanceE - = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.EAST, Direction.CENTER, 220, 220); + Tile instanceE = TileCache.createTile(TileBean.TileType.CROSS, Orientation.EAST, Direction.CENTER, 220, 220); Tile instanceS - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.SOUTH, Direction.CENTER, 220, 220); Tile instanceW - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.WEST, Direction.CENTER, 220, 220); Tile instanceN - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.NORTH, Direction.CENTER, 220, 220); Set expResultE = new HashSet<>(); @@ -175,31 +170,31 @@ public void testGetAltPointsCross() { public void testGetNeighborPointsCross() { System.out.println("getNeighborPointsCross"); Tile instanceEL - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.EAST, Direction.LEFT, 220, 220); Tile instanceER - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.EAST, Direction.RIGHT, 220, 220); Tile instanceWL - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.WEST, Direction.LEFT, 220, 220); Tile instanceWR - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.WEST, Direction.RIGHT, 220, 220); Tile instanceSL - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.SOUTH, Direction.LEFT, 220, 220); Tile instanceSR - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.SOUTH, Direction.RIGHT, 220, 220); Tile instanceNL - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.NORTH, Direction.LEFT, 220, 220); Tile instanceNR - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.NORTH, Direction.RIGHT, 220, 220); Map expResultEL = new HashMap<>(); @@ -287,23 +282,23 @@ public void testGetNeighborPointsCross() { public void testIsAdjacentStraight() { System.out.println("isAdjacentStraight"); Tile instanceE - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 100, 100); Tile instanceN - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 100, 100); Tile west - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 60, 100); Tile east - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 140, 100); Tile north - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 100, 60); Tile south - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 100, 140); assertTrue(instanceE.isAdjacent(west)); @@ -322,31 +317,31 @@ public void testIsAdjacentBlock() { System.out.println("isAdjacentBlock"); Tile instanceE - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.BLOCK, Orientation.EAST, Direction.CENTER, 220, 220); Tile instanceW - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.BLOCK, Orientation.WEST, Direction.CENTER, 220, 220); Tile instanceS - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.BLOCK, Orientation.SOUTH, Direction.CENTER, 220, 220); Tile instanceN - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.BLOCK, Orientation.NORTH, Direction.CENTER, 220, 220); Tile west - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 140, 220); Tile east - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 300, 220); Tile north - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 220, 140); Tile south - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 220, 300); assertTrue(instanceE.isAdjacent(west)); @@ -369,29 +364,29 @@ public void testIsAdjacentBlock() { public void testIsAdjacentCurved() { System.out.println("isAdjacentCurved"); Tile instanceE - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 860, 140); Tile instanceN - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 860, 140); Tile instanceW - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 860, 140); Tile instanceS - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 860, 140); Tile straightE - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 140); Tile straightN - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 100); Tile straightW - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 140); Tile straightS - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180); assertTrue(instanceE.isAdjacent(straightE)); @@ -420,29 +415,29 @@ public void testIsAdjacentEnd() { System.out.println("isAdjacentEnd"); Tile instanceE - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.END, Orientation.EAST, Direction.CENTER, 860, 140); Tile instanceS - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.END, Orientation.SOUTH, Direction.CENTER, 860, 140); Tile instanceW - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.END, Orientation.WEST, Direction.CENTER, 860, 140); Tile instanceN - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.END, Orientation.NORTH, Direction.CENTER, 860, 140); Tile straightE - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 140); Tile straightN - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 100); Tile straightW - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 140); Tile straightS - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180); assertFalse(instanceE.isAdjacent(straightE)); @@ -470,30 +465,30 @@ public void testIsAdjacentEnd() { public void testgetIdSuffix() { System.out.println("getGetIdSuffix"); Tile instanceE - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.BLOCK, Orientation.EAST, Direction.CENTER, 220, 220); Tile instanceW - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.BLOCK, Orientation.WEST, Direction.CENTER, 220, 220); Tile instanceN - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.BLOCK, Orientation.NORTH, Direction.CENTER, 220, 220); Tile instanceS - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.BLOCK, Orientation.SOUTH, Direction.CENTER, 220, 220); Tile west - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 140, 220); Tile east - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 300, 220); Tile north - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 220, 140); Tile south - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 220, 300); String expResult = "-"; @@ -524,55 +519,55 @@ public void testgetIdSuffix() { public void testIsAdjacentSwitchL() { System.out.println("isAdjacentSwitchL"); Tile instanceE - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.SWITCH, Orientation.EAST, Direction.LEFT, 1060, 140); Tile instanceS - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.SWITCH, Orientation.SOUTH, Direction.LEFT, 1060, 140); Tile instanceW - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.SWITCH, Orientation.WEST, Direction.LEFT, 1060, 140); Tile instanceN - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.SWITCH, Orientation.NORTH, Direction.LEFT, 1060, 140); Tile north - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 1060, 100); Tile west - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 1020, 140); Tile east - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 1100, 140); Tile south - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 1060, 180); Tile westCS - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 1020, 140); Tile westCE - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 1020, 140); Tile westCW - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 1020, 140); Tile westCN - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 1020, 140); Tile southCS - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 1060, 180); Tile southCE - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 1060, 180); Tile southCW - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 1060, 180); Tile southCN - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 1060, 180); assertTrue(instanceE.isAdjacent(west)); @@ -610,55 +605,55 @@ public void testIsAdjacentSwitchL() { public void testIsAdjacentSwitchR() { System.out.println("isAdjacentSwitchR"); Tile instanceE - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.SWITCH, Orientation.EAST, Direction.RIGHT, 1060, 140); Tile instanceS - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.SWITCH, Orientation.SOUTH, Direction.RIGHT, 1060, 140); Tile instanceW - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.SWITCH, Orientation.WEST, Direction.RIGHT, 1060, 140); Tile instanceN - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.SWITCH, Orientation.NORTH, Direction.RIGHT, 1060, 140); Tile north - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 1060, 100); Tile west - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 1020, 140); Tile east - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 1100, 140); Tile south - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 1060, 180); Tile eastCS - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 1100, 140); Tile eastCE - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 1100, 140); Tile eastCW - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 1100, 140); Tile eastCN - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 1100, 140); Tile northCS - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 1060, 100); Tile northCE - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 1060, 100); Tile northCW - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 1060, 100); Tile northCN - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 1060, 100); assertTrue(instanceE.isAdjacent(west)); @@ -696,29 +691,29 @@ public void testIsAdjacentSwitchR() { public void testIsArrowSwitchSide() { System.out.println("isArrowSwitchSide"); Tile instanceE - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT_DIR, Orientation.EAST, Direction.RIGHT, 860, 140); Tile instanceS - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT_DIR, Orientation.SOUTH, Direction.RIGHT, 860, 140); Tile instanceW - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT_DIR, Orientation.WEST, Direction.RIGHT, 860, 140); Tile instanceN - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT_DIR, Orientation.NORTH, Direction.RIGHT, 860, 140); Tile straighE - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 140); Tile straighS - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180); Tile straighW - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 140); Tile straighN - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 100); assertTrue(instanceE.isArrowDirection(straighE)); @@ -738,53 +733,53 @@ public void testIsArrowSwitchSide() { public void testIsAdjacentCrossL() { System.out.println("iIsAdjacentCrossL"); Tile instanceE - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.EAST, Direction.LEFT, 860, 100); Tile instanceS - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.SOUTH, Direction.LEFT, 860, 100); Tile instanceW - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.WEST, Direction.LEFT, 860, 100); Tile instanceN - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.NORTH, Direction.LEFT, 860, 100); Tile north - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 900, 60); Tile north2 - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 60); Tile north3 - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 20); Tile west - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 100); Tile west2 - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 780, 100); Tile west3 - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 60); Tile east - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 940, 100); Tile east2 - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 100); Tile east3 - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 140); Tile south - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 140); Tile south2 - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 820, 140); Tile south3 - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180); assertTrue(instanceE.isAdjacent(west)); @@ -812,60 +807,60 @@ public void testIsAdjacentCrossL() { public void testIsAdjacentCrossR() { System.out.println("iIsAdjacentCrossR"); Tile instanceE - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.EAST, Direction.RIGHT, 860, 100); Tile instanceS - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.SOUTH, Direction.RIGHT, 860, 100); Tile instanceW - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.WEST, Direction.RIGHT, 860, 100); Tile instanceN - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.NORTH, Direction.RIGHT, 860, 100); Tile north - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 60); Tile north2 - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 60); Tile north3 - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 20); Tile north4 - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 820, 60); Tile west - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 140); Tile west2 - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 100); Tile west3 - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 860, 100); Tile west4 - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 780, 100); Tile east - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 940, 100); Tile east2 - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 60); Tile east3 - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 100); Tile south - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 140); Tile south2 - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 900, 140); Tile south3 - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180); assertTrue(instanceE.isAdjacent(west2)); @@ -892,14 +887,14 @@ public void testIsAdjacentCrossR() { @Test public void testIsAdjacentCrossing() { System.out.println("isAdjacentCrossing"); - Tile instanceE = TileFactory.createTile(TileBean.TileType.CROSSING, Orientation.EAST, Direction.CENTER, 100, 100); + Tile instanceE = TileCache.createTile(TileBean.TileType.CROSSING, Orientation.EAST, Direction.CENTER, 100, 100); - Tile instanceN = TileFactory.createTile(TileBean.TileType.CROSSING, Orientation.NORTH, Direction.CENTER, 100, 100); + Tile instanceN = TileCache.createTile(TileBean.TileType.CROSSING, Orientation.NORTH, Direction.CENTER, 100, 100); - Tile west = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 60, 100); - Tile east = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 140, 100); - Tile north = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 100, 60); - Tile south = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 100, 140); + Tile west = TileCache.createTile(TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 60, 100); + Tile east = TileCache.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 140, 100); + Tile north = TileCache.createTile(TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 100, 60); + Tile south = TileCache.createTile(TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 100, 140); assertTrue(instanceE.isAdjacent(west)); assertTrue(instanceE.isAdjacent(east)); diff --git a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossLeftEast.java b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossLeftEast.java index cda2231c..f388fdb0 100644 --- a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossLeftEast.java +++ b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossLeftEast.java @@ -18,10 +18,9 @@ import java.util.ArrayList; import java.util.List; import jcs.entities.RouteBean; -import jcs.persistence.PersistenceFactory; import jcs.persistence.util.PersistenceTestHelper; import jcs.ui.layout.tiles.Tile; -import jcs.ui.layout.tiles.TileFactory; +import jcs.ui.layout.tiles.TileCache; import org.junit.After; import static org.junit.Assert.assertEquals; import org.junit.Before; @@ -54,7 +53,8 @@ public void tearDown() { @Test public void testBuildGraph() { System.out.println("buildGraph"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = TileCache.loadTiles(false); + assertEquals(21, tiles.size()); AStar instance = new AStar(); instance.buildGraph(tiles); @@ -68,7 +68,8 @@ public void testBuildGraph() { @Test public void testGetAllBlockToBlockNodes() { System.out.println("getAllBlockToBlockNodes"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = TileCache.loadTiles(false); + AStar instance = new AStar(); instance.buildGraph(tiles); List> result = instance.getAllBlockToBlockNodes(); @@ -86,7 +87,8 @@ public void testFindPath_bk_1p_bk2m() { String toNodeId = "bk-2"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = TileCache.loadTiles(false); + instance.buildGraph(tiles); String expPath = "[bk-1+]->[bk-2-]: bk-1+[bk-1] -> st-1 -> st-2 -> cs-3[GREEN] -> st-5 -> st-6 -> bk-2-[bk-2]"; @@ -107,7 +109,8 @@ public void testFindPath_bk_4m_bk3p() { String toNodeId = "bk-3"; String toSuffix = "+"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = TileCache.loadTiles(false); + instance.buildGraph(tiles); String expPath = "[bk-4-]->[bk-3+]: bk-4-[bk-4] -> st-29 -> st-30 -> cs-3[GREEN] -> st-25 -> st-26 -> bk-3+[bk-3]"; @@ -124,7 +127,8 @@ public void testFindPath_bk_2m_bk4m() { String toNodeId = "bk-4"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = TileCache.loadTiles(false); + instance.buildGraph(tiles); String expPath = ""; @@ -141,7 +145,8 @@ public void testFindPath_bk_2m_bk3p() { String toNodeId = "bk-3"; String toSuffix = "+"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = TileCache.loadTiles(false); + instance.buildGraph(tiles); String expPath = "[bk-2-]->[bk-3+]: bk-2-[bk-2] -> st-6 -> st-5 -> cs-3[RED] -> st-25 -> st-26 -> bk-3+[bk-3]"; @@ -156,7 +161,7 @@ public void testFindPath_bk_2m_bk3p() { @Test public void testRouteAll() { System.out.println("routeAll"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = TileCache.loadTiles(false); List expRouteDesc = new ArrayList<>(); diff --git a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossLeftSouth.java b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossLeftSouth.java index 7ed22ab3..aa13a460 100644 --- a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossLeftSouth.java +++ b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossLeftSouth.java @@ -18,10 +18,8 @@ import java.util.ArrayList; import java.util.List; import jcs.entities.RouteBean; -import jcs.persistence.PersistenceFactory; import jcs.persistence.util.PersistenceTestHelper; import jcs.ui.layout.tiles.Tile; -import jcs.ui.layout.tiles.TileFactory; import org.junit.After; import static org.junit.Assert.assertEquals; import org.junit.Before; @@ -54,7 +52,7 @@ public void tearDown() { @Test public void testBuildGraph() { System.out.println("buildGraph"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); assertEquals(21, tiles.size()); AStar instance = new AStar(); instance.buildGraph(tiles); @@ -68,7 +66,7 @@ public void testBuildGraph() { @Test public void testGetAllBlockToBlockNodes() { System.out.println("getAllBlockToBlockNodes"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); AStar instance = new AStar(); instance.buildGraph(tiles); List> result = instance.getAllBlockToBlockNodes(); @@ -86,7 +84,7 @@ public void testFindPath_bk_1p_bk2m() { String toNodeId = "bk-2"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = "[bk-1+]->[bk-2-]: bk-1+[bk-1] -> st-1 -> st-2 -> cs-3[GREEN] -> st-5 -> st-6 -> bk-2-[bk-2]"; @@ -107,7 +105,7 @@ public void testFindPath_bk_4m_bk3p() { String toNodeId = "bk-3"; String toSuffix = "+"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = "[bk-4-]->[bk-3+]: bk-4-[bk-4] -> st-29 -> st-30 -> cs-3[GREEN] -> st-25 -> st-26 -> bk-3+[bk-3]"; @@ -124,7 +122,7 @@ public void testFindPath_bk_2m_bk4m() { String toNodeId = "bk-4"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = "[bk-2-]->[bk-4-]: bk-2-[bk-2] -> st-6 -> st-5 -> cs-3[RED] -> st-30 -> st-29 -> bk-4-[bk-4]"; @@ -141,7 +139,7 @@ public void testFindPath_bk_2m_bk3p() { String toNodeId = "bk-3"; String toSuffix = "+"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = ""; @@ -156,7 +154,7 @@ public void testFindPath_bk_2m_bk3p() { @Test public void testRouteAll() { System.out.println("routeAll"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); List expRouteDesc = new ArrayList<>(); diff --git a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossRightEast.java b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossRightEast.java index 1de71214..53b2a7e8 100644 --- a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossRightEast.java +++ b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossRightEast.java @@ -18,10 +18,8 @@ import java.util.ArrayList; import java.util.List; import jcs.entities.RouteBean; -import jcs.persistence.PersistenceFactory; import jcs.persistence.util.PersistenceTestHelper; import jcs.ui.layout.tiles.Tile; -import jcs.ui.layout.tiles.TileFactory; import org.junit.After; import static org.junit.Assert.assertEquals; import org.junit.Before; @@ -54,7 +52,7 @@ public void tearDown() { @Test public void testBuildGraph() { System.out.println("buildGraph"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); assertEquals(21, tiles.size()); AStar instance = new AStar(); instance.buildGraph(tiles); @@ -68,7 +66,7 @@ public void testBuildGraph() { @Test public void testGetAllBlockToBlockNodes() { System.out.println("getAllBlockToBlockNodes"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); AStar instance = new AStar(); instance.buildGraph(tiles); List> result = instance.getAllBlockToBlockNodes(); @@ -86,7 +84,7 @@ public void testFindPath_bk_1p_bk2m() { String toNodeId = "bk-2"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = "[bk-1+]->[bk-2-]: bk-1+[bk-1] -> st-1 -> st-2 -> cs-2[GREEN] -> st-5 -> st-6 -> bk-2-[bk-2]"; @@ -107,7 +105,7 @@ public void testFindPath_bk_4m_bk3p() { String toNodeId = "bk-3"; String toSuffix = "+"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = "[bk-4-]->[bk-3+]: bk-4-[bk-4] -> st-29 -> st-30 -> cs-2[GREEN] -> st-25 -> st-26 -> bk-3+[bk-3]"; @@ -124,7 +122,7 @@ public void testFindPath_bk_2m_bk4m() { String toNodeId = "bk-4"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = "[bk-2-]->[bk-4-]: bk-2-[bk-2] -> st-6 -> st-5 -> cs-2[RED] -> st-30 -> st-29 -> bk-4-[bk-4]"; @@ -141,7 +139,7 @@ public void testFindPath_bk_2m_bk3p() { String toNodeId = "bk-3"; String toSuffix = "+"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = ""; @@ -156,7 +154,7 @@ public void testFindPath_bk_2m_bk3p() { @Test public void testRouteAll() { System.out.println("routeAll"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); List expRouteDesc = new ArrayList<>(); diff --git a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossRightSouth.java b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossRightSouth.java index ecba391b..4ad7e132 100644 --- a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossRightSouth.java +++ b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossRightSouth.java @@ -18,10 +18,8 @@ import java.util.ArrayList; import java.util.List; import jcs.entities.RouteBean; -import jcs.persistence.PersistenceFactory; import jcs.persistence.util.PersistenceTestHelper; import jcs.ui.layout.tiles.Tile; -import jcs.ui.layout.tiles.TileFactory; import org.junit.After; import static org.junit.Assert.assertEquals; import org.junit.Before; @@ -54,7 +52,7 @@ public void tearDown() { @Test public void testBuildGraph() { System.out.println("buildGraph"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); assertEquals(21, tiles.size()); AStar instance = new AStar(); instance.buildGraph(tiles); @@ -68,7 +66,7 @@ public void testBuildGraph() { @Test public void testGetAllBlockToBlockNodes() { System.out.println("getAllBlockToBlockNodes"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); AStar instance = new AStar(); instance.buildGraph(tiles); List> result = instance.getAllBlockToBlockNodes(); @@ -86,7 +84,7 @@ public void testFindPath_bk_1p_bk2m() { String toNodeId = "bk-2"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = "[bk-1+]->[bk-2-]: bk-1+[bk-1] -> st-1 -> st-2 -> cs-2[GREEN] -> st-5 -> st-6 -> bk-2-[bk-2]"; @@ -107,7 +105,7 @@ public void testFindPath_bk_4m_bk3p() { String toNodeId = "bk-3"; String toSuffix = "+"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = "[bk-4-]->[bk-3+]: bk-4-[bk-4] -> st-29 -> st-30 -> cs-2[GREEN] -> st-25 -> st-26 -> bk-3+[bk-3]"; @@ -124,7 +122,7 @@ public void testFindPath_bk_2m_bk4m() { String toNodeId = "bk-4"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = ""; @@ -141,7 +139,7 @@ public void testFindPath_bk_2m_bk3p() { String toNodeId = "bk-3"; String toSuffix = "+"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = "[bk-2-]->[bk-3+]: bk-2-[bk-2] -> st-6 -> st-5 -> cs-2[RED] -> st-25 -> st-26 -> bk-3+[bk-3]"; @@ -156,7 +154,7 @@ public void testFindPath_bk_2m_bk3p() { @Test public void testRouteAll() { System.out.println("routeAll"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); List expRouteDesc = new ArrayList<>(); diff --git a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossingTest.java b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossingTest.java index f558911e..ca7e2626 100644 --- a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossingTest.java +++ b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossingTest.java @@ -18,10 +18,8 @@ import java.util.ArrayList; import java.util.List; import jcs.entities.RouteBean; -import jcs.persistence.PersistenceFactory; import jcs.persistence.util.PersistenceTestHelper; import jcs.ui.layout.tiles.Tile; -import jcs.ui.layout.tiles.TileFactory; import org.junit.After; import static org.junit.Assert.assertEquals; import org.junit.Before; @@ -54,7 +52,8 @@ public void tearDown() { @Test public void testBuildGraph() { System.out.println("buildGraph"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); + assertEquals(21, tiles.size()); AStar instance = new AStar(); instance.buildGraph(tiles); @@ -68,7 +67,8 @@ public void testBuildGraph() { @Test public void testGetAllBlockToBlockNodes() { System.out.println("getAllBlockToBlockNodes"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); + AStar instance = new AStar(); instance.buildGraph(tiles); List> result = instance.getAllBlockToBlockNodes(); @@ -86,7 +86,8 @@ public void testFindPath_bk_1p_bk2m() { String toNodeId = "bk-2"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); + instance.buildGraph(tiles); String expPath = "[bk-1+]->[bk-2-]: bk-1+[bk-1] -> st-1 -> st-2 -> cr-1 -> st-5 -> st-6 -> bk-2-[bk-2]"; @@ -107,7 +108,8 @@ public void testFindPath_bk_4m_bk3p() { String toNodeId = "bk-3"; String toSuffix = "+"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); + instance.buildGraph(tiles); String expPath = "[bk-4-]->[bk-3+]: bk-4-[bk-4] -> st-29 -> st-30 -> cr-1 -> st-25 -> st-26 -> bk-3+[bk-3]"; @@ -124,7 +126,8 @@ public void testFindPath_bk_2m_bk4m() { String toNodeId = "bk-4"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); + instance.buildGraph(tiles); String expPath = ""; @@ -139,7 +142,7 @@ public void testFindPath_bk_2m_bk4m() { @Test public void testRouteAll() { System.out.println("routeAll"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); List expRouteDesc = new ArrayList<>(); diff --git a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftEast.java b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftEast.java index c907b6fb..83ab13a6 100644 --- a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftEast.java +++ b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftEast.java @@ -18,10 +18,8 @@ import java.util.ArrayList; import java.util.List; import jcs.entities.RouteBean; -import jcs.persistence.PersistenceFactory; import jcs.persistence.util.PersistenceTestHelper; import jcs.ui.layout.tiles.Tile; -import jcs.ui.layout.tiles.TileFactory; import org.junit.After; import static org.junit.Assert.assertEquals; import org.junit.Before; @@ -54,7 +52,8 @@ public void tearDown() { @Test public void testBuildGraph() { System.out.println("buildGraph"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); + assertEquals(21, tiles.size()); AStar instance = new AStar(); instance.buildGraph(tiles); @@ -68,7 +67,8 @@ public void testBuildGraph() { @Test public void testGetAllBlockToBlockNodes() { System.out.println("getAllBlockToBlockNodes"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); + AStar instance = new AStar(); instance.buildGraph(tiles); List> result = instance.getAllBlockToBlockNodes(); @@ -86,7 +86,8 @@ public void testFindPath_bk_1p_bk2m() { String toNodeId = "bk-2"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); + instance.buildGraph(tiles); String expPath = "[bk-1+]->[bk-2-]: bk-1+[bk-1] -> st-1 -> st-2 -> sw-1[GREEN] -> st-5 -> st-6 -> bk-2-[bk-2]"; @@ -107,7 +108,8 @@ public void testFindPath_bk_4m_bk3p() { String toNodeId = "bk-3"; String toSuffix = "+"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); + instance.buildGraph(tiles); String expPath = ""; @@ -124,7 +126,8 @@ public void testFindPath_bk_2m_bk4m() { String toNodeId = "bk-4"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); + instance.buildGraph(tiles); String expPath = ""; @@ -141,7 +144,8 @@ public void testFindPath_bk_2m_bk3p() { String toNodeId = "bk-3"; String toSuffix = "+"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); + instance.buildGraph(tiles); String expPath = "[bk-2-]->[bk-3+]: bk-2-[bk-2] -> st-6 -> st-5 -> sw-1[RED] -> st-25 -> st-26 -> bk-3+[bk-3]"; @@ -156,7 +160,7 @@ public void testFindPath_bk_2m_bk3p() { @Test public void testRouteAll() { System.out.println("routeAll"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); List expRouteDesc = new ArrayList<>(); diff --git a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftNorth.java b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftNorth.java index 56e2caa5..cf091c8f 100644 --- a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftNorth.java +++ b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftNorth.java @@ -18,10 +18,8 @@ import java.util.ArrayList; import java.util.List; import jcs.entities.RouteBean; -import jcs.persistence.PersistenceFactory; import jcs.persistence.util.PersistenceTestHelper; import jcs.ui.layout.tiles.Tile; -import jcs.ui.layout.tiles.TileFactory; import org.junit.After; import static org.junit.Assert.assertEquals; import org.junit.Before; @@ -54,7 +52,7 @@ public void tearDown() { @Test public void testBuildGraph() { System.out.println("buildGraph"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); assertEquals(21, tiles.size()); AStar instance = new AStar(); instance.buildGraph(tiles); @@ -68,7 +66,7 @@ public void testBuildGraph() { @Test public void testGetAllBlockToBlockNodes() { System.out.println("getAllBlockToBlockNodes"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); AStar instance = new AStar(); instance.buildGraph(tiles); List> result = instance.getAllBlockToBlockNodes(); @@ -86,7 +84,7 @@ public void testFindPath_bk_1p_bk2m() { String toNodeId = "bk-2"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = ""; @@ -107,7 +105,7 @@ public void testFindPath_bk_4m_bk3p() { String toNodeId = "bk-3"; String toSuffix = "+"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = "[bk-4-]->[bk-3+]: bk-4-[bk-4] -> st-29 -> st-30 -> sw-1[GREEN] -> st-25 -> st-26 -> bk-3+[bk-3]"; @@ -124,7 +122,7 @@ public void testFindPath_bk_2m_bk4m() { String toNodeId = "bk-4"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = "[bk-2-]->[bk-4-]: bk-2-[bk-2] -> st-6 -> st-5 -> sw-1[RED] -> st-30 -> st-29 -> bk-4-[bk-4]"; @@ -141,7 +139,7 @@ public void testFindPath_bk_2m_bk3p() { String toNodeId = "bk-3"; String toSuffix = "+"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = ""; @@ -156,7 +154,7 @@ public void testFindPath_bk_2m_bk3p() { @Test public void testRouteAll() { System.out.println("routeAll"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); List expRouteDesc = new ArrayList<>(); diff --git a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftSouth.java b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftSouth.java index a6d53691..772669e6 100644 --- a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftSouth.java +++ b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftSouth.java @@ -18,10 +18,8 @@ import java.util.ArrayList; import java.util.List; import jcs.entities.RouteBean; -import jcs.persistence.PersistenceFactory; import jcs.persistence.util.PersistenceTestHelper; import jcs.ui.layout.tiles.Tile; -import jcs.ui.layout.tiles.TileFactory; import org.junit.After; import static org.junit.Assert.assertEquals; import org.junit.Before; @@ -54,7 +52,7 @@ public void tearDown() { @Test public void testBuildGraph() { System.out.println("buildGraph"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); assertEquals(21, tiles.size()); AStar instance = new AStar(); instance.buildGraph(tiles); @@ -68,7 +66,8 @@ public void testBuildGraph() { @Test public void testGetAllBlockToBlockNodes() { System.out.println("getAllBlockToBlockNodes"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); + AStar instance = new AStar(); instance.buildGraph(tiles); List> result = instance.getAllBlockToBlockNodes(); @@ -86,7 +85,7 @@ public void testFindPath_bk_1p_bk2m() { String toNodeId = "bk-2"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = ""; @@ -107,7 +106,7 @@ public void testFindPath_bk_4m_bk3p() { String toNodeId = "bk-3"; String toSuffix = "+"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = "[bk-4-]->[bk-3+]: bk-4-[bk-4] -> st-29 -> st-30 -> sw-1[GREEN] -> st-25 -> st-26 -> bk-3+[bk-3]"; @@ -124,7 +123,8 @@ public void testFindPath_bk_2m_bk4m() { String toNodeId = "bk-4"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); + instance.buildGraph(tiles); String expPath = ""; @@ -141,7 +141,7 @@ public void testFindPath_bk_2m_bk3p() { String toNodeId = "bk-3"; String toSuffix = "+"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = ""; @@ -156,7 +156,7 @@ public void testFindPath_bk_2m_bk3p() { @Test public void testRouteAll() { System.out.println("routeAll"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); List expRouteDesc = new ArrayList<>(); diff --git a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftWest.java b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftWest.java index 81797259..f980b320 100644 --- a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftWest.java +++ b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftWest.java @@ -18,10 +18,8 @@ import java.util.ArrayList; import java.util.List; import jcs.entities.RouteBean; -import jcs.persistence.PersistenceFactory; import jcs.persistence.util.PersistenceTestHelper; import jcs.ui.layout.tiles.Tile; -import jcs.ui.layout.tiles.TileFactory; import org.junit.After; import static org.junit.Assert.assertEquals; import org.junit.Before; @@ -54,7 +52,7 @@ public void tearDown() { @Test public void testBuildGraph() { System.out.println("buildGraph"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); assertEquals(21, tiles.size()); AStar instance = new AStar(); instance.buildGraph(tiles); @@ -68,7 +66,7 @@ public void testBuildGraph() { @Test public void testGetAllBlockToBlockNodes() { System.out.println("getAllBlockToBlockNodes"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); AStar instance = new AStar(); instance.buildGraph(tiles); List> result = instance.getAllBlockToBlockNodes(); @@ -86,7 +84,7 @@ public void testFindPath_bk_1p_bk2m() { String toNodeId = "bk-2"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = "[bk-1+]->[bk-2-]: bk-1+[bk-1] -> st-1 -> st-2 -> sw-1[GREEN] -> st-5 -> st-6 -> bk-2-[bk-2]"; @@ -107,7 +105,8 @@ public void testFindPath_bk_4m_bk3p() { String toNodeId = "bk-3"; String toSuffix = "+"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); + instance.buildGraph(tiles); String expPath = ""; @@ -124,7 +123,7 @@ public void testFindPath_bk_2m_bk4m() { String toNodeId = "bk-4"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = ""; @@ -141,7 +140,7 @@ public void testFindPath_bk_2m_bk3p() { String toNodeId = "bk-3"; String toSuffix = "+"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = ""; @@ -156,7 +155,7 @@ public void testFindPath_bk_2m_bk3p() { @Test public void testRouteAll() { System.out.println("routeAll"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); List expRouteDesc = new ArrayList<>(); diff --git a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarTest.java b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarTest.java index 314b1ded..f7d905d2 100644 --- a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarTest.java +++ b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarTest.java @@ -18,10 +18,8 @@ import java.util.ArrayList; import java.util.List; import jcs.entities.RouteBean; -import jcs.persistence.PersistenceFactory; import jcs.persistence.util.PersistenceTestHelper; import jcs.ui.layout.tiles.Tile; -import jcs.ui.layout.tiles.TileFactory; import org.junit.After; import static org.junit.Assert.assertEquals; import org.junit.Before; @@ -55,7 +53,7 @@ public void tearDown() { @Test public void testBuildGraph() { System.out.println("buildGraph"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); assertEquals(37, tiles.size()); AStar instance = new AStar(); instance.buildGraph(tiles); @@ -69,7 +67,7 @@ public void testBuildGraph() { @Test public void testGetAllBlockToBlockNodes() { System.out.println("getAllBlockToBlockNodes"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); AStar instance = new AStar(); instance.buildGraph(tiles); List> result = instance.getAllBlockToBlockNodes(); @@ -87,7 +85,7 @@ public void testFindPathbk_2p_bkm3() { String toNodeId = "bk-3"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = "[bk-2+]->[bk-3-]: bk-2+[bk-2] -> se-3 -> st-4 -> ct-1 -> sw-2[RED] -> st-5 -> ct-4 -> st-11 -> st-12 -> st-13 -> st-14 -> ct-6 -> st-20 -> st-19 -> st-18 -> se-6 -> bk-3-[bk-3]"; @@ -108,7 +106,7 @@ public void testFindPathbk_2m_bkm3() { String toNodeId = "bk-3"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = ""; List path = instance.findPath(fromNodeId, fromSuffix, toNodeId, toSuffix); @@ -122,7 +120,7 @@ public void testFindPathbk_2m_bkm3() { //@Test public void testRouteAll() { System.out.println("routeAll"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); List expRouteDesc = new ArrayList<>(); @@ -164,7 +162,7 @@ public void testRouteAll() { //@Test public void testGetRoute() { System.out.println("getRoute"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); AStar instance = new AStar(); instance.buildGraph(tiles); List routeBeans = instance.routeAll(); diff --git a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarTestWithDirection.java b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarTestWithDirection.java index eaed4cb2..ccd8b00a 100644 --- a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarTestWithDirection.java +++ b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarTestWithDirection.java @@ -18,10 +18,8 @@ import java.util.ArrayList; import java.util.List; import jcs.entities.RouteBean; -import jcs.persistence.PersistenceFactory; import jcs.persistence.util.PersistenceTestHelper; import jcs.ui.layout.tiles.Tile; -import jcs.ui.layout.tiles.TileFactory; import org.junit.After; import static org.junit.Assert.assertEquals; import org.junit.Before; @@ -55,7 +53,7 @@ public void tearDown() { @Test public void testBuildGraph() { System.out.println("buildGraph"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); assertEquals(37, tiles.size()); AStar instance = new AStar(); instance.buildGraph(tiles); @@ -69,7 +67,7 @@ public void testBuildGraph() { @Test public void testGetAllBlockToBlockNodes() { System.out.println("getAllBlockToBlockNodes"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); AStar instance = new AStar(); instance.buildGraph(tiles); List> result = instance.getAllBlockToBlockNodes(); @@ -87,7 +85,7 @@ public void testFindPathbk_2p_bkm3() { String toNodeId = "bk-3"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = "[bk-2+]->[bk-3-]: bk-2+[bk-2] -> se-3 -> sd-3 -> ct-1 -> sw-2[RED] -> st-5 -> ct-4 -> st-11 -> st-12 -> st-13 -> st-14 -> ct-6 -> st-20 -> st-19 -> st-18 -> se-6 -> bk-3-[bk-3]"; @@ -108,7 +106,7 @@ public void testFindPathbk_2p_bk3m() { String toNodeId = "bk-3"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = "[bk-2+]->[bk-3-]: bk-2+[bk-2] -> se-3 -> sd-3 -> ct-1 -> sw-2[RED] -> st-5 -> ct-4 -> st-11 -> st-12 -> st-13 -> st-14 -> ct-6 -> st-20 -> st-19 -> st-18 -> se-6 -> bk-3-[bk-3]"; @@ -129,7 +127,7 @@ public void testFindPathbk_2m_bk3p() { String toNodeId = "bk-3"; String toSuffix = "+"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = ""; List path = instance.findPath(fromNodeId, fromSuffix, toNodeId, toSuffix); @@ -143,7 +141,7 @@ public void testFindPathbk_2m_bk3p() { @Test public void testRouteAll() { System.out.println("routeAll"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); List expRouteDesc = new ArrayList<>(); @@ -177,7 +175,7 @@ public void testRouteAll() { //@Test public void testGetRoute() { System.out.println("getRoute"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); AStar instance = new AStar(); instance.buildGraph(tiles); List routeBeans = instance.routeAll(); diff --git a/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java b/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java index 3aa327eb..2f35c035 100644 --- a/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java +++ b/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java @@ -1 +1 @@ -/* * Copyright 2024 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.Color; import java.awt.Point; import javax.swing.ComboBoxModel; import javax.swing.DefaultComboBoxModel; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.AccessoryValue; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import jcs.entities.TileBean.TileType; import jcs.ui.layout.LayoutUtil; import org.tinylog.Logger; public class TileTesterFrame extends javax.swing.JFrame { private Tile tile; public TileTesterFrame() { initComponents(); this.tileCB.setModel(createTileTypeComboBoxModel()); this.orientationCB.setModel(createOrientationComboBoxModel()); this.incomingSideCB.setModel(createOrientationComboBoxModel()); this.directionCB.setModel(createDirectionComboBoxModel(true)); createTile(); pack(); setVisible(true); } private ComboBoxModel createTileTypeComboBoxModel() { DefaultComboBoxModel tileTypeModel = new DefaultComboBoxModel(); tileTypeModel.addElement(TileBean.TileType.STRAIGHT); tileTypeModel.addElement(TileBean.TileType.STRAIGHT_DIR); tileTypeModel.addElement(TileBean.TileType.SENSOR); tileTypeModel.addElement(TileBean.TileType.SIGNAL); tileTypeModel.addElement(TileBean.TileType.END); tileTypeModel.addElement(TileBean.TileType.CROSSING); tileTypeModel.addElement(TileBean.TileType.CURVED); tileTypeModel.addElement(TileBean.TileType.SWITCH); tileTypeModel.addElement(TileBean.TileType.CROSS); return tileTypeModel; } private ComboBoxModel createOrientationComboBoxModel() { DefaultComboBoxModel orientationModel = new DefaultComboBoxModel(); orientationModel.addElement(Orientation.EAST); orientationModel.addElement(Orientation.SOUTH); orientationModel.addElement(Orientation.WEST); orientationModel.addElement(Orientation.NORTH); return orientationModel; } private ComboBoxModel createDirectionComboBoxModel(boolean dontCare) { DefaultComboBoxModel directionModel = new DefaultComboBoxModel(); if (dontCare) { directionModel.addElement(Direction.CENTER); } else { directionModel.addElement(Direction.LEFT); directionModel.addElement(Direction.RIGHT); } return directionModel; } private void createTile() { if (tile != null) { Logger.trace("Removing tile " + tile.getId()); canvas.remove(tile); tile = null; } TileType tileType = (TileType) tileCB.getSelectedItem(); Orientation orientation = (Orientation) orientationCB.getSelectedItem(); if (TileType.SWITCH == tileType || TileType.CROSS == tileType) { directionCB.setModel(createDirectionComboBoxModel(false)); } else { directionCB.setModel(createDirectionComboBoxModel(true)); } Direction direction = (Direction) this.directionCB.getSelectedItem(); boolean scale = !scaleCB.isSelected(); boolean showCenter = showCenterCB.isSelected(); int w = canvas.getWidth(); int h = canvas.getHeight(); int x = w / 2; int y = h / 2; Point tileCenter = new Point(x, y); tileCenter = LayoutUtil.snapToGrid(tileCenter); Tile newTile = TileFactory.createTile(tileType, orientation, direction, tileCenter); newTile.setScaleImage(scale); newTile.setDrawCenterPoint(showCenter); //tile.setPropertyChangeListener(this); Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); newTile.setIncomingSide(incomingSide); newTile.setShowRoute(displayRouteCB.isSelected()); newTile.setTrackRouteColor(Color.blue); Logger.trace("Adding tile " + newTile.getId() + " " + newTile.xyToString()); //this.cPanel.add((JComponent) newTile); this.canvas.add(newTile); this.tile = newTile; tile.updateUI(); } private AccessoryValue getAccessoryState() { AccessoryValue value; if (greenRB.isSelected()) { value = AccessoryValue.GREEN; } else if (redRB.isSelected()) { value = AccessoryValue.RED; } else { value = AccessoryValue.OFF; } return value; } private void changeAccesoryState() { if (tile instanceof Sensor) { tile.setActive(this.redRB.isSelected()); } if (tile instanceof Switch aSwitch) { if (this.displayRouteCB.isSelected()) { aSwitch.setRouteValue(getAccessoryState()); } else { aSwitch.setAccessoryValue(getAccessoryState()); } } if (tile instanceof Signal aSignal) { if (this.greenRB.isSelected()) { aSignal.setSignalValue(AccessoryBean.SignalValue.Hp1); } else if (this.redRB.isSelected()) { aSignal.setSignalValue(AccessoryBean.SignalValue.Hp0); } else { aSignal.setSignalValue(AccessoryBean.SignalValue.OFF); } } //this.tile.repaint(); } // @Override // public void propertyChange(PropertyChangeEvent evt) { // if ("repaintTile".equals(evt.getPropertyName())) { // Tile t = (Tile) evt.getNewValue(); // Logger.trace("Tile: " + t); // //this.repaint(); // } // } // @Override // public void paint(Graphics g) { // super.paint(g); // Graphics2D g2d = (Graphics2D) g; // boolean outline = this.drawOutlineCB.isSelected(); // boolean showRoute = this.displayRouteCB.isSelected(); // tile.setShowRoute(showRoute); // // tile.drawTile(g2d, outline); // // if (outline) { // tile.drawBounds(g2d); // tile.drawCenterPoint(g2d, Color.red); // } // } // @Override // public void paint(Graphics g) { // long started = System.currentTimeMillis(); // super.paint(g); // // long now = System.currentTimeMillis(); // Logger.trace("Duration: " + (now - started) + " ms."); // } private void changeDirection() { Direction direction = (Direction) this.directionCB.getSelectedItem(); this.tile.setDirection(direction); //if (TileType.CROSS == tile.getTileType()) { // ((Cross) tile).setWidthHeightAndOffsets(); //} //this.repaint(); } private void rotateTile() { Orientation newOrientation = tile.rotate(); orientationCB.setSelectedItem(newOrientation); // if (TileType.CROSS == tile.getTileType()) { // int x = tile.getCenterX(); // int y = tile.getCenterY(); // int w = tile.getWidth() * 10; // int h = tile.getHeight() * 10; // // //calculate a new centerpoint for cross // switch (tile.getOrientation()) { // case SOUTH -> { // x = x + w / 2; // y = y - h / 4; // } // case WEST -> { // x = x + w / 4; // y = y + h / 2; // } // case NORTH -> { // x = x - w / 2; // y = y + h / 4; // } // default -> { // x = x - w / 4; // y = y - h / 2; // } // } // tile.setCenter(new Point(x, y)); // } //this.canvas.repaint(this.tile.getTileBounds()); //tile.repaint(); } private void changeOrientation() { Orientation orientation = (Orientation) this.orientationCB.getSelectedItem(); tile.setOrientation(orientation); // if (TileType.CROSS == tile.getTileType()) { // //((Cross) tile).setWidthHeightAndOffsets(); // // int x = tile.getCenterX(); // int y = tile.getCenterY(); // int w = tile.getWidth() * 10; // int h = tile.getHeight() * 10; // // //calculate a new centerpoint for cross // switch (tile.getOrientation()) { // case SOUTH -> { // x = x + w / 2; // y = y - h / 4; // } // case WEST -> { // x = x + w / 4; // y = y + h / 2; // } // case NORTH -> { // x = x - w / 2; // y = y + h / 4; // } // default -> { // x = x - w / 4; // y = y - h / 2; // } // } // tile.setCenter(new Point(x, y)); // } //this.repaint(); } private void showRoute() { Logger.trace("Show route on tile " + tile.getId()); String tileId = tile.getId(); Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); //TileEvent tileEvent; if (tile.isJunction()) { AccessoryValue routeState = getAccessoryState(); //tileEvent = new TileEvent(tileId, true, incomingSide, routeState); } else { //tileEvent = new TileEvent(tileId, true, incomingSide); } //TileCache.fireTileEventListener(tileEvent); // ((JComponent) this.tile).repaint(); tile.setShowRoute(displayRouteCB.isSelected()); //repaint(); } // private void showOutline() { // //repaint(); // } private void changeIncomingSide() { Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); tile.setIncomingSide(incomingSide); //this.repaint(); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { accessoryBG = new javax.swing.ButtonGroup(); nPanel = new javax.swing.JPanel(); tileCB = new javax.swing.JComboBox<>(); orientationCB = new javax.swing.JComboBox<>(); inComingLbl = new javax.swing.JLabel(); incomingSideCB = new javax.swing.JComboBox<>(); directionCB = new javax.swing.JComboBox<>(); rotateButton = new javax.swing.JButton(); offRB = new javax.swing.JRadioButton(); greenRB = new javax.swing.JRadioButton(); redRB = new javax.swing.JRadioButton(); displayRouteCB = new javax.swing.JCheckBox(); scaleCB = new javax.swing.JCheckBox(); showCenterCB = new javax.swing.JCheckBox(); canvas = new jcs.ui.layout.tiles.DotGridCanvas(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); nPanel.setMinimumSize(new java.awt.Dimension(860, 36)); nPanel.setPreferredSize(new java.awt.Dimension(1020, 36)); java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); flowLayout1.setAlignOnBaseline(true); nPanel.setLayout(flowLayout1); tileCB.setPreferredSize(new java.awt.Dimension(150, 23)); tileCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { tileCBActionPerformed(evt); } }); nPanel.add(tileCB); orientationCB.setPreferredSize(new java.awt.Dimension(100, 23)); orientationCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { orientationCBActionPerformed(evt); } }); nPanel.add(orientationCB); inComingLbl.setText("Incoming Orientation"); nPanel.add(inComingLbl); incomingSideCB.setPreferredSize(new java.awt.Dimension(100, 23)); incomingSideCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { incomingSideCBActionPerformed(evt); } }); nPanel.add(incomingSideCB); directionCB.setPreferredSize(new java.awt.Dimension(100, 23)); directionCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { directionCBActionPerformed(evt); } }); nPanel.add(directionCB); rotateButton.setText("Rotate"); rotateButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { rotateButtonActionPerformed(evt); } }); nPanel.add(rotateButton); accessoryBG.add(offRB); offRB.setForeground(new java.awt.Color(153, 153, 153)); offRB.setSelected(true); offRB.setText("Off"); offRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { offRBActionPerformed(evt); } }); nPanel.add(offRB); accessoryBG.add(greenRB); greenRB.setForeground(new java.awt.Color(102, 255, 0)); greenRB.setText("Green"); greenRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { greenRBActionPerformed(evt); } }); nPanel.add(greenRB); accessoryBG.add(redRB); redRB.setForeground(new java.awt.Color(255, 0, 51)); redRB.setText("Red"); redRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { redRBActionPerformed(evt); } }); nPanel.add(redRB); displayRouteCB.setText("Route"); displayRouteCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { displayRouteCBActionPerformed(evt); } }); nPanel.add(displayRouteCB); scaleCB.setText("Scale"); scaleCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { scaleCBActionPerformed(evt); } }); nPanel.add(scaleCB); showCenterCB.setText("Center"); showCenterCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { showCenterCBActionPerformed(evt); } }); nPanel.add(showCenterCB); getContentPane().add(nPanel, java.awt.BorderLayout.NORTH); canvas.setPreferredSize(new java.awt.Dimension(600, 600)); getContentPane().add(canvas, java.awt.BorderLayout.CENTER); pack(); }// //GEN-END:initComponents private void rotateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rotateButtonActionPerformed rotateTile(); }//GEN-LAST:event_rotateButtonActionPerformed private void tileCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tileCBActionPerformed createTile(); }//GEN-LAST:event_tileCBActionPerformed private void orientationCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_orientationCBActionPerformed changeOrientation(); }//GEN-LAST:event_orientationCBActionPerformed private void directionCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_directionCBActionPerformed changeDirection(); }//GEN-LAST:event_directionCBActionPerformed private void offRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_offRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_offRBActionPerformed private void greenRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_greenRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_greenRBActionPerformed private void redRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_redRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_redRBActionPerformed private void displayRouteCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_displayRouteCBActionPerformed showRoute(); }//GEN-LAST:event_displayRouteCBActionPerformed private void scaleCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_scaleCBActionPerformed this.tile.setScaleImage(!this.scaleCB.isSelected()); this.tile.setBounds(this.tile.getTileBounds()); }//GEN-LAST:event_scaleCBActionPerformed private void incomingSideCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_incomingSideCBActionPerformed changeIncomingSide(); }//GEN-LAST:event_incomingSideCBActionPerformed private void showCenterCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showCenterCBActionPerformed this.tile.setDrawCenterPoint(this.showCenterCB.isSelected()); }//GEN-LAST:event_showCenterCBActionPerformed /** * @param args the command line arguments */ public static void main(String args[]) { try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { Logger.error(ex); } /* Create and display the form */ java.awt.EventQueue.invokeLater(() -> { TileTesterFrame app = new TileTesterFrame(); app.setTitle("Tile Tester"); app.setLocationRelativeTo(null); }); } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.ButtonGroup accessoryBG; private jcs.ui.layout.tiles.DotGridCanvas canvas; private javax.swing.JComboBox directionCB; private javax.swing.JCheckBox displayRouteCB; private javax.swing.JRadioButton greenRB; private javax.swing.JLabel inComingLbl; private javax.swing.JComboBox incomingSideCB; private javax.swing.JPanel nPanel; private javax.swing.JRadioButton offRB; private javax.swing.JComboBox orientationCB; private javax.swing.JRadioButton redRB; private javax.swing.JButton rotateButton; private javax.swing.JCheckBox scaleCB; private javax.swing.JCheckBox showCenterCB; private javax.swing.JComboBox tileCB; // End of variables declaration//GEN-END:variables } \ No newline at end of file +/* * Copyright 2024 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.Color; import java.awt.Point; import javax.swing.ComboBoxModel; import javax.swing.DefaultComboBoxModel; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.AccessoryValue; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import jcs.entities.TileBean.TileType; import jcs.ui.layout.LayoutUtil; import org.tinylog.Logger; public class TileTesterFrame extends javax.swing.JFrame { private Tile tile; public TileTesterFrame() { initComponents(); this.tileCB.setModel(createTileTypeComboBoxModel()); this.orientationCB.setModel(createOrientationComboBoxModel()); this.incomingSideCB.setModel(createOrientationComboBoxModel()); this.directionCB.setModel(createDirectionComboBoxModel(true)); createTile(); pack(); setVisible(true); } private ComboBoxModel createTileTypeComboBoxModel() { DefaultComboBoxModel tileTypeModel = new DefaultComboBoxModel(); tileTypeModel.addElement(TileBean.TileType.STRAIGHT); tileTypeModel.addElement(TileBean.TileType.STRAIGHT_DIR); tileTypeModel.addElement(TileBean.TileType.SENSOR); tileTypeModel.addElement(TileBean.TileType.SIGNAL); tileTypeModel.addElement(TileBean.TileType.END); tileTypeModel.addElement(TileBean.TileType.CROSSING); tileTypeModel.addElement(TileBean.TileType.CURVED); tileTypeModel.addElement(TileBean.TileType.SWITCH); tileTypeModel.addElement(TileBean.TileType.CROSS); return tileTypeModel; } private ComboBoxModel createOrientationComboBoxModel() { DefaultComboBoxModel orientationModel = new DefaultComboBoxModel(); orientationModel.addElement(Orientation.EAST); orientationModel.addElement(Orientation.SOUTH); orientationModel.addElement(Orientation.WEST); orientationModel.addElement(Orientation.NORTH); return orientationModel; } private ComboBoxModel createDirectionComboBoxModel(boolean dontCare) { DefaultComboBoxModel directionModel = new DefaultComboBoxModel(); if (dontCare) { directionModel.addElement(Direction.CENTER); } else { directionModel.addElement(Direction.LEFT); directionModel.addElement(Direction.RIGHT); } return directionModel; } private void createTile() { if (tile != null) { Logger.trace("Removing tile " + tile.getId()); canvas.remove(tile); tile = null; } TileType tileType = (TileType) tileCB.getSelectedItem(); Orientation orientation = (Orientation) orientationCB.getSelectedItem(); if (TileType.SWITCH == tileType || TileType.CROSS == tileType) { directionCB.setModel(createDirectionComboBoxModel(false)); } else { directionCB.setModel(createDirectionComboBoxModel(true)); } Direction direction = (Direction) this.directionCB.getSelectedItem(); boolean scale = !scaleCB.isSelected(); boolean showCenter = showCenterCB.isSelected(); int w = canvas.getWidth(); int h = canvas.getHeight(); int x = w / 2; int y = h / 2; Point tileCenter = new Point(x, y); tileCenter = LayoutUtil.snapToGrid(tileCenter); Tile newTile = TileCache.createTile(tileType, orientation, direction, tileCenter); newTile.setScaleImage(scale); newTile.setDrawCenterPoint(showCenter); //tile.setPropertyChangeListener(this); Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); newTile.setIncomingSide(incomingSide); newTile.setShowRoute(displayRouteCB.isSelected()); newTile.setTrackRouteColor(Color.blue); Logger.trace("Adding tile " + newTile.getId() + " " + newTile.xyToString()); //this.cPanel.add((JComponent) newTile); this.canvas.add(newTile); this.tile = newTile; tile.updateUI(); } private AccessoryValue getAccessoryState() { AccessoryValue value; if (greenRB.isSelected()) { value = AccessoryValue.GREEN; } else if (redRB.isSelected()) { value = AccessoryValue.RED; } else { value = AccessoryValue.OFF; } return value; } private void changeAccesoryState() { if (tile instanceof Sensor) { tile.setActive(this.redRB.isSelected()); } if (tile instanceof Switch aSwitch) { if (this.displayRouteCB.isSelected()) { aSwitch.setRouteValue(getAccessoryState()); } else { aSwitch.setAccessoryValue(getAccessoryState()); } } if (tile instanceof Signal aSignal) { if (this.greenRB.isSelected()) { aSignal.setSignalValue(AccessoryBean.SignalValue.Hp1); } else if (this.redRB.isSelected()) { aSignal.setSignalValue(AccessoryBean.SignalValue.Hp0); } else { aSignal.setSignalValue(AccessoryBean.SignalValue.OFF); } } //this.tile.repaint(); } // @Override // public void propertyChange(PropertyChangeEvent evt) { // if ("repaintTile".equals(evt.getPropertyName())) { // Tile t = (Tile) evt.getNewValue(); // Logger.trace("Tile: " + t); // //this.repaint(); // } // } // @Override // public void paint(Graphics g) { // super.paint(g); // Graphics2D g2d = (Graphics2D) g; // boolean outline = this.drawOutlineCB.isSelected(); // boolean showRoute = this.displayRouteCB.isSelected(); // tile.setShowRoute(showRoute); // // tile.drawTile(g2d, outline); // // if (outline) { // tile.drawBounds(g2d); // tile.drawCenterPoint(g2d, Color.red); // } // } // @Override // public void paint(Graphics g) { // long started = System.currentTimeMillis(); // super.paint(g); // // long now = System.currentTimeMillis(); // Logger.trace("Duration: " + (now - started) + " ms."); // } private void changeDirection() { Direction direction = (Direction) this.directionCB.getSelectedItem(); this.tile.setDirection(direction); //if (TileType.CROSS == tile.getTileType()) { // ((Cross) tile).setWidthHeightAndOffsets(); //} //this.repaint(); } private void rotateTile() { Orientation newOrientation = tile.rotate(); orientationCB.setSelectedItem(newOrientation); // if (TileType.CROSS == tile.getTileType()) { // int x = tile.getCenterX(); // int y = tile.getCenterY(); // int w = tile.getWidth() * 10; // int h = tile.getHeight() * 10; // // //calculate a new centerpoint for cross // switch (tile.getOrientation()) { // case SOUTH -> { // x = x + w / 2; // y = y - h / 4; // } // case WEST -> { // x = x + w / 4; // y = y + h / 2; // } // case NORTH -> { // x = x - w / 2; // y = y + h / 4; // } // default -> { // x = x - w / 4; // y = y - h / 2; // } // } // tile.setCenter(new Point(x, y)); // } //this.canvas.repaint(this.tile.getTileBounds()); //tile.repaint(); } private void changeOrientation() { Orientation orientation = (Orientation) this.orientationCB.getSelectedItem(); tile.setOrientation(orientation); // if (TileType.CROSS == tile.getTileType()) { // //((Cross) tile).setWidthHeightAndOffsets(); // // int x = tile.getCenterX(); // int y = tile.getCenterY(); // int w = tile.getWidth() * 10; // int h = tile.getHeight() * 10; // // //calculate a new centerpoint for cross // switch (tile.getOrientation()) { // case SOUTH -> { // x = x + w / 2; // y = y - h / 4; // } // case WEST -> { // x = x + w / 4; // y = y + h / 2; // } // case NORTH -> { // x = x - w / 2; // y = y + h / 4; // } // default -> { // x = x - w / 4; // y = y - h / 2; // } // } // tile.setCenter(new Point(x, y)); // } //this.repaint(); } private void showRoute() { Logger.trace("Show route on tile " + tile.getId()); String tileId = tile.getId(); Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); //TileEvent tileEvent; if (tile.isJunction()) { AccessoryValue routeState = getAccessoryState(); //tileEvent = new TileEvent(tileId, true, incomingSide, routeState); } else { //tileEvent = new TileEvent(tileId, true, incomingSide); } //TileCache.fireTileEventListener(tileEvent); // ((JComponent) this.tile).repaint(); tile.setShowRoute(displayRouteCB.isSelected()); //repaint(); } // private void showOutline() { // //repaint(); // } private void changeIncomingSide() { Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); tile.setIncomingSide(incomingSide); //this.repaint(); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { accessoryBG = new javax.swing.ButtonGroup(); nPanel = new javax.swing.JPanel(); tileCB = new javax.swing.JComboBox<>(); orientationCB = new javax.swing.JComboBox<>(); inComingLbl = new javax.swing.JLabel(); incomingSideCB = new javax.swing.JComboBox<>(); directionCB = new javax.swing.JComboBox<>(); rotateButton = new javax.swing.JButton(); offRB = new javax.swing.JRadioButton(); greenRB = new javax.swing.JRadioButton(); redRB = new javax.swing.JRadioButton(); displayRouteCB = new javax.swing.JCheckBox(); scaleCB = new javax.swing.JCheckBox(); showCenterCB = new javax.swing.JCheckBox(); canvas = new jcs.ui.layout.tiles.DotGridCanvas(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); nPanel.setMinimumSize(new java.awt.Dimension(860, 36)); nPanel.setPreferredSize(new java.awt.Dimension(1020, 36)); java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); flowLayout1.setAlignOnBaseline(true); nPanel.setLayout(flowLayout1); tileCB.setPreferredSize(new java.awt.Dimension(150, 23)); tileCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { tileCBActionPerformed(evt); } }); nPanel.add(tileCB); orientationCB.setPreferredSize(new java.awt.Dimension(100, 23)); orientationCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { orientationCBActionPerformed(evt); } }); nPanel.add(orientationCB); inComingLbl.setText("Incoming Orientation"); nPanel.add(inComingLbl); incomingSideCB.setPreferredSize(new java.awt.Dimension(100, 23)); incomingSideCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { incomingSideCBActionPerformed(evt); } }); nPanel.add(incomingSideCB); directionCB.setPreferredSize(new java.awt.Dimension(100, 23)); directionCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { directionCBActionPerformed(evt); } }); nPanel.add(directionCB); rotateButton.setText("Rotate"); rotateButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { rotateButtonActionPerformed(evt); } }); nPanel.add(rotateButton); accessoryBG.add(offRB); offRB.setForeground(new java.awt.Color(153, 153, 153)); offRB.setSelected(true); offRB.setText("Off"); offRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { offRBActionPerformed(evt); } }); nPanel.add(offRB); accessoryBG.add(greenRB); greenRB.setForeground(new java.awt.Color(102, 255, 0)); greenRB.setText("Green"); greenRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { greenRBActionPerformed(evt); } }); nPanel.add(greenRB); accessoryBG.add(redRB); redRB.setForeground(new java.awt.Color(255, 0, 51)); redRB.setText("Red"); redRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { redRBActionPerformed(evt); } }); nPanel.add(redRB); displayRouteCB.setText("Route"); displayRouteCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { displayRouteCBActionPerformed(evt); } }); nPanel.add(displayRouteCB); scaleCB.setText("Scale"); scaleCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { scaleCBActionPerformed(evt); } }); nPanel.add(scaleCB); showCenterCB.setText("Center"); showCenterCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { showCenterCBActionPerformed(evt); } }); nPanel.add(showCenterCB); getContentPane().add(nPanel, java.awt.BorderLayout.NORTH); canvas.setPreferredSize(new java.awt.Dimension(600, 600)); getContentPane().add(canvas, java.awt.BorderLayout.CENTER); pack(); }// //GEN-END:initComponents private void rotateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rotateButtonActionPerformed rotateTile(); }//GEN-LAST:event_rotateButtonActionPerformed private void tileCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tileCBActionPerformed createTile(); }//GEN-LAST:event_tileCBActionPerformed private void orientationCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_orientationCBActionPerformed changeOrientation(); }//GEN-LAST:event_orientationCBActionPerformed private void directionCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_directionCBActionPerformed changeDirection(); }//GEN-LAST:event_directionCBActionPerformed private void offRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_offRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_offRBActionPerformed private void greenRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_greenRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_greenRBActionPerformed private void redRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_redRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_redRBActionPerformed private void displayRouteCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_displayRouteCBActionPerformed showRoute(); }//GEN-LAST:event_displayRouteCBActionPerformed private void scaleCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_scaleCBActionPerformed this.tile.setScaleImage(!this.scaleCB.isSelected()); this.tile.setBounds(this.tile.getTileBounds()); }//GEN-LAST:event_scaleCBActionPerformed private void incomingSideCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_incomingSideCBActionPerformed changeIncomingSide(); }//GEN-LAST:event_incomingSideCBActionPerformed private void showCenterCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showCenterCBActionPerformed this.tile.setDrawCenterPoint(this.showCenterCB.isSelected()); }//GEN-LAST:event_showCenterCBActionPerformed /** * @param args the command line arguments */ public static void main(String args[]) { try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { Logger.error(ex); } /* Create and display the form */ java.awt.EventQueue.invokeLater(() -> { TileTesterFrame app = new TileTesterFrame(); app.setTitle("Tile Tester"); app.setLocationRelativeTo(null); }); } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.ButtonGroup accessoryBG; private jcs.ui.layout.tiles.DotGridCanvas canvas; private javax.swing.JComboBox directionCB; private javax.swing.JCheckBox displayRouteCB; private javax.swing.JRadioButton greenRB; private javax.swing.JLabel inComingLbl; private javax.swing.JComboBox incomingSideCB; private javax.swing.JPanel nPanel; private javax.swing.JRadioButton offRB; private javax.swing.JComboBox orientationCB; private javax.swing.JRadioButton redRB; private javax.swing.JButton rotateButton; private javax.swing.JCheckBox scaleCB; private javax.swing.JCheckBox showCenterCB; private javax.swing.JComboBox tileCB; // End of variables declaration//GEN-END:variables } \ No newline at end of file From f0de294ea13d6f6c46e863c065e1a03a7ac8f354 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Thu, 13 Feb 2025 21:07:50 +0100 Subject: [PATCH 22/70] Experiment for idle state --- .../jcs/commandStation/autopilot/state/IdleState.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/java/jcs/commandStation/autopilot/state/IdleState.java b/src/main/java/jcs/commandStation/autopilot/state/IdleState.java index df5b5dbb..01988258 100644 --- a/src/main/java/jcs/commandStation/autopilot/state/IdleState.java +++ b/src/main/java/jcs/commandStation/autopilot/state/IdleState.java @@ -59,6 +59,17 @@ DispatcherState execute(Dispatcher dispatcher) { } catch (InterruptedException ex) { Logger.trace("Interrupted: " + ex.getMessage()); } + } else { + //Automode is switched off for this Dispatcher so the Idle state must end... + Logger.trace(dispatcher.getName() + " Automode: " + AutoPilot.isAutoModeActive() + " Dispacher " + dispatcher.isLocomotiveAutomodeOn()); + try { + synchronized (this) { + wait(10000); + } + } catch (InterruptedException ex) { + Logger.trace("Interrupted: " + ex.getMessage()); + } + } } return this; From 82c018c88fc2775d8c54c0a6f2e1d90f1fba15eb Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Wed, 19 Feb 2025 17:30:49 +0100 Subject: [PATCH 23/70] Most of the issues are now solved --- pom.xml | 5 + src/main/java/jcs/JCS.java | 107 +++++---- .../autopilot/ActionCommandHandler.java | 102 +++++++++ .../commandStation/autopilot/AutoPilot.java | 214 ++++++++++++------ .../autopilot/AutoPilotActionEvent.java | 46 ++++ .../autopilot/DriveSimulator.java | 3 - .../autopilot/state/Dispatcher.java | 172 +++++++------- .../autopilot/state/IdleState.java | 4 +- ...teMachineThread.java => StateMachine.java} | 79 ++++--- .../esu/ecos/FeedbackManager.java | 1 - .../java/jcs/ui/DispatcherStatusPanel.java | 14 +- src/main/java/jcs/ui/JCSFrame.form | 71 +++--- src/main/java/jcs/ui/JCSFrame.java | 121 +++++----- src/main/java/jcs/ui/layout/LayoutCanvas.java | 39 ++-- src/main/java/jcs/ui/layout/LayoutPanel.java | 24 +- .../ui/layout/dialogs/BlockControlDialog.java | 14 +- .../java/jcs/ui/layout/events/TileEvent.java | 157 ------------- .../ui/layout/events/TileEventListener.java | 24 -- .../java/jcs/ui/layout/tiles/TileCache.java | 2 +- .../jcs/ui/table/DispatcherTablePanel.java | 72 ++---- .../jcs/ui/table/LocomotiveTablePanel.java | 10 +- .../resources/media/arrowhead-right-gn.png | Bin 0 -> 456 bytes src/main/resources/media/pause-gr.png | Bin 0 -> 186 bytes src/main/resources/media/reset-happy.png | Bin 0 -> 738 bytes src/main/resources/tinylog-dev.properties | 7 +- src/main/resources/tinylog.properties | 6 +- .../autopilot/AutoPilotTest.java | 8 +- .../state/StateMachineStepByStepTest.java | 32 +-- .../state/StateMachineThreadTest.java | 15 +- 29 files changed, 692 insertions(+), 657 deletions(-) create mode 100644 src/main/java/jcs/commandStation/autopilot/ActionCommandHandler.java create mode 100644 src/main/java/jcs/commandStation/autopilot/AutoPilotActionEvent.java rename src/main/java/jcs/commandStation/autopilot/state/{StateMachineThread.java => StateMachine.java} (92%) delete mode 100644 src/main/java/jcs/ui/layout/events/TileEvent.java delete mode 100644 src/main/java/jcs/ui/layout/events/TileEventListener.java create mode 100755 src/main/resources/media/arrowhead-right-gn.png create mode 100755 src/main/resources/media/pause-gr.png create mode 100755 src/main/resources/media/reset-happy.png diff --git a/pom.xml b/pom.xml index 7222ff10..d7a8a16d 100644 --- a/pom.xml +++ b/pom.xml @@ -172,6 +172,11 @@ logback-classic 1.2.13 + org.netbeans.external AbsoluteLayout diff --git a/src/main/java/jcs/JCS.java b/src/main/java/jcs/JCS.java index 93ef061a..b14d1b48 100755 --- a/src/main/java/jcs/JCS.java +++ b/src/main/java/jcs/JCS.java @@ -16,10 +16,13 @@ package jcs; import java.awt.GraphicsEnvironment; +import java.io.File; +import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.List; import javax.swing.ImageIcon; +import javax.swing.JOptionPane; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import jcs.commandStation.JCSCommandStation; @@ -46,22 +49,22 @@ * */ public class JCS extends Thread { - + private static JCS instance = null; private static JCSSplash splashScreen; private static PersistenceService persistentStore; private static JCSCommandStation jcsCommandStation; - + private static MacOsAdapter osAdapter; private static JCSFrame jcsFrame; private static String version; - + private final List refreshEventListeners; - + private JCS() { refreshEventListeners = new ArrayList<>(); } - + public static void logProgress(String message) { if (splashScreen != null) { splashScreen.logProgress(message); @@ -69,18 +72,18 @@ public static void logProgress(String message) { Logger.info(message); } } - + public static JCSFrame getParentFrame() { return jcsFrame; } - + public static PersistenceService getPersistenceService() { if (persistentStore == null) { persistentStore = PersistenceFactory.getService(); } return persistentStore; } - + public static JCSCommandStation getJcsCommandStation() { if (jcsCommandStation == null) { if (getPersistenceService() != null) { @@ -91,18 +94,18 @@ public static JCSCommandStation getJcsCommandStation() { } return jcsCommandStation; } - + private void startGui() { JCS.logProgress("Check OS..."); - + if (RunUtil.isMacOSX()) { MacOsAdapter.setMacOsProperties(); osAdapter = new MacOsAdapter(); } - + java.awt.EventQueue.invokeLater(() -> { jcsFrame = new JCSFrame(); - + if (RunUtil.isMacOSX()) { osAdapter.setUiCallback(jcsFrame); } @@ -112,9 +115,9 @@ private void startGui() { if (iconUrl != null) { jcsFrame.setIconImage(new ImageIcon(iconUrl).getImage()); } - + FrameMonitor.registerFrame(jcsFrame, JCS.class.getName()); - + jcsFrame.setVisible(true); jcsFrame.toFront(); jcsFrame.showOverviewPanel(); @@ -122,12 +125,12 @@ private void startGui() { jcsFrame.connect(true); } }); - + JCS.logProgress("JCS started..."); - + int mb = 1024 * 1024; Runtime runtime = Runtime.getRuntime(); - + StringBuilder sb = new StringBuilder(); sb.append("Used Memory: "); sb.append((runtime.totalMemory() - runtime.freeMemory()) / mb); @@ -138,7 +141,7 @@ private void startGui() { sb.append(" [MB]. Max Memory: "); sb.append(runtime.maxMemory() / mb); sb.append(" [MB]."); - + Logger.info(sb); splashScreen.hideSplash(200); splashScreen.close(); @@ -155,21 +158,21 @@ public void run() { ProcessFactory.getInstance().shutdown(); Logger.info("JCS " + VersionInfo.getVersion() + " session finished"); } - + public static void addRefreshListener(RefreshEventListener refreshListener) { instance.refreshEventListeners.add(refreshListener); } - + public static void removeRefreshListener(RefreshEventListener refreshListener) { instance.refreshEventListeners.remove(refreshListener); } - + public static void settingsChanged(RefreshEvent refreshEvent) { for (RefreshEventListener rel : instance.refreshEventListeners) { rel.onChange(refreshEvent); } } - + public static JCS getInstance() { if (instance == null) { instance = new JCS(); @@ -179,21 +182,38 @@ public static JCS getInstance() { } return instance; } - + + private static boolean lockAppInstance() { + try { + String lockFilePath = System.getProperty("user.home") + File.separator + "jcs" + File.separator + "jcs.lock"; + + final File file = new File(lockFilePath); + if (file.createNewFile()) { + file.deleteOnExit(); + return true; + } + return false; + } catch (IOException e) { + return false; + } + } + public static void main(String[] args) { System.setProperty("fazecast.jSerialComm.appid", "JCS"); version = VersionInfo.getVersion(); Logger.info("Starting JCS Version " + version + "..."); - + if (GraphicsEnvironment.isHeadless()) { Logger.error("This JDK environment is headless, can't start a GUI!"); //Quit.... System.exit(1); } + //Load properties RunUtil.loadProperties(); + RunUtil.loadExternalProperties(); - + try { String plaf = System.getProperty("jcs.plaf", "com.formdev.flatlaf.FlatLightLaf"); if (plaf != null) { @@ -204,11 +224,19 @@ public static void main(String[] args) { } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { Logger.error(ex); } - + + if (!lockAppInstance()) { + Logger.warn("Can not obtain a lock. Check if an other instance of JCS is running"); + JOptionPane.showMessageDialog(null, "There is another instance of JCS running.", "JCS allready running", JOptionPane.INFORMATION_MESSAGE, null); + System.exit(0); + } + splashScreen = new JCSSplash(); + splashScreen.showSplash(); + splashScreen.setProgressMax(25); - + logProgress("JCS is Starting..."); //Check the persistent properties, prepare environment @@ -221,24 +249,27 @@ public static void main(String[] args) { //Database file exist check whether an update is needed String dbVersion = H2DatabaseUtil.getDataBaseVersion(); + if (!H2DatabaseUtil.DB_VERSION.equals(dbVersion)) { Logger.trace("Current DB Version " + dbVersion + " need to be updated to: " + H2DatabaseUtil.DB_VERSION + "..."); logProgress("Updating JCS Database to version " + H2DatabaseUtil.DB_VERSION + "..."); dbVersion = H2DatabaseUtil.updateDatabase(); } + logProgress("Connecting to existing Database version " + dbVersion + "..."); - + logProgress("Starting JCS Command Station..."); persistentStore = getPersistenceService(); jcsCommandStation = getJcsCommandStation(); - - if (persistentStore != null) { + + if (persistentStore + != null) { if ("true".equalsIgnoreCase(System.getProperty("commandStation.autoconnect", "true"))) { if (jcsCommandStation != null) { boolean connected = jcsCommandStation.connect(); if (connected) { logProgress("Connected with Command Station..."); - + boolean power = jcsCommandStation.isPowerOn(); logProgress("Track Power is " + (power ? "on" : "off")); Logger.info("Track Power is " + (power ? "on" : "off")); @@ -250,9 +281,9 @@ public static void main(String[] args) { logProgress("NO Default Command Station found..."); } } - + logProgress("Starting UI..."); - + JCS jcs = JCS.getInstance(); jcs.startGui(); } else { @@ -263,20 +294,20 @@ public static void main(String[] args) { System.exit(0); } } - + private static class Powerlistener implements PowerEventListener { - + Powerlistener() { } - + @Override public void onPowerChange(PowerEvent event) { Logger.info("Track Power is " + (event.isPower() ? "on" : "off")); - + if (JCS.jcsFrame != null) { JCS.jcsFrame.powerChanged(event); } } } - + } diff --git a/src/main/java/jcs/commandStation/autopilot/ActionCommandHandler.java b/src/main/java/jcs/commandStation/autopilot/ActionCommandHandler.java new file mode 100644 index 00000000..62195505 --- /dev/null +++ b/src/main/java/jcs/commandStation/autopilot/ActionCommandHandler.java @@ -0,0 +1,102 @@ +/* + * Copyright 2025 fransjacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.commandStation.autopilot; + +import java.util.concurrent.ConcurrentLinkedQueue; +import org.tinylog.Logger; + +/** + * + * A Handler to Monitor the AutoPilot engine. + * + */ +public class ActionCommandHandler extends Thread { + + private boolean stop = false; + private boolean quit = true; + + private final ConcurrentLinkedQueue eventQueue; + + ActionCommandHandler(ConcurrentLinkedQueue eventQueue) { + this.eventQueue = eventQueue; + } + + void quit() { + this.quit = true; + } + + boolean isRunning() { + return !this.quit; + } + + boolean isFinished() { + return this.stop; + } + + @Override + public void run() { + quit = false; + setName("AUTOPILOT-COMMAND-HANDLER"); + + Logger.trace("AutoPilot ActionCommandHandler Started..."); + + while (isRunning()) { + try { + AutoPilotActionEvent event = eventQueue.poll(); + if (event != null) { + switch (event.getActionCommand()) { + case "start" -> { + AutoPilot.startAutoMode(); + } + case "stop" -> { + AutoPilot.stopAutoMode(); + } + case "startLocomotive" -> { + AutoPilot.startDispatcher(event.getLocomotiveBean()); + } + case "stopLocomotive" -> { + AutoPilot.stopDispatcher(event.getLocomotiveBean()); + } + case "startAllLocomotives" -> { + AutoPilot.startLocomotives(); + } + case "removeLocomotive" -> { + AutoPilot.removeDispatcher(event.getLocomotiveBean()); + } + case "addLocomotive" -> { + AutoPilot.addDispatcher(event.getLocomotiveBean()); + } + case "reset" -> { + AutoPilot.resetStates(); + } + } + } else { + //lets sleep for a while + synchronized (this) { + wait(10000); + } + } + + } catch (InterruptedException ex) { + Logger.error(ex); + } + } + + stop = true; + Logger.trace("Tile ActionEventHandler Stopped..."); + } + +} diff --git a/src/main/java/jcs/commandStation/autopilot/AutoPilot.java b/src/main/java/jcs/commandStation/autopilot/AutoPilot.java index ec8f7415..d733f806 100644 --- a/src/main/java/jcs/commandStation/autopilot/AutoPilot.java +++ b/src/main/java/jcs/commandStation/autopilot/AutoPilot.java @@ -23,8 +23,7 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; +import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Semaphore; import java.util.stream.Collectors; import jcs.JCS; @@ -45,12 +44,12 @@ * The AutoPilot is the "automatic driving engine".
* Every Locomotive on the track will start it own Thread.
* The Dispatcher is run in this Thread.
- * The AutoPilot has it own Monitor Thread: AutoPilotThread. + * The AutoPilot has it own Monitor Thread: AutoPilotMonitorThread. * */ public final class AutoPilot { - private static AutoPilotThread autoPilotThread = null; + private static AutoPilotMonitorThread autoPilotThread = null; private static CommandStationBean commandStationBean; @@ -61,43 +60,83 @@ public final class AutoPilot { private static final List autoPilotStatusListeners = Collections.synchronizedList(new ArrayList<>()); private static final Semaphore semaphore = new Semaphore(1); - private static final ExecutorService executor = Executors.newCachedThreadPool(); private static final ThreadGroup autoPilotRunners = new ThreadGroup("AUTOPILOT"); + private static final ConcurrentLinkedQueue actionCommandQueue = new ConcurrentLinkedQueue(); + + private static final ActionCommandHandler actionCommandHandler = new ActionCommandHandler(actionCommandQueue); + + static { + actionCommandHandler.start(); + } + private AutoPilot() { } public static void runAutoPilot(boolean flag) { if (flag) { - executor.execute(() -> startAutoMode()); + enqueCommand(new AutoPilotActionEvent("start")); } else { - executor.execute(() -> stopAutoMode()); + enqueCommand(new AutoPilotActionEvent("stop")); } } - public synchronized static void startAutoMode() { + public static void startLocomotive(LocomotiveBean locomotiveBean) { + enqueCommand(new AutoPilotActionEvent("startLocomotive", locomotiveBean)); + } + + public static void stopLocomotive(LocomotiveBean locomotiveBean) { + enqueCommand(new AutoPilotActionEvent("stopLocomotive", locomotiveBean)); + } + + public static void removeLocomotive(LocomotiveBean locomotiveBean) { + enqueCommand(new AutoPilotActionEvent("removeLocomotive", locomotiveBean)); + } + + public static void addLocomotive(LocomotiveBean locomotiveBean) { + enqueCommand(new AutoPilotActionEvent("addLocomotive", locomotiveBean)); + } + + public static void startAllLocomotives() { + enqueCommand(new AutoPilotActionEvent("startAllLocomotives")); + } + + public static void reset() { + enqueCommand(new AutoPilotActionEvent("reset")); + } + + private static void enqueCommand(AutoPilotActionEvent command) { + actionCommandQueue.offer(command); + synchronized (AutoPilot.actionCommandHandler) { + actionCommandHandler.notifyAll(); + } + } + + static boolean startAutoMode() { if (JCS.getJcsCommandStation().isPowerOn()) { if (autoPilotThread != null && autoPilotThread.isRunning()) { Logger.trace("Allready running"); + return true; } else { commandStationBean = JCS.getJcsCommandStation().getCommandStationBean(); dispatchers.clear(); sensorHandlers.clear(); - autoPilotThread = new AutoPilotThread(autoPilotRunners); + autoPilotThread = new AutoPilotMonitorThread(autoPilotRunners); autoPilotThread.start(); + Logger.debug("AutoMode Started"); + return true; } } else { - Logger.warn("Can't start Automode is Power is Off!"); + Logger.warn("Can't start Automode, Command Station Power is Off!"); + return false; } } - public static void stopAutoMode() { + static void stopAutoMode() { if (autoPilotThread != null) { - autoPilotThread.stopAutoMode(); - - //Notify all dispachers so thath the ones which waiting and Idle will stop + //Notify all dispachers so that the ones which waiting and Idle will stop Set snapshot = new HashSet<>(dispatchers.values()); for (Dispatcher d : snapshot) { d.stopLocomotiveAutomode(); @@ -106,12 +145,16 @@ public static void stopAutoMode() { } } + autoPilotThread.stopAutoMode(); + try { autoPilotThread.join(); } catch (InterruptedException ex) { Logger.error("Interruppted during join " + ex); } } + Logger.debug("AutoMode Stopped"); + } public static boolean isAutoModeActive() { @@ -139,7 +182,7 @@ public static boolean isRunning(LocomotiveBean locomotive) { } } - public static boolean areDispatchersRunning() { + public static boolean isADispatcherRunning() { boolean isRunning = false; Set snapshot = new HashSet<>(dispatchers.values()); for (Dispatcher ld : snapshot) { @@ -162,7 +205,7 @@ public static int getRunningDispatcherCount() { return runningDispatchers; } - public static synchronized Dispatcher createDispatcher(LocomotiveBean locomotiveBean) { + static Dispatcher createDispatcher(LocomotiveBean locomotiveBean) { Dispatcher dispatcher = null; //check if the locomotive is on track if (isOnTrack(locomotiveBean)) { @@ -180,6 +223,32 @@ public static synchronized Dispatcher createDispatcher(LocomotiveBean locomotive return dispatcher; } + static void removeDispatcher(LocomotiveBean locomotiveBean) { + if (dispatchers.containsKey(locomotiveBean.getName())) { + Dispatcher dispatcher = dispatchers.remove(locomotiveBean.getName()); + Logger.trace("removing Dispatcher for locomotive " + locomotiveBean.getName()); + if (dispatcher.isRunning()) { + Logger.trace("Stopping Automode for " + locomotiveBean.getName() + "..."); + dispatcher.stopLocomotiveAutomode(); + dispatcher.stopRunning(); + } + + dispatcher.removeAllStateEventListeners(); + + for (AutoPilotStatusListener asl : autoPilotStatusListeners) { + asl.statusChanged(autoPilotThread.running); + } + } + } + + static void addDispatcher(LocomotiveBean locomotiveBean) { + createDispatcher(locomotiveBean); + + for (AutoPilotStatusListener asl : autoPilotStatusListeners) { + asl.statusChanged(autoPilotThread.running); + } + } + public static void prepareAllDispatchers() { Logger.trace("Preparing Dispatchers for all on track locomotives..."); List locs = getOnTrackLocomotives(); @@ -192,7 +261,7 @@ public static void prepareAllDispatchers() { if (snapshot.containsKey(loc.getName())) { dispatcher = snapshot.get(loc.getName()); dispatchers.put(loc.getName(), dispatcher); - Logger.trace("Reused dispatcher for " + loc.getName() + "..."); + Logger.trace("Re use dispatcher " + loc.getName() + "..."); } else { createDispatcher(loc); } @@ -200,7 +269,7 @@ public static void prepareAllDispatchers() { } public static synchronized void clearDispatchers() { - Logger.trace("Remove all Dispatchers..."); + Logger.trace("Removing all Dispatchers..."); for (Dispatcher dispatcher : dispatchers.values()) { dispatcher.stopLocomotiveAutomode(); @@ -209,32 +278,42 @@ public static synchronized void clearDispatchers() { dispatchers.clear(); } - public static void startStopLocomotive(LocomotiveBean locomotiveBean, boolean start) { - Logger.trace((start ? "Starting" : "Stopping") + " auto drive for " + locomotiveBean.getName()); + static void startDispatcher(LocomotiveBean locomotiveBean) { + Logger.trace("Starting locomotive for " + locomotiveBean.getName()); String key = locomotiveBean.getName(); - if (start) { - Dispatcher dispatcher; - if (dispatchers.containsKey(key)) { - dispatcher = dispatchers.get(key); - Logger.trace("Dispatcher " + key + " exists"); - } else { - dispatcher = createDispatcher(locomotiveBean); - Logger.trace("Dispatcher " + key + " created"); - } + Dispatcher dispatcher; + if (dispatchers.containsKey(key)) { + dispatcher = dispatchers.get(key); + //Logger.trace("Dispatcher " + key + " exists"); + } else { + dispatcher = createDispatcher(locomotiveBean); + Logger.trace("Dispatcher " + key + " created"); + } - if (!dispatcher.isRunning()) { - Logger.trace("Starting dispatcher thread" + key); - dispatcher.startLocomotiveAutomode(); - } + if (!dispatcher.isRunning()) { + Logger.trace("Starting dispatcher thread " + key); + dispatcher.startLocomotiveAutomode(); + } - Logger.trace("Started dispatcher" + key + " automode..."); - } else { - Dispatcher dispatcher = dispatchers.get(key); - if (dispatcher != null && dispatcher.isRunning()) { - dispatcher.stopLocomotiveAutomode(); - Logger.trace("Stopped dispatcher" + key + " automode..."); - } + Logger.trace("Started locomotive " + key + "..."); + } + + static void stopDispatcher(LocomotiveBean locomotiveBean) { + Logger.trace("Stopping locomotive " + locomotiveBean.getName()); + String key = locomotiveBean.getName(); + + Dispatcher dispatcher = dispatchers.get(key); + if (dispatcher != null && dispatcher.isRunning()) { + dispatcher.stopLocomotiveAutomode(); + Logger.trace("Stopped locomotive " + key + "..."); + } + } + + static void startLocomotives() { + List locos = getOnTrackLocomotives(); + for (LocomotiveBean loc : locos) { + startDispatcher(loc); } } @@ -254,24 +333,11 @@ public static synchronized void resetDispatcher(LocomotiveBean locomotiveBean) { dispatcher.reset(); } - private static void startStopAllLocomotivesInBackground(boolean start) { - List onTrackLocos = getOnTrackLocomotives(); - Logger.trace((start ? "Starting" : "Stopping") + " automode for " + onTrackLocos.size() + " ontrack locomotives..."); - - for (LocomotiveBean locomotiveBean : onTrackLocos) { - startStopLocomotive(locomotiveBean, start); - } - } - - public static void startAllLocomotives() { - executor.execute(() -> startStopAllLocomotivesInBackground(true)); - } + static void resetStates() { + Logger.trace("Resetting AutoPilot..."); - public static void stopAllLocomotives() { - executor.execute(() -> startStopAllLocomotivesInBackground(false)); - } + stopAutoMode(); - public static void resetStates() { List routes = PersistenceFactory.getService().getRoutes(); int lockedCounter = 0; for (RouteBean route : routes) { @@ -300,7 +366,6 @@ public static void resetStates() { case LOCKED, INBOUND -> { //destinations block, reset! tile.setLocomotive(null); - //block.setLocomotive(null); tile.setBlockState(BlockBean.BlockState.FREE); tile.setArrivalSuffix(null); freeBlockCounter++; @@ -359,21 +424,26 @@ public static List getOnTrackLocomotives() { List occupiedBlocks = blocks.stream().filter(t -> t.getLocomotive() != null && t.getLocomotive().getId() != null).collect(Collectors.toList()); //Logger.trace("There " + (occupiedBlocks.size() == 1 ? "is" : "are") + " " + occupiedBlocks.size() + " occupied block(s)"); - Set activeLocomotives = new HashSet<>(); + //Set activeLocomotives = new HashSet<>(); + ArrayList activeLocomotives = new ArrayList<>(); for (BlockBean occupiedBlock : occupiedBlocks) { LocomotiveBean dbl = PersistenceFactory.getService().getLocomotive(occupiedBlock.getLocomotiveId()); if (dbl != null) { - activeLocomotives.add(dbl); + if (activeLocomotives.contains(dbl)) { + Logger.warn("Loc " + dbl.getName() + " Is allready in the list! "); + } else { + activeLocomotives.add(dbl); + } } } - if (Logger.isTraceEnabled()) { - // Logger.trace("There are " + activeLocomotives.size() + " Locomotives on the track: "); - for (LocomotiveBean loc : activeLocomotives) { - Logger.trace(loc); - } - } - return new ArrayList<>(activeLocomotives); + //if (Logger.isTraceEnabled()) { + //Logger.trace("There are " + activeLocomotives.size() + " Locomotives on the track: "); + //for (LocomotiveBean loc : activeLocomotives) { + // Logger.trace(loc); + //} + //} + return activeLocomotives; //new ArrayList<>(activeLocomotives); } public static boolean isGostDetected() { @@ -468,15 +538,15 @@ public static int avialablePermits() { return semaphore.availablePermits(); } - private static class AutoPilotThread extends Thread { + private static class AutoPilotMonitorThread extends Thread { private final List sensorListeners = new ArrayList<>(); private boolean running = false; private boolean stopped = false; - AutoPilotThread(ThreadGroup parent) { - super(parent, "AUTO_MAIN"); + AutoPilotMonitorThread(ThreadGroup parent) { + super(parent, "AUTOPILOT-MONITOR"); } void stopAutoMode() { @@ -525,7 +595,7 @@ public void run() { registerAllSensors(); prepareAllDispatchers(); - Logger.trace("Autopilot Started. Notify " + autoPilotStatusListeners.size() + " Listeners..."); + Logger.trace("Autopilot Started. There are " + dispatchers.size() + " Dispatchers created..."); for (AutoPilotStatusListener asl : autoPilotStatusListeners) { asl.statusChanged(running); @@ -547,7 +617,7 @@ public void run() { long start = now; long timeout = now + 30000; //Check if all dispachers are stopped - boolean dispatchersRunning = areDispatchersRunning(); + boolean dispatchersRunning = isADispatcherRunning(); Logger.trace("Try to finish all dispatchers. There are " + getRunningDispatcherCount() + " Dispatchers running..."); @@ -562,7 +632,7 @@ public void run() { } while (dispatchersRunning && now < timeout) { - dispatchersRunning = areDispatchersRunning(); + dispatchersRunning = isADispatcherRunning(); try { synchronized (this) { wait(10); diff --git a/src/main/java/jcs/commandStation/autopilot/AutoPilotActionEvent.java b/src/main/java/jcs/commandStation/autopilot/AutoPilotActionEvent.java new file mode 100644 index 00000000..9360dd09 --- /dev/null +++ b/src/main/java/jcs/commandStation/autopilot/AutoPilotActionEvent.java @@ -0,0 +1,46 @@ +/* + * Copyright 2025 fransjacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.commandStation.autopilot; + +import jcs.entities.LocomotiveBean; + +/** + * + * @author fransjacobs + */ +public class AutoPilotActionEvent { + + private final String actionCommand; + private final LocomotiveBean locomotiveBean; + + AutoPilotActionEvent(String actionCommand) { + this(actionCommand, null); + } + + AutoPilotActionEvent(String actionCommand, LocomotiveBean locomotiveBean) { + this.actionCommand = actionCommand; + this.locomotiveBean = locomotiveBean; + } + + String getActionCommand() { + return actionCommand; + } + + LocomotiveBean getLocomotiveBean() { + return locomotiveBean; + } + +} diff --git a/src/main/java/jcs/commandStation/autopilot/DriveSimulator.java b/src/main/java/jcs/commandStation/autopilot/DriveSimulator.java index c9e2a371..c55b839d 100644 --- a/src/main/java/jcs/commandStation/autopilot/DriveSimulator.java +++ b/src/main/java/jcs/commandStation/autopilot/DriveSimulator.java @@ -16,14 +16,11 @@ package jcs.commandStation.autopilot; import java.util.List; -import java.util.concurrent.Callable; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import jcs.JCS; -import jcs.commandStation.AccessoryController; import jcs.commandStation.FeedbackController; -import jcs.commandStation.GenericController; import jcs.commandStation.autopilot.state.Dispatcher; import jcs.commandStation.events.SensorEvent; import jcs.entities.LocomotiveBean; diff --git a/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java b/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java index b9f9f44a..647430fd 100644 --- a/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java +++ b/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java @@ -33,24 +33,23 @@ import jcs.entities.TileBean; import jcs.persistence.PersistenceFactory; import jcs.ui.layout.tiles.TileCache; -import jcs.ui.layout.events.TileEvent; import jcs.ui.layout.tiles.Tile; import org.tinylog.Logger; /** * The Dispatcher is the controlling class during auto mode of one Locomotive
- * When a Locomotive runs a separate stateMachineThread is started which handles all the states.
+ * When a Locomotive runs a separate stateMachine is started which handles all the states.
* */ public class Dispatcher { - + private final LocomotiveBean locomotiveBean; - + private RouteBean routeBean; - + private String departureBlockId; private String destinationBlockId; - + private String waitingForSensorId; //Enter Sensor of the destination private String enterSensorId; @@ -61,42 +60,42 @@ public class Dispatcher { private String occupationSensorId; //The exit of the departure private String exitSensorId; - + private final List stateEventListeners; - + private final ThreadGroup parent; - - private StateMachineThread stateMachineThread; - + + private StateMachine stateMachine; + public Dispatcher(ThreadGroup parent, LocomotiveBean locomotiveBean) { this.parent = parent; this.locomotiveBean = locomotiveBean; //Prefill with the current locomotive direction this.locomotiveBean.setDispatcherDirection(locomotiveBean.getDirection()); this.stateEventListeners = new LinkedList<>(); - this.stateMachineThread = new StateMachineThread(parent, this); + this.stateMachine = new StateMachine(parent, this); } - - StateMachineThread getStateMachineThread() { - return stateMachineThread; + + StateMachine getStateMachine() { + return stateMachine; } - + public Long getId() { return this.locomotiveBean.getId(); } - + public String getName() { return this.locomotiveBean.getName(); } - + public LocomotiveBean getLocomotiveBean() { return locomotiveBean; } - + RouteBean getRouteBean() { return routeBean; } - + void setRouteBean(RouteBean routeBean) { this.routeBean = routeBean; if (routeBean == null) { @@ -107,54 +106,54 @@ void setRouteBean(RouteBean routeBean) { this.destinationBlockId = routeBean.getToTileId(); } } - + public boolean isLocomotiveAutomodeOn() { - return this.stateMachineThread.isEnableAutomode(); + return stateMachine.isAutomodeEnabled(); } - + public boolean startLocomotiveAutomode() { //Only when the Autopilot is ON! if (AutoPilot.isAutoModeActive()) { - stateMachineThread.setEnableAutomode(true); + stateMachine.setEnableAutomode(true); //is the thread running? startRunning(); } - return this.stateMachineThread.isEnableAutomode(); + return this.stateMachine.isAutomodeEnabled(); } - + public void stopLocomotiveAutomode() { - stateMachineThread.setEnableAutomode(false); + stateMachine.setEnableAutomode(false); } - + void startRunning() { - if (this.stateMachineThread != null && this.stateMachineThread.isThreadRunning()) { + if (this.stateMachine != null && this.stateMachine.isThreadRunning()) { return; } - - if (this.stateMachineThread == null || !this.stateMachineThread.isAlive()) { - stateMachineThread = new StateMachineThread(this.parent, this); + + if (this.stateMachine == null || !this.stateMachine.isAlive()) { + stateMachine = new StateMachine(this.parent, this); } - - this.stateMachineThread.setEnableAutomode(true); - if (!this.stateMachineThread.isThreadRunning()) { - this.stateMachineThread.start(); + + this.stateMachine.setEnableAutomode(true); + if (!this.stateMachine.isThreadRunning()) { + this.stateMachine.start(); } } - + public void stopRunning() { - if (stateMachineThread != null && stateMachineThread.isThreadRunning()) { - stateMachineThread.stopRunningThread(); - + if (stateMachine != null && stateMachine.isThreadRunning()) { + stateMachine.stopRunningThread(); + try { Logger.trace(this.getName() + " Thread Joining..."); - stateMachineThread.join(); + stateMachine.join(); } catch (InterruptedException ex) { Logger.trace("Join error " + ex); } Logger.trace(this.getName() + " Thread Joined!"); } } - + void resetDispatcher() { this.routeBean = null; this.departureBlockId = null; @@ -166,16 +165,16 @@ void resetDispatcher() { this.stateEventListeners.clear(); this.locomotiveBean.setDispatcherDirection(Direction.SWITCH); } - + public void reset() { Logger.trace("Resetting dispatcher " + getName() + " StateMachine..."); - this.stateMachineThread.reset(); + this.stateMachine.reset(); resetDispatcher(); } - + public boolean isRunning() { - if (stateMachineThread != null) { - return stateMachineThread.isThreadRunning(); + if (stateMachine != null) { + return stateMachine.isThreadRunning(); } else { return false; } @@ -194,7 +193,7 @@ BlockBean getDepartureBlock() { return departureBlock; } } - + BlockBean getDestinationBlock() { if (destinationBlockId != null) { return PersistenceFactory.getService().getBlockByTileId(destinationBlockId); @@ -205,55 +204,55 @@ BlockBean getDestinationBlock() { return null; } } - + public String getStateName() { - if (stateMachineThread != null) { - return stateMachineThread.getDispatcherStateName(); + if (stateMachine != null) { + return stateMachine.getDispatcherStateName(); } else { return "#Idle"; } } - + void setWaitForSensorid(String sensorId) { this.waitingForSensorId = sensorId; } - + public String getWaitingForSensorId() { return waitingForSensorId; } - + public String getEnterSensorId() { return enterSensorId; } - + void setEnterSensorId(String enterSensorId) { this.enterSensorId = enterSensorId; } - + public String getInSensorId() { return inSensorId; } - + void setInSensorId(String inSensorId) { this.inSensorId = inSensorId; } - + public String getOccupationSensorId() { return occupationSensorId; } - + void setOccupationSensorId(String occupationSensorId) { this.occupationSensorId = occupationSensorId; } - + public String getExitSensorId() { return exitSensorId; } - + void setExitSensorId(String exitSensorId) { this.exitSensorId = exitSensorId; } - + void clearDepartureIgnoreEventHandlers() { if (departureBlockId != null) { BlockBean departureBlock = getDepartureBlock(); @@ -263,7 +262,7 @@ void clearDepartureIgnoreEventHandlers() { AutoPilot.removeHandler(plusSensorId); } } - + public void onIgnoreEvent(SensorEvent event) { //Only in Simulator mode if (JCS.getJcsCommandStation().getCommandStationBean().isVirtual()) { @@ -272,19 +271,19 @@ public void onIgnoreEvent(SensorEvent event) { this.waitingForSensorId = null; } } - + if (this.enterSensorId != null && this.enterSensorId.equals(event.getId())) { if (!event.isActive()) { this.enterSensorId = null; } } - + if (this.inSensorId != null && this.inSensorId.equals(event.getId())) { if (!event.isActive()) { this.inSensorId = null; } } - + if (this.exitSensorId != null && this.exitSensorId.equals(event.getId())) { if (!event.isActive()) { this.exitSensorId = null; @@ -293,35 +292,39 @@ public void onIgnoreEvent(SensorEvent event) { } //Logger.trace("Event for a ignored listener: " + event.getId() + " Changed: " + event.isChanged() + ", active: " + event.getSensorBean().isActive()); } - + synchronized void switchAccessory(AccessoryBean accessory, AccessoryValue value) { JCS.getJcsCommandStation().switchAccessory(accessory, value); } - + synchronized void changeLocomotiveVelocity(LocomotiveBean locomotive, int velocity) { JCS.getJcsCommandStation().changeLocomotiveSpeed(velocity, locomotive); locomotiveBean.setVelocity(velocity); } - + synchronized void changeLocomotiveDirection(LocomotiveBean locomotive, Direction newDirection) { JCS.getJcsCommandStation().changeLocomotiveDirection(newDirection, locomotive); locomotiveBean.setDirection(newDirection); } - - void fireStateListeners(String s) { + + public void fireStateListeners(String s) { for (StateEventListener sel : stateEventListeners) { sel.onStateChange(this); } } - + public void addStateEventListener(StateEventListener listener) { stateEventListeners.add(listener); } - + public void removeStateEventListener(StateEventListener listener) { stateEventListeners.remove(listener); } - + + public void removeAllStateEventListeners() { + stateEventListeners.clear(); + } + public static void resetRoute(RouteBean route) { List routeElements = route.getRouteElements(); for (RouteElementBean re : routeElements) { @@ -344,26 +347,27 @@ public static void resetRoute(RouteBean route) { } } } - + void showBlockState(BlockBean blockBean) { - Logger.trace("Show block " + blockBean); Tile tile = TileCache.findTile(blockBean.getTileId()); - tile.setBlockBean(blockBean); + if (tile != null) { + tile.setBlockBean(blockBean); + } } - + void showRoute(RouteBean routeBean, Color routeColor) { Logger.trace("Show route " + routeBean.toLogString()); List routeElements = routeBean.getRouteElements(); - + for (RouteElementBean re : routeElements) { String tileId = re.getTileId(); Tile tile = TileCache.findTile(tileId); if (tile != null) { TileBean.Orientation incomingSide = re.getIncomingOrientation(); - + tile.setIncomingSide(incomingSide); tile.setTrackRouteColor(Tile.DEFAULT_ROUTE_TRACK_COLOR); - + if (re.isTurnout()) { AccessoryBean.AccessoryValue routeState = re.getAccessoryValue(); tile.setRouteValue(routeState); @@ -381,19 +385,19 @@ void showRoute(RouteBean routeBean, Color routeColor) { } } } - + int getRandomNumber(int min, int max) { Random random = new Random(); return random.ints(min, max).findFirst().getAsInt(); } - + @Override public int hashCode() { int hash = 7; hash = 37 * hash + Objects.hashCode(locomotiveBean.getId()); return hash; } - + @Override public boolean equals(Object obj) { if (this == obj) { diff --git a/src/main/java/jcs/commandStation/autopilot/state/IdleState.java b/src/main/java/jcs/commandStation/autopilot/state/IdleState.java index 01988258..4ec46479 100644 --- a/src/main/java/jcs/commandStation/autopilot/state/IdleState.java +++ b/src/main/java/jcs/commandStation/autopilot/state/IdleState.java @@ -60,8 +60,10 @@ DispatcherState execute(Dispatcher dispatcher) { Logger.trace("Interrupted: " + ex.getMessage()); } } else { - //Automode is switched off for this Dispatcher so the Idle state must end... + //Locomotive is stopped... Logger.trace(dispatcher.getName() + " Automode: " + AutoPilot.isAutoModeActive() + " Dispacher " + dispatcher.isLocomotiveAutomodeOn()); + + //stop this thread... try { synchronized (this) { wait(10000); diff --git a/src/main/java/jcs/commandStation/autopilot/state/StateMachineThread.java b/src/main/java/jcs/commandStation/autopilot/state/StateMachine.java similarity index 92% rename from src/main/java/jcs/commandStation/autopilot/state/StateMachineThread.java rename to src/main/java/jcs/commandStation/autopilot/state/StateMachine.java index a15defc5..2c3aeb39 100644 --- a/src/main/java/jcs/commandStation/autopilot/state/StateMachineThread.java +++ b/src/main/java/jcs/commandStation/autopilot/state/StateMachine.java @@ -41,33 +41,33 @@ * * @author frans */ -class StateMachineThread extends Thread { - +class StateMachine extends Thread { + private final Dispatcher dispatcher; private DispatcherState dispatcherState; - + private boolean running = false; - + private boolean enableAutomode = false; private boolean resetRequested = false; - - StateMachineThread(ThreadGroup parent, Dispatcher dispatcher) { - super(parent, "STM->" + dispatcher.getLocomotiveBean().getName()); + + StateMachine(ThreadGroup parent, Dispatcher dispatcher) { + super(parent, "STM->" + dispatcher.getLocomotiveBean().getName().toUpperCase()); this.dispatcher = dispatcher; this.dispatcherState = new IdleState(); } - + boolean isThreadRunning() { return this.running; } - + synchronized void stopRunningThread() { this.running = false; this.enableAutomode = false; notifyAll(); } - - boolean isEnableAutomode() { + + boolean isAutomodeEnabled() { return this.enableAutomode; } @@ -82,46 +82,56 @@ synchronized void reset() { //Switch of running this.enableAutomode = false; this.resetRequested = true; - + Logger.trace("Reset requested..."); if (running) { notifyAll(); } } - + DispatcherState getDispatcherState() { return dispatcherState; } - + String getDispatcherStateName() { return dispatcherState.getName(); } - + void handleState() { //Obtain current dispatcherState DispatcherState previousState = dispatcherState; //Execute the action for the current dispatcherState dispatcherState = dispatcherState.execute(dispatcher); - + if ("true".equals(System.getProperty("state.machine.stepTest", "false"))) { Logger.debug("Current State: " + dispatcherState.getName() + " Previous State: " + previousState.getName()); } - + if (!AutoPilot.isAutoModeActive()) { //Automode has stopped, let the Thread finish when WaitState is reached or is Idle if (dispatcherState instanceof IdleState || dispatcherState instanceof WaitState) { Logger.trace(getName() + " Stopping thread as Autopilot automode is stopped"); this.running = false; //Just stop - synchronized(this) { + synchronized (this) { + this.notifyAll(); + } + } + } + + if (!dispatcher.isLocomotiveAutomodeOn()) { + if (dispatcherState instanceof IdleState) { + Logger.trace(getName() + " Stopping thread as Locomotive " + dispatcher.getName() + " has stopped..."); + this.running = false; + synchronized (this) { this.notifyAll(); } } } - + if (previousState != dispatcherState || dispatcherState instanceof WaitState) { //handle the dispatcherState changes - Logger.trace("Fire for "+dispatcherState.getName()); + Logger.trace("Fire for " + dispatcherState.getName()); dispatcher.fireStateListeners(dispatcherState.getName()); } @@ -145,7 +155,7 @@ void resetStateMachine() { Logger.trace("Removing " + sensorEventListener.toString() + " as Sensor Listener..."); JCS.getJcsCommandStation().removeSensorEventListener(sensorEventListener); } - + dispatcher.clearDepartureIgnoreEventHandlers(); //Restore the Departure block state @@ -158,7 +168,7 @@ void resetStateMachine() { destinationBlock.setLocomotive(null); destinationBlock.setArrivalSuffix(null); destinationBlock.setReverseArrival(false); - + PersistenceFactory.getService().persist(departureBlock); PersistenceFactory.getService().persist(destinationBlock); @@ -166,15 +176,15 @@ void resetStateMachine() { RouteBean route = dispatcher.getRouteBean(); route.setLocked(false); Dispatcher.resetRoute(route); - + PersistenceFactory.getService().persist(route); dispatcher.setRouteBean(null); - + dispatcher.showBlockState(departureBlock); dispatcher.showBlockState(destinationBlock); - + dispatcherState = new IdleState(); - + this.resetRequested = false; } @@ -200,7 +210,7 @@ public void run() { this.running = true; Logger.trace(getName() + " Started. State " + dispatcherState.getName() + "..."); } - + while (running) { if (resetRequested) { resetStateMachine(); @@ -208,7 +218,7 @@ public void run() { handleState(); } } - + Logger.trace(getName() + " in state " + dispatcherState.getClass().getSimpleName() + " is ending..."); //Make sure that also the linked locomotive is stopped @@ -223,19 +233,14 @@ public void run() { } else { Logger.trace("No sensor listeners are registered..."); } - + dispatcher.clearDepartureIgnoreEventHandlers(); Logger.trace("Ignore Handlers removed..."); - + dispatcher.fireStateListeners(getName() + " Finished"); Logger.trace(getName() + " State listeners fired..."); - + Logger.trace(getName() + " last state " + dispatcherState.getClass().getSimpleName() + " is Finished"); } - -// synchronized void sensorUpdated(final SensorEvent sensorEvent) { -// Logger.trace("Sensor " + sensorEvent.getId() + " Value " + (sensorEvent.isActive() ? "On" : "Off")); -// this.notifyAll(); -// } - + } diff --git a/src/main/java/jcs/commandStation/esu/ecos/FeedbackManager.java b/src/main/java/jcs/commandStation/esu/ecos/FeedbackManager.java index 87c97142..d55e6f72 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/FeedbackManager.java +++ b/src/main/java/jcs/commandStation/esu/ecos/FeedbackManager.java @@ -42,7 +42,6 @@ class FeedbackManager { } private List parse(EcosMessage message) { - Logger.trace(message.getMessage()); Logger.trace(message.getResponse()); List changedSensors; diff --git a/src/main/java/jcs/ui/DispatcherStatusPanel.java b/src/main/java/jcs/ui/DispatcherStatusPanel.java index 8495ad73..d9f52bc7 100644 --- a/src/main/java/jcs/ui/DispatcherStatusPanel.java +++ b/src/main/java/jcs/ui/DispatcherStatusPanel.java @@ -30,7 +30,19 @@ public class DispatcherStatusPanel extends JPanel implements RefreshEventListene public DispatcherStatusPanel() { initComponents(); } - + + public void showDispatcherTab() { + this.tabsPane.setSelectedIndex(1); + } + + public void showLocomotiveTab() { + this.tabsPane.setSelectedIndex(0); + } + + public void refresh() { + this.locomotiveTablePanel.refresh(); + } + @Override public void onChange(RefreshEvent event) { this.locomotiveTablePanel.onChange(event); diff --git a/src/main/java/jcs/ui/JCSFrame.form b/src/main/java/jcs/ui/JCSFrame.form index 4da3c4b3..6ab04d2b 100755 --- a/src/main/java/jcs/ui/JCSFrame.form +++ b/src/main/java/jcs/ui/JCSFrame.form @@ -409,7 +409,7 @@ - + @@ -480,7 +480,7 @@ - + @@ -583,7 +583,7 @@ - + @@ -616,12 +616,12 @@ - + - + - + @@ -629,7 +629,9 @@ - + + + @@ -642,25 +644,39 @@ - + - - - - + + + + + + + + + + + + + + + + + + - + - + @@ -689,7 +705,7 @@ - + @@ -700,35 +716,12 @@ - + - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/src/main/java/jcs/ui/JCSFrame.java b/src/main/java/jcs/ui/JCSFrame.java index 4988a9c7..bb8db46f 100755 --- a/src/main/java/jcs/ui/JCSFrame.java +++ b/src/main/java/jcs/ui/JCSFrame.java @@ -244,7 +244,7 @@ private void setControllerProperties() { } private void showSensorMonitor() { - if (this.feedbackMonitor == null) { + if (feedbackMonitor == null) { Logger.trace("Creating a Monitor UI"); feedbackMonitor = new FeedbackMonitor(); FrameMonitor.registerFrame(feedbackMonitor, FeedbackMonitor.class.getName()); @@ -277,10 +277,10 @@ private void initComponents() { showFeedbackMonitorBtn = new JButton(); filler8 = new Box.Filler(new Dimension(20, 0), new Dimension(20, 0), new Dimension(20, 32767)); autoPilotBtn = new JToggleButton(); - startAllLocomotivesBtn = new JToggleButton(); - resetAutoPilotBtn = new JButton(); + startAllLocsBtn = new JButton(); filler9 = new Box.Filler(new Dimension(20, 0), new Dimension(20, 0), new Dimension(20, 32767)); - showSettingsBtn = new JButton(); + resetAutoPilotBtn = new JButton(); + filler10 = new Box.Filler(new Dimension(20, 0), new Dimension(20, 0), new Dimension(20, 32767)); statusPanel = new StatusPanel(); mainPanel = new JPanel(); locoDisplaySP = new JSplitPane(); @@ -436,7 +436,7 @@ public void actionPerformed(ActionEvent evt) { jcsToolBar.add(filler4); showEditDesignBtn.setIcon(new ImageIcon(getClass().getResource("/media/paintbrush-24.png"))); // NOI18N - showEditDesignBtn.setToolTipText("Design Layout"); + showEditDesignBtn.setToolTipText("Edit Layout"); showEditDesignBtn.setBorder(BorderFactory.createLineBorder(new Color(204, 204, 204))); showEditDesignBtn.setFocusable(false); showEditDesignBtn.setHorizontalTextPosition(SwingConstants.CENTER); @@ -473,7 +473,7 @@ public void actionPerformed(ActionEvent evt) { jcsToolBar.add(showVNCBtn); showKeyboardBtn.setIcon(new ImageIcon(getClass().getResource("/media/controller-24.png"))); // NOI18N - showKeyboardBtn.setToolTipText("Diagnostics"); + showKeyboardBtn.setToolTipText("Show Accessory Keyboard"); showKeyboardBtn.setBorder(BorderFactory.createLineBorder(new Color(204, 204, 204))); showKeyboardBtn.setDoubleBuffered(true); showKeyboardBtn.setFocusable(false); @@ -516,7 +516,7 @@ public void actionPerformed(ActionEvent evt) { jcsToolBar.add(filler8); autoPilotBtn.setIcon(new ImageIcon(getClass().getResource("/media/pilot.png"))); // NOI18N - autoPilotBtn.setToolTipText("Connect/Disconnect with Central Station"); + autoPilotBtn.setToolTipText("En- or Disable automatic driving"); autoPilotBtn.setBorder(BorderFactory.createLineBorder(new Color(204, 204, 204))); autoPilotBtn.setDoubleBuffered(true); autoPilotBtn.setFocusable(false); @@ -535,29 +535,31 @@ public void actionPerformed(ActionEvent evt) { }); jcsToolBar.add(autoPilotBtn); - startAllLocomotivesBtn.setIcon(new ImageIcon(getClass().getResource("/media/cruise-control-on-black.png"))); // NOI18N - startAllLocomotivesBtn.setToolTipText("Connect/Disconnect with Central Station"); - startAllLocomotivesBtn.setBorder(BorderFactory.createLineBorder(new Color(204, 204, 204))); - startAllLocomotivesBtn.setDoubleBuffered(true); - startAllLocomotivesBtn.setEnabled(false); - startAllLocomotivesBtn.setFocusable(false); - startAllLocomotivesBtn.setHorizontalTextPosition(SwingConstants.CENTER); - startAllLocomotivesBtn.setMargin(new Insets(0, 0, 0, 0)); - startAllLocomotivesBtn.setMaximumSize(new Dimension(40, 40)); - startAllLocomotivesBtn.setMinimumSize(new Dimension(40, 40)); - startAllLocomotivesBtn.setName("startAllLocomotivesBtn"); // NOI18N - startAllLocomotivesBtn.setPreferredSize(new Dimension(40, 40)); - startAllLocomotivesBtn.setSelectedIcon(new ImageIcon(getClass().getResource("/media/cruise-control-on-green.png"))); // NOI18N - startAllLocomotivesBtn.setVerticalTextPosition(SwingConstants.BOTTOM); - startAllLocomotivesBtn.addActionListener(new ActionListener() { + startAllLocsBtn.setIcon(new ImageIcon(getClass().getResource("/media/arrowhead-right-gn.png"))); // NOI18N + startAllLocsBtn.setToolTipText("Start all Locomotives"); + startAllLocsBtn.setBorder(BorderFactory.createLineBorder(new Color(204, 204, 204))); + startAllLocsBtn.setDisabledIcon(new ImageIcon(getClass().getResource("/media/pause-gr.png"))); // NOI18N + startAllLocsBtn.setEnabled(false); + startAllLocsBtn.setFocusable(false); + startAllLocsBtn.setHorizontalTextPosition(SwingConstants.CENTER); + startAllLocsBtn.setMargin(new Insets(0, 0, 0, 0)); + startAllLocsBtn.setMaximumSize(new Dimension(40, 40)); + startAllLocsBtn.setMinimumSize(new Dimension(40, 40)); + startAllLocsBtn.setName("startAllLocsBtn"); // NOI18N + startAllLocsBtn.setPreferredSize(new Dimension(40, 40)); + startAllLocsBtn.setVerticalTextPosition(SwingConstants.BOTTOM); + startAllLocsBtn.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { - startAllLocomotivesBtnActionPerformed(evt); + startAllLocsBtnActionPerformed(evt); } }); - jcsToolBar.add(startAllLocomotivesBtn); + jcsToolBar.add(startAllLocsBtn); + + filler9.setName("filler9"); // NOI18N + jcsToolBar.add(filler9); - resetAutoPilotBtn.setIcon(new ImageIcon(getClass().getResource("/media/director-red.png"))); // NOI18N - resetAutoPilotBtn.setToolTipText("Design Layout"); + resetAutoPilotBtn.setIcon(new ImageIcon(getClass().getResource("/media/reset-happy.png"))); // NOI18N + resetAutoPilotBtn.setToolTipText("Stop and Reset AutoPilot"); resetAutoPilotBtn.setBorder(BorderFactory.createLineBorder(new Color(204, 204, 204))); resetAutoPilotBtn.setFocusable(false); resetAutoPilotBtn.setHorizontalTextPosition(SwingConstants.CENTER); @@ -574,23 +576,8 @@ public void actionPerformed(ActionEvent evt) { }); jcsToolBar.add(resetAutoPilotBtn); - filler9.setName("filler9"); // NOI18N - jcsToolBar.add(filler9); - - showSettingsBtn.setIcon(new ImageIcon(getClass().getResource("/media/load-24.png"))); // NOI18N - showSettingsBtn.setFocusable(false); - showSettingsBtn.setHorizontalTextPosition(SwingConstants.CENTER); - showSettingsBtn.setMaximumSize(new Dimension(40, 40)); - showSettingsBtn.setMinimumSize(new Dimension(40, 40)); - showSettingsBtn.setName("showSettingsBtn"); // NOI18N - showSettingsBtn.setPreferredSize(new Dimension(40, 40)); - showSettingsBtn.setVerticalTextPosition(SwingConstants.BOTTOM); - showSettingsBtn.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent evt) { - showSettingsBtnActionPerformed(evt); - } - }); - jcsToolBar.add(showSettingsBtn); + filler10.setName("filler10"); // NOI18N + jcsToolBar.add(filler10); toolbarPanel.add(jcsToolBar); @@ -873,13 +860,13 @@ private void showKeyboardBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_ }//GEN-LAST:event_showKeyboardBtnActionPerformed private void quitMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_quitMIActionPerformed - this.dispatchEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING)); + dispatchEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING)); }//GEN-LAST:event_quitMIActionPerformed private void formWindowClosing(WindowEvent evt) {//GEN-FIRST:event_formWindowClosing boolean closed = this.handleQuitRequest(); if (closed) { - this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(false); dispose(); @@ -903,7 +890,7 @@ private void showEditDesignBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:even private void showOverviewBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_showOverviewBtnActionPerformed showOverviewPanel(); - this.overviewPanel.loadLayout(); + overviewPanel.loadLayout(); }//GEN-LAST:event_showOverviewBtnActionPerformed private void powerButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_powerButtonActionPerformed @@ -994,10 +981,6 @@ private void commandStationsMIActionPerformed(ActionEvent evt) {//GEN-FIRST:even csd.setVisible(true); }//GEN-LAST:event_commandStationsMIActionPerformed - private void showSettingsBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_showSettingsBtnActionPerformed - showSettings(); - }//GEN-LAST:event_showSettingsBtnActionPerformed - private void aboutMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_aboutMIActionPerformed Logger.trace(evt.getActionCommand()); AboutDialog dialog = new AboutDialog(this, true); @@ -1012,31 +995,22 @@ private void showVNCBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_showV }//GEN-LAST:event_showVNCBtnActionPerformed private void autoPilotBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_autoPilotBtnActionPerformed - Logger.trace(evt.getActionCommand() + (this.autoPilotBtn.isSelected() ? " Enable" : " Disable") + " Auto mode"); + //Logger.trace(evt.getActionCommand() + (autoPilotBtn.isSelected() ? " Enable" : " Disable") + " Auto mode"); - if (this.autoPilotBtn.isSelected()) { - this.startAllLocomotivesBtn.setEnabled(true); + if (autoPilotBtn.isSelected()) { + startAllLocsBtn.setEnabled(true); + dispatcherStatusPanel.showDispatcherTab(); + // startAllLocsBtn.setIcon(new ImageIcon(getClass().getResource("/media/arrowhead-right-gn.png"))); } else { - if (this.startAllLocomotivesBtn.isSelected()) { - startAllLocomotivesBtn.doClick(); - } - this.startAllLocomotivesBtn.setEnabled(false); + startAllLocsBtn.setEnabled(false); + dispatcherStatusPanel.showLocomotiveTab(); } - AutoPilot.runAutoPilot(this.autoPilotBtn.isSelected()); + AutoPilot.runAutoPilot(autoPilotBtn.isSelected()); }//GEN-LAST:event_autoPilotBtnActionPerformed - private void startAllLocomotivesBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_startAllLocomotivesBtnActionPerformed - Logger.trace(evt.getActionCommand() + " Start All Locomotives " + this.startAllLocomotivesBtn.isSelected()); - if (this.startAllLocomotivesBtn.isSelected()) { - AutoPilot.startAllLocomotives(); - } else { - AutoPilot.stopAllLocomotives(); - } - }//GEN-LAST:event_startAllLocomotivesBtnActionPerformed - private void resetAutoPilotBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_resetAutoPilotBtnActionPerformed - AutoPilot.resetStates(); + AutoPilot.reset(); }//GEN-LAST:event_resetAutoPilotBtnActionPerformed private void virtualCBActionPerformed(ActionEvent evt) {//GEN-FIRST:event_virtualCBActionPerformed @@ -1046,6 +1020,13 @@ private void virtualCBActionPerformed(ActionEvent evt) {//GEN-FIRST:event_virtua } }//GEN-LAST:event_virtualCBActionPerformed + private void startAllLocsBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_startAllLocsBtnActionPerformed + int result = JOptionPane.showConfirmDialog(this, "Are you sure you want to start All Locomotives?", "Start ALL Locomotives", JOptionPane.YES_NO_OPTION); + if (result == JOptionPane.YES_OPTION) { + AutoPilot.startAllLocomotives(); + } + }//GEN-LAST:event_startAllLocsBtnActionPerformed + private String getTitleString() { String jcsVersion = VersionInfo.getVersion(); @@ -1128,6 +1109,7 @@ public void powerChanged(PowerEvent event) { private JMenuItem editLayout; private JMenu fileMenu; private Box.Filler filler1; + private Box.Filler filler10; private Box.Filler filler2; private Box.Filler filler3; private Box.Filler filler4; @@ -1162,9 +1144,8 @@ public void powerChanged(PowerEvent event) { private JMenuItem showLocosMI; private JButton showOverviewBtn; private JMenuItem showSensorMonitor; - private JButton showSettingsBtn; private JButton showVNCBtn; - private JToggleButton startAllLocomotivesBtn; + private JButton startAllLocsBtn; private StatusPanel statusPanel; private JPanel toolbarPanel; private JMenu toolsMenu; diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.java b/src/main/java/jcs/ui/layout/LayoutCanvas.java index 8e3672ef..34b3ad87 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.java +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.java @@ -955,18 +955,18 @@ private void formMouseDragged(MouseEvent evt) {//GEN-FIRST:event_formMouseDragge }//GEN-LAST:event_formMouseDragged private void startLocomotiveMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_startLocomotiveMIActionPerformed - if (this.selectedTile != null) { - Block block = (Block) selectedTile; - LocomotiveBean locomotive = block.getLocomotive(); - executor.execute(() -> AutoPilot.startStopLocomotive(locomotive, true)); + if (selectedTile != null && selectedTile.isBlock() && selectedTile.getLocomotive() != null) { + LocomotiveBean locomotive = selectedTile.getLocomotive(); + //executor.execute(() -> AutoPilot.startStopLocomotive(locomotive, true)); + AutoPilot.startLocomotive(locomotive); } }//GEN-LAST:event_startLocomotiveMIActionPerformed private void stopLocomotiveMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_stopLocomotiveMIActionPerformed - if (selectedTile != null) { - Block block = (Block) selectedTile; - LocomotiveBean locomotive = block.getLocomotive(); - executor.execute(() -> AutoPilot.startStopLocomotive(locomotive, false)); + if (selectedTile != null && selectedTile.isBlock() && selectedTile.getLocomotive() != null) { + LocomotiveBean locomotive = selectedTile.getLocomotive(); + //executor.execute(() -> AutoPilot.startStopLocomotive(locomotive, false)); + AutoPilot.stopLocomotive(locomotive); } }//GEN-LAST:event_stopLocomotiveMIActionPerformed @@ -983,27 +983,28 @@ private void resetDispatcherMIActionPerformed(ActionEvent evt) {//GEN-FIRST:even }//GEN-LAST:event_resetDispatcherMIActionPerformed private void removeLocMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_removeLocMIActionPerformed - if (selectedTile != null) { - Block block = (Block) selectedTile; - LocomotiveBean locomotive = block.getLocomotive(); + if (selectedTile != null && selectedTile.isBlock()) { + LocomotiveBean locomotive = selectedTile.getLocomotive(); locomotive.setDispatcherDirection(null); - - block.setLocomotive(null); - + + selectedTile.setLocomotive(null); + executor.execute(() -> { - PersistenceFactory.getService().persist(block.getBlockBean()); + PersistenceFactory.getService().persist(selectedTile.getBlockBean()); PersistenceFactory.getService().persist(locomotive); + + AutoPilot.removeLocomotive(locomotive); }); } }//GEN-LAST:event_removeLocMIActionPerformed private void blockPropertiesMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_blockPropertiesMIActionPerformed - if (this.selectedTile != null) { + if (selectedTile != null && selectedTile.isBlock()) { //show the Block control dialog so tha a locomotive can be assigned to the block - Block block = (Block) selectedTile; - BlockControlDialog bcd = new BlockControlDialog(getParentFrame(), block); + BlockControlDialog bcd = new BlockControlDialog(getParentFrame(), (Block) selectedTile); bcd.setVisible(true); - repaint(block.getTileBounds()); + + repaint(selectedTile.getTileBounds()); } }//GEN-LAST:event_blockPropertiesMIActionPerformed diff --git a/src/main/java/jcs/ui/layout/LayoutPanel.java b/src/main/java/jcs/ui/layout/LayoutPanel.java index 20ae29ef..9917b52c 100755 --- a/src/main/java/jcs/ui/layout/LayoutPanel.java +++ b/src/main/java/jcs/ui/layout/LayoutPanel.java @@ -18,7 +18,6 @@ import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.FlowLayout; -import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ComponentAdapter; @@ -848,7 +847,7 @@ private void sensorBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_sensor }//GEN-LAST:event_sensorBtnActionPerformed private void gridBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_gridBtnActionPerformed - this.canvas.setDrawGrid(this.gridBtn.isSelected()); + this.canvas.setDrawGrid(this.gridBtn.isSelected()); }//GEN-LAST:event_gridBtnActionPerformed private void formComponentResized(ComponentEvent evt) {//GEN-FIRST:event_formComponentResized @@ -897,27 +896,24 @@ private void endTrackBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_endT }//GEN-LAST:event_endTrackBtnActionPerformed private void autoPilotBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_autoPilotBtnActionPerformed - Logger.trace(evt.getActionCommand() + (this.autoPilotBtn.isSelected() ? " Enable" : " Disable") + " Auto mode"); + Logger.trace(evt.getActionCommand() + (autoPilotBtn.isSelected() ? " Enable" : " Disable") + " Auto mode"); - if (this.autoPilotBtn.isSelected()) { - this.startAllLocomotivesBtn.setEnabled(true); + if (autoPilotBtn.isSelected()) { + startAllLocomotivesBtn.setEnabled(true); } else { - if (this.startAllLocomotivesBtn.isSelected()) { - startAllLocomotivesBtn.doClick(); - } - this.startAllLocomotivesBtn.setEnabled(false); + ///if (startAllLocomotivesBtn.isSelected()) { + // startAllLocomotivesBtn.doClick(); + //} + startAllLocomotivesBtn.setEnabled(false); } - AutoPilot.runAutoPilot(this.autoPilotBtn.isSelected()); - + AutoPilot.runAutoPilot(autoPilotBtn.isSelected()); }//GEN-LAST:event_autoPilotBtnActionPerformed private void startAllLocomotivesBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_startAllLocomotivesBtnActionPerformed Logger.trace(evt.getActionCommand() + " Start All Locomotives " + this.startAllLocomotivesBtn.isSelected()); if (this.startAllLocomotivesBtn.isSelected()) { AutoPilot.startAllLocomotives(); - } else { - AutoPilot.stopAllLocomotives(); } }//GEN-LAST:event_startAllLocomotivesBtnActionPerformed @@ -926,7 +922,7 @@ private void crossingBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_cros }//GEN-LAST:event_crossingBtnActionPerformed private void resetAutopilotBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_resetAutopilotBtnActionPerformed - AutoPilot.resetStates(); + AutoPilot.reset(); }//GEN-LAST:event_resetAutopilotBtnActionPerformed private void setTileType(TileBean.TileType tileType) { diff --git a/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java b/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java index 88409cd5..1fe853fa 100644 --- a/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java +++ b/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java @@ -433,6 +433,8 @@ private void saveExitBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-F if (bb.getLocomotive() != null && bb.getLocomotive().getName() != null) { LocomotiveBean loc = bb.getLocomotive(); PersistenceFactory.getService().persist(loc); + + AutoPilot.addLocomotive(loc); } TileCache.findTile(bb.getTileId()).setBlockBean(bb); @@ -448,6 +450,7 @@ private void locomotiveCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN- LocomotiveBean selected = (LocomotiveBean) locomotiveComboBoxModel.getSelectedItem(); + LocomotiveBean previous = block.getLocomotive(); if (selected.getId() != null) { block.setLocomotive(selected); } else { @@ -472,12 +475,21 @@ private void locomotiveCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN- } else { startLocButton.setEnabled(false); } + + if (previous != null && previous.getId() != null && !previous.getId().equals(selected.getId())) { + AutoPilot.removeLocomotive(previous); + } + }//GEN-LAST:event_locomotiveCBActionPerformed private void startLocButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_startLocButtonActionPerformed LocomotiveBean loc = block.getLocomotive(); if (loc != null) { - AutoPilot.startStopLocomotive(loc, startLocButton.isSelected()); + if (startLocButton.isSelected()) { + AutoPilot.startLocomotive(loc); + } else { + AutoPilot.stopLocomotive(loc); + } } }//GEN-LAST:event_startLocButtonActionPerformed diff --git a/src/main/java/jcs/ui/layout/events/TileEvent.java b/src/main/java/jcs/ui/layout/events/TileEvent.java deleted file mode 100644 index de3b4f1b..00000000 --- a/src/main/java/jcs/ui/layout/events/TileEvent.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright 2023 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout.events; - -import java.awt.Color; -import jcs.entities.AccessoryBean; -import jcs.entities.AccessoryBean.AccessoryValue; -import jcs.entities.BlockBean; -import jcs.entities.BlockBean.BlockState; -import jcs.entities.TileBean; -import jcs.entities.TileBean.Orientation; -import jcs.ui.layout.tiles.Tile; - -/** - * - * @author Frans Jacobs - */ -public class TileEvent { - - private final String tileId; - - private final Color backgroundColor; - private final Color trackColor; - private final Color trackRouteColor; - - private final Orientation incomingSide; - private final boolean showRoute; - - private AccessoryBean.AccessoryValue routeState; - private BlockBean blockBean; - private TileBean tileBean; - - private BlockState blockState; - - public TileEvent(String tileId, boolean showRoute) { - this(tileId, showRoute, null, AccessoryValue.OFF); - } - - public TileEvent(String tileId, boolean showRoute, Orientation incomingSide) { - this(tileId, showRoute, incomingSide, AccessoryValue.OFF); - } - - public TileEvent(String tileId, boolean showRoute, Orientation incomingSide, Color trackRouteColor) { - this(tileId, showRoute, incomingSide, AccessoryValue.OFF, trackRouteColor); - } - - public TileEvent(String tileId, boolean showRoute, Orientation incomingSide, AccessoryValue routeState) { - this(tileId, showRoute, incomingSide, routeState, Tile.DEFAULT_ROUTE_TRACK_COLOR); - } - - public TileEvent(String tileId, boolean showRoute, Orientation incomingSide, AccessoryValue routeState, Color trackRouteColor) { - this(tileId, showRoute, incomingSide, routeState, Tile.DEFAULT_BACKGROUND_COLOR, Tile.DEFAULT_TRACK_COLOR, trackRouteColor, BlockState.FREE); - } - - public TileEvent(String tileId, boolean showRoute, BlockState blockState) { - this(tileId, showRoute, null, AccessoryValue.OFF, Tile.DEFAULT_BACKGROUND_COLOR, Tile.DEFAULT_TRACK_COLOR, Tile.DEFAULT_ROUTE_TRACK_COLOR, blockState); - } - - public TileEvent(String tileId, boolean showRoute, Orientation incomingSide, AccessoryValue routeState, Color backgroundColor, Color trackColor, Color trackRouteColor, BlockState blockState) { - this.tileId = tileId; - this.showRoute = showRoute; - this.incomingSide = incomingSide; - this.routeState = routeState; - - this.tileBean = null; - this.blockBean = null; - - this.backgroundColor = backgroundColor; - this.trackColor = trackColor; - this.trackRouteColor = trackRouteColor; - this.blockState = blockState; - } - - public TileEvent(BlockBean blockBean) { - this.tileId = blockBean.getTileId(); - - this.showRoute = false; - this.blockBean = blockBean; - - this.incomingSide = Orientation.EAST; - this.backgroundColor = Tile.DEFAULT_BACKGROUND_COLOR; - this.trackColor = Tile.DEFAULT_TRACK_COLOR; - this.trackRouteColor = Tile.DEFAULT_ROUTE_TRACK_COLOR; - } - - public TileEvent(TileBean tileBean) { - this.tileId = tileBean.getId(); - - this.showRoute = false; - - this.tileBean = tileBean; - this.blockBean = tileBean.getBlockBean(); - - this.incomingSide = tileBean.getOrientation(); - this.backgroundColor = Tile.DEFAULT_BACKGROUND_COLOR; - this.trackColor = Tile.DEFAULT_TRACK_COLOR; - this.trackRouteColor = Tile.DEFAULT_ROUTE_TRACK_COLOR; - } - - public boolean isEventFor(Tile tile) { - return this.tileId.equals(tile.getId()); - } - - public String getTileId() { - return tileId; - } - - public boolean isShowRoute() { - return showRoute; - } - - public Orientation getIncomingSide() { - return incomingSide; - } - - public AccessoryValue getRouteState() { - return routeState; - } - - public Color getBackgroundColor() { - return backgroundColor; - } - - public Color getTrackColor() { - return trackColor; - } - - public Color getTrackRouteColor() { - return trackRouteColor; - } - - public BlockBean getBlockBean() { - return blockBean; - } - - public TileBean getTileBean() { - return tileBean; - } - - public BlockState getBlockState() { - return blockState; - } - -} diff --git a/src/main/java/jcs/ui/layout/events/TileEventListener.java b/src/main/java/jcs/ui/layout/events/TileEventListener.java deleted file mode 100644 index 94480bb3..00000000 --- a/src/main/java/jcs/ui/layout/events/TileEventListener.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2023 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout.events; - -public interface TileEventListener { - - String getId(); - - void onTileChange(TileEvent tileEvent); - -} diff --git a/src/main/java/jcs/ui/layout/tiles/TileCache.java b/src/main/java/jcs/ui/layout/tiles/TileCache.java index 825c3987..ade3c9c2 100644 --- a/src/main/java/jcs/ui/layout/tiles/TileCache.java +++ b/src/main/java/jcs/ui/layout/tiles/TileCache.java @@ -27,7 +27,6 @@ import jcs.entities.TileBean; import jcs.persistence.PersistenceFactory; import org.tinylog.Logger; -import jcs.commandStation.events.JCSActionEvent; import jcs.commandStation.events.SensorEventListener; import jcs.entities.AccessoryBean; import jcs.entities.SensorBean; @@ -41,6 +40,7 @@ import static jcs.entities.TileBean.TileType.STRAIGHT; import static jcs.entities.TileBean.TileType.STRAIGHT_DIR; import static jcs.entities.TileBean.TileType.SWITCH; +import jcs.commandStation.events.JCSActionEvent; /** * Factory object to create Tiles and cache pointMap diff --git a/src/main/java/jcs/ui/table/DispatcherTablePanel.java b/src/main/java/jcs/ui/table/DispatcherTablePanel.java index 93857a8c..b9624cff 100644 --- a/src/main/java/jcs/ui/table/DispatcherTablePanel.java +++ b/src/main/java/jcs/ui/table/DispatcherTablePanel.java @@ -25,8 +25,6 @@ import javax.swing.JLabel; import javax.swing.JTable; import javax.swing.SwingUtilities; -import javax.swing.UIManager; -import javax.swing.UnsupportedLookAndFeelException; import javax.swing.event.RowSorterEvent; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.TableRowSorter; @@ -47,14 +45,12 @@ public class DispatcherTablePanel extends javax.swing.JPanel implements AutoPilo * Creates new form LocomotiveTablePanel */ public DispatcherTablePanel() { - initComponents(); this.dispatcherTable.setDefaultRenderer(Image.class, new LocIconRenderer()); this.dispatcherTable.getRowSorter().addRowSorterListener((RowSorterEvent e) -> { //Logger.trace(e.getType() + "," + e.getSource().getSortKeys());// Sorting changed }); - initModel(); } @@ -67,7 +63,7 @@ private void initModel() { public void statusChanged(boolean running) { List dispatchers = AutoPilot.getLocomotiveDispatchers(); Logger.trace("Found " + dispatchers.size() + " Dispatchers. Automode: " + (running ? "on" : "off")); - this.locomotiveDispatcherTableModel.refresh(); + locomotiveDispatcherTableModel.refresh(); } private class LocIconRenderer extends DefaultTableCellRenderer { @@ -75,15 +71,16 @@ private class LocIconRenderer extends DefaultTableCellRenderer { @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); - - Image img = (Image) value; - int size = 40; - float aspect = (float) img.getHeight(null) / (float) img.getWidth(null); - img = img.getScaledInstance(size, (int) (size * aspect), Image.SCALE_SMOOTH); - BufferedImage bi = ImageUtil.toBuffered(img); - setIcon(new ImageIcon(bi)); - setHorizontalAlignment(JLabel.CENTER); - setText(""); + if (value != null) { + Image img = (Image) value; + int size = 40; + float aspect = (float) img.getHeight(null) / (float) img.getWidth(null); + img = img.getScaledInstance(size, (int) (size * aspect), Image.SCALE_SMOOTH); + BufferedImage bi = ImageUtil.toBuffered(img); + setIcon(new ImageIcon(bi)); + setHorizontalAlignment(JLabel.CENTER); + setText(""); + } return this; } } @@ -135,10 +132,10 @@ private void dispatcherTableMouseReleased(java.awt.event.MouseEvent evt) {//GEN- public void setVisible(boolean aFlag) { super.setVisible(aFlag); if (aFlag) { - AutoPilot.addAutoPilotStatusListener(this); + //AutoPilot.addAutoPilotStatusListener(this); statusChanged(AutoPilot.isAutoModeActive()); } else { - AutoPilot.removeAutoPilotStatusListener(this); + //AutoPilot.removeAutoPilotStatusListener(this); } } @@ -165,47 +162,4 @@ private void showDriverCabDialog(LocomotiveBean locomotiveBean) { private jcs.ui.table.model.LocomotiveDispatcherTableModel locomotiveDispatcherTableModel; // End of variables declaration//GEN-END:variables - public static void main(String args[]) { - - long now = System.currentTimeMillis(); - long maxtime = now + 5000L; - AutoPilot.startAutoMode(); - int dispcnt = AutoPilot.getLocomotiveDispatchers().size(); - while (dispcnt == 0 && now < maxtime) { - now = System.currentTimeMillis(); - dispcnt = AutoPilot.getLocomotiveDispatchers().size(); - } - - try { - String plaf = System.getProperty("jcs.plaf", "com.formdev.flatlaf.FlatLightLaf"); - if (plaf != null) { - UIManager.setLookAndFeel(plaf); - } else { - UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - } - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { - Logger.error(ex); - } - - java.awt.EventQueue.invokeLater(() -> { - - DispatcherTablePanel testPanel = new DispatcherTablePanel(); - JFrame testFrame = new JFrame("LocomotiveTablePanel Tester"); - - testFrame.add(testPanel); - - testFrame.addWindowListener(new java.awt.event.WindowAdapter() { - @Override - public void windowClosing(java.awt.event.WindowEvent e) { - System.exit(0); - } - }); - testFrame.pack(); - testFrame.setLocationRelativeTo(null); - - //testPanel.loadLocomotives(); - //testPanel.locomotiveDispatcherTableModel.refresh(); - testFrame.setVisible(true); - }); - } } diff --git a/src/main/java/jcs/ui/table/LocomotiveTablePanel.java b/src/main/java/jcs/ui/table/LocomotiveTablePanel.java index c9a3caf1..d4bf146d 100644 --- a/src/main/java/jcs/ui/table/LocomotiveTablePanel.java +++ b/src/main/java/jcs/ui/table/LocomotiveTablePanel.java @@ -52,9 +52,9 @@ public LocomotiveTablePanel() { initComponents(); - this.locomotiveTable.setDefaultRenderer(Image.class, new LocIconRenderer()); + locomotiveTable.setDefaultRenderer(Image.class, new LocIconRenderer()); - this.locomotiveTable.getRowSorter().addRowSorterListener((RowSorterEvent e) -> { + locomotiveTable.getRowSorter().addRowSorterListener((RowSorterEvent e) -> { //Logger.trace(e.getType() + "," + e.getSource().getSortKeys());// Sorting changed }); @@ -80,10 +80,14 @@ private void initModel() { @Override public void onChange(RefreshEvent event) { if ("locomotives".equals(event.getSource())) { - locomotiveBeanTableModel.refresh(); + refresh(); } } + public void refresh() { + locomotiveBeanTableModel.refresh(); + } + private class LocIconRenderer extends DefaultTableCellRenderer { @Override diff --git a/src/main/resources/media/arrowhead-right-gn.png b/src/main/resources/media/arrowhead-right-gn.png new file mode 100755 index 0000000000000000000000000000000000000000..b850cfba9f060322de851e4619018b8d7d28d53e GIT binary patch literal 456 zcmV;(0XP1MP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0bNN%K~zXf<&?im z!%!53&rK_|@*c6EvmIRuiX`b)-5p&V1P9$5b#rrd)7`~QH~)b`7fA<&E{+Z^;*h>Z zOrbxngDu!gLzCD^zwvx<5BI`*z@J1L?-E=q$UF;{3`QJl6Fn{l&bkz7i7Nnz)^bEm z9k?e_rGaFC?-TK4!u5U+`_Z!hI+@QVeuD{UE4M%`6}Y?7%pzd{K)@1NbgMe<^~zgK zNgqezf-%H&5EY`9Hf~kAX{0Uy00Nc4XlUb}gKK%|f0C&H06>%n=uDYz!w$T%)MK(2 zj37dFU~x+Y&Y^UeM*#p3qd*p|PCHk^cMuPQUkKO>ZT~?!{B{FozA1K#mAK)^x&Z@i z4EgAzSSw;H9(x0000gTe~ HDWM4fW+XUD literal 0 HcmV?d00001 diff --git a/src/main/resources/media/reset-happy.png b/src/main/resources/media/reset-happy.png new file mode 100755 index 0000000000000000000000000000000000000000..3ec82eea2cfe526b837478b500d2a92482036993 GIT binary patch literal 738 zcmV<80v-K{P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0(VJ7K~zXf-IXzD z6Hyq)f8VmC^`yO6gukQVCm4o#X+co zU`2<3(p-o`r8HC;+fp4$a(ACYbCH{JWc@BRPp-raWx|2h&E;xraB1!Kvi zKta)dUp7eDftmDh?L}-!gq{Igb}sFSPAe4Sb72%-if2lxk?K->4#30(fJP-#bi}Jf z%$03bEdw7Fb$nT16yttauV$|XwIR9!8kJ1ZGBPVj8bHzac-~klU+eP>7cG^sRDH0| zg>hhEXO$cjc<{B7y&kiR25i~6v@uNkV-1OMHD3P3Iak+w1aRUGX4o7av~-L zUY$EoNd(h>k|@?<)C7RRZu&ob1>UU9lGub*hH1v6!_@_cVQv&@S*7ky;j_XqL z&4~x3MygAS+ze}b!3b07vJ@h dispList = AutoPilot.getLocomotiveDispatchers(); assertEquals(1, dispList.size()); - assertFalse(AutoPilot.areDispatchersRunning()); + assertFalse(AutoPilot.isADispatcherRunning()); AutoPilot.stopAutoMode(); //let the autopilot finish... @@ -542,7 +542,7 @@ public void testStartAllLocomotives() { public void testStopAllLocomotives() { System.out.println("stopAllLocomotives"); AutoPilot instance = null; - AutoPilot.stopAllLocomotives(); + //AutoPilot.stopAllLocomotives(); fail("The test case is a prototype."); } diff --git a/src/test/java/jcs/commandStation/autopilot/state/StateMachineStepByStepTest.java b/src/test/java/jcs/commandStation/autopilot/state/StateMachineStepByStepTest.java index 1aa92a52..bde9a609 100644 --- a/src/test/java/jcs/commandStation/autopilot/state/StateMachineStepByStepTest.java +++ b/src/test/java/jcs/commandStation/autopilot/state/StateMachineStepByStepTest.java @@ -77,14 +77,14 @@ public void setUp() { ps.persist(route); } JCS.getJcsCommandStation().switchPower(true); - AutoPilot.startAutoMode(); + AutoPilot.runAutoPilot(true); Logger.info("=========================== setUp done.............."); } @AfterEach public void tearDown() { Logger.info("=========================== Teardown.............."); - AutoPilot.stopAutoMode(); + AutoPilot.runAutoPilot(false); long now = System.currentTimeMillis(); long start = now; long timeout = now + 10000; @@ -201,7 +201,7 @@ public void testBk1ToBk4() { BlockBean block4 = ps.getBlockByTileId("bk-4"); assertEquals(BlockBean.BlockState.FREE, block4.getBlockState()); - StateMachineThread stateMachine = dispatcher.getStateMachineThread(); + StateMachine stateMachine = dispatcher.getStateMachine(); //Start from bk-1 assertEquals(NS_DHG_6505, block1.getLocomotiveId()); @@ -211,7 +211,7 @@ public void testBk1ToBk4() { //Thread should NOT run! assertFalse(stateMachine.isThreadRunning()); - assertFalse(stateMachine.isEnableAutomode()); + assertFalse(stateMachine.isAutomodeEnabled()); assertEquals("IdleState", stateMachine.getDispatcherStateName()); //Execute IdleState @@ -222,7 +222,7 @@ public void testBk1ToBk4() { //Departure //Automode should be enabled stateMachine.setEnableAutomode(true); - assertTrue(stateMachine.isEnableAutomode()); + assertTrue(stateMachine.isAutomodeEnabled()); //Execute IdleState again stateMachine.handleState(); @@ -385,7 +385,7 @@ public void testFromBk1ToBk4andViceVersa() { block4.setMinWaitTime(3); ps.persist(block4); - StateMachineThread stateMachine = dispatcher.getStateMachineThread(); + StateMachine stateMachine = dispatcher.getStateMachine(); //Start from bk-1 assertEquals(NS_DHG_6505, block1.getLocomotiveId()); @@ -395,7 +395,7 @@ public void testFromBk1ToBk4andViceVersa() { //Thread should NOT run! assertFalse(stateMachine.isThreadRunning()); - assertFalse(stateMachine.isEnableAutomode()); + assertFalse(stateMachine.isAutomodeEnabled()); assertEquals("IdleState", stateMachine.getDispatcherStateName()); //Execute IdleState @@ -406,7 +406,7 @@ public void testFromBk1ToBk4andViceVersa() { //Departure //Automode should be enabled stateMachine.setEnableAutomode(true); - assertTrue(stateMachine.isEnableAutomode()); + assertTrue(stateMachine.isAutomodeEnabled()); //Execute IdleState again stateMachine.handleState(); @@ -695,7 +695,7 @@ public void testFromBk1ToBk4andViceVersa() { //Automode OFF! stateMachine.setEnableAutomode(false); - assertFalse(stateMachine.isEnableAutomode()); + assertFalse(stateMachine.isAutomodeEnabled()); //Execute the WaitState stateMachine.handleState(); @@ -722,7 +722,7 @@ public void testFromBk1ToBk4Gost() { BlockBean block4 = ps.getBlockByTileId("bk-4"); assertEquals(BlockBean.BlockState.FREE, block4.getBlockState()); - StateMachineThread stateMachine = dispatcher.getStateMachineThread(); + StateMachine stateMachine = dispatcher.getStateMachine(); //Start from bk-1 assertEquals(NS_DHG_6505, block1.getLocomotiveId()); @@ -732,7 +732,7 @@ public void testFromBk1ToBk4Gost() { //Thread should NOT run! assertFalse(stateMachine.isThreadRunning()); - assertFalse(stateMachine.isEnableAutomode()); + assertFalse(stateMachine.isAutomodeEnabled()); assertEquals("IdleState", stateMachine.getDispatcherStateName()); //Execute IdleState @@ -743,7 +743,7 @@ public void testFromBk1ToBk4Gost() { //Departure //Automode should be enabled stateMachine.setEnableAutomode(true); - assertTrue(stateMachine.isEnableAutomode()); + assertTrue(stateMachine.isAutomodeEnabled()); //Execute IdleState again stateMachine.handleState(); @@ -839,7 +839,7 @@ public void testReset() { BlockBean block4 = ps.getBlockByTileId("bk-4"); assertEquals(BlockBean.BlockState.OUT_OF_ORDER, block4.getBlockState()); - StateMachineThread instance = dispatcher.getStateMachineThread(); + StateMachine instance = dispatcher.getStateMachine(); //Start from bk-2 assertEquals(NS_1631, block2.getLocomotiveId()); @@ -849,7 +849,7 @@ public void testReset() { assertNull(dispatcher.getRouteBean()); assertFalse(instance.isThreadRunning()); - assertFalse(instance.isEnableAutomode()); + assertFalse(instance.isAutomodeEnabled()); assertEquals("IdleState", instance.getDispatcherStateName()); //Execute IdleState @@ -872,7 +872,7 @@ public void testReset() { //Automode ON! instance.setEnableAutomode(true); - assertTrue(instance.isEnableAutomode()); + assertTrue(instance.isAutomodeEnabled()); assertFalse(instance.isThreadRunning()); block1 = ps.getBlockByTileId("bk-1"); @@ -965,7 +965,7 @@ public void testReset() { assertNull(dispatcher.getRouteBean()); assertNull(dispatcher.getDestinationBlock()); - assertFalse(instance.isEnableAutomode()); + assertFalse(instance.isAutomodeEnabled()); block1 = ps.getBlockByTileId("bk-1"); assertEquals(BlockBean.BlockState.OUT_OF_ORDER, block1.getBlockState()); diff --git a/src/test/java/jcs/commandStation/autopilot/state/StateMachineThreadTest.java b/src/test/java/jcs/commandStation/autopilot/state/StateMachineThreadTest.java index 6892971f..84859fdb 100644 --- a/src/test/java/jcs/commandStation/autopilot/state/StateMachineThreadTest.java +++ b/src/test/java/jcs/commandStation/autopilot/state/StateMachineThreadTest.java @@ -36,7 +36,6 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.BeforeAll; import org.tinylog.Logger; @@ -109,7 +108,7 @@ public void setUp() { Logger.trace("Power on in " + (now - start) + "ms."); - AutoPilot.startAutoMode(); + AutoPilot.runAutoPilot(true); Logger.info("=========================== setUp done.............."); } @@ -117,7 +116,7 @@ public void setUp() { @AfterEach public void tearDown() { Logger.info("=========================== Teardown.............."); - AutoPilot.stopAutoMode(); + AutoPilot.runAutoPilot(false); long now = System.currentTimeMillis(); long start = now; long timeout = now + 10000; @@ -270,7 +269,7 @@ public void testBk1ToBk4() { assertTrue(AutoPilot.isOnTrack(dhg)); assertTrue(AutoPilot.isAutoModeActive()); - AutoPilot.startAutoMode(); + AutoPilot.runAutoPilot(true); long now = System.currentTimeMillis(); long timeout = now + 10000; @@ -578,7 +577,7 @@ public void testStartStopLocomotiveAutomode() { long now = System.currentTimeMillis(); long timeout = now + 10000; //Start Automode - AutoPilot.startAutoMode(); + AutoPilot.runAutoPilot(true); boolean autoPilotRunning = AutoPilot.isAutoModeActive(); while (!autoPilotRunning && timeout > now) { @@ -846,7 +845,7 @@ public void testStartStopThreadRunning() { BlockBean block3 = PersistenceFactory.getService().getBlockByTileId("bk-3"); assertEquals(BlockBean.BlockState.OUT_OF_ORDER, block3.getBlockState()); - StateMachineThread instance = dispatcher.getStateMachineThread(); + StateMachine instance = dispatcher.getStateMachine(); assertFalse(instance.isThreadRunning()); assertFalse(instance.isAlive()); @@ -865,7 +864,7 @@ public void testStartStopThreadRunning() { Logger.debug("Dispatcher Thread Started"); assertTrue(instance.isThreadRunning()); assertTrue(instance.isAlive()); - assertFalse(instance.isEnableAutomode()); + assertFalse(instance.isAutomodeEnabled()); instance.stopRunningThread(); Logger.debug("Dispatcher Thread Stopped"); @@ -906,7 +905,7 @@ public static void beforeAll() { @AfterAll public static void assertOutput() { - AutoPilot.stopAutoMode(); + AutoPilot.runAutoPilot(false); long now = System.currentTimeMillis(); long start = now; From dd93284b787d8d2de45e5684c4688c7d7f0e0acd Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Wed, 19 Feb 2025 21:27:20 +0100 Subject: [PATCH 24/70] GUI minor changes --- src/main/java/jcs/ui/JCSFrame.form | 37 +++- src/main/java/jcs/ui/JCSFrame.java | 23 ++- src/main/java/jcs/ui/layout/LayoutCanvas.form | 6 +- src/main/java/jcs/ui/layout/LayoutCanvas.java | 174 ++++++++++-------- src/main/java/jcs/ui/layout/LayoutPanel.form | 24 +-- src/main/java/jcs/ui/layout/LayoutPanel.java | 20 +- .../java/jcs/ui/layout/tiles/TileCache.java | 25 ++- src/main/resources/tinylog-dev.properties | 2 +- 8 files changed, 193 insertions(+), 118 deletions(-) diff --git a/src/main/java/jcs/ui/JCSFrame.form b/src/main/java/jcs/ui/JCSFrame.form index 6ab04d2b..9c5ed621 100755 --- a/src/main/java/jcs/ui/JCSFrame.form +++ b/src/main/java/jcs/ui/JCSFrame.form @@ -798,7 +798,13 @@
+ + + + + + @@ -809,11 +815,11 @@ - + - + @@ -826,7 +832,7 @@ - + @@ -846,11 +852,11 @@ - + - + @@ -864,9 +870,12 @@ - + + + + @@ -895,7 +904,13 @@ + + + + + + @@ -998,7 +1013,13 @@ + + + + + + @@ -1011,11 +1032,11 @@ - + - + diff --git a/src/main/java/jcs/ui/JCSFrame.java b/src/main/java/jcs/ui/JCSFrame.java index bb8db46f..b75af53d 100755 --- a/src/main/java/jcs/ui/JCSFrame.java +++ b/src/main/java/jcs/ui/JCSFrame.java @@ -583,26 +583,29 @@ public void actionPerformed(ActionEvent evt) { getContentPane().add(toolbarPanel, BorderLayout.NORTH); + statusPanel.setMinimumSize(new Dimension(1227, 45)); statusPanel.setName("statusPanel"); // NOI18N + statusPanel.setPreferredSize(new Dimension(1227, 48)); getContentPane().add(statusPanel, BorderLayout.SOUTH); - mainPanel.setMinimumSize(new Dimension(1050, 900)); + mainPanel.setMinimumSize(new Dimension(1232, 770)); mainPanel.setName("mainPanel"); // NOI18N - mainPanel.setPreferredSize(new Dimension(1315, 850)); + mainPanel.setPreferredSize(new Dimension(1232, 770)); mainPanel.setLayout(new BorderLayout()); - locoDisplaySP.setDividerLocation(300); + locoDisplaySP.setDividerLocation(302); locoDisplaySP.setMinimumSize(new Dimension(1050, 900)); locoDisplaySP.setName("locoDisplaySP"); // NOI18N locoDisplaySP.setPreferredSize(new Dimension(1050, 850)); - centerPanel.setMinimumSize(new Dimension(1000, 900)); + centerPanel.setMinimumSize(new Dimension(1002, 772)); centerPanel.setName("centerPanel"); // NOI18N - centerPanel.setPreferredSize(new Dimension(1010, 900)); + centerPanel.setPreferredSize(new Dimension(1002, 772)); centerPanel.setLayout(new CardLayout()); - keyboardSensorMessagePanel.setMinimumSize(new Dimension(885, 840)); + keyboardSensorMessagePanel.setMinimumSize(new Dimension(1002, 772)); keyboardSensorMessagePanel.setName("keyboardSensorMessagePanel"); // NOI18N + keyboardSensorMessagePanel.setPreferredSize(new Dimension(1002, 772)); centerPanel.add(keyboardSensorMessagePanel, "diagnosticPanel"); layoutPanel.setMinimumSize(new Dimension(885, 160)); @@ -610,7 +613,9 @@ public void actionPerformed(ActionEvent evt) { centerPanel.add(layoutPanel, "designPanel"); layoutPanel.getAccessibleContext().setAccessibleName("designPanel"); + overviewPanel.setMinimumSize(new Dimension(1002, 772)); overviewPanel.setName("overviewPanel"); // NOI18N + overviewPanel.setPreferredSize(new Dimension(1002, 772)); centerPanel.add(overviewPanel, "overviewPanel"); overviewPanel.getAccessibleContext().setAccessibleName("overviewPanel"); @@ -624,14 +629,16 @@ public void actionPerformed(ActionEvent evt) { centerPanel.add(settingsPanel, "settingsPanel"); + vncPanel.setMinimumSize(new Dimension(1002, 772)); vncPanel.setName("vncPanel"); // NOI18N + vncPanel.setPreferredSize(new Dimension(1002, 772)); centerPanel.add(vncPanel, "vncPanel"); locoDisplaySP.setRightComponent(centerPanel); - leftPanel.setMinimumSize(new Dimension(220, 850)); + leftPanel.setMinimumSize(new Dimension(225, 772)); leftPanel.setName("leftPanel"); // NOI18N - leftPanel.setPreferredSize(new Dimension(225, 845)); + leftPanel.setPreferredSize(new Dimension(225, 772)); leftPanel.setLayout(new BorderLayout(1, 1)); bottomLeftPanel.setBorder(BorderFactory.createTitledBorder("Controller Properties")); diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.form b/src/main/java/jcs/ui/layout/LayoutCanvas.form index 884eba14..0253ad8b 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.form +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.form @@ -197,10 +197,10 @@ - + - + @@ -224,7 +224,7 @@ - + diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.java b/src/main/java/jcs/ui/layout/LayoutCanvas.java index 34b3ad87..a1914b97 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.java +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.java @@ -85,38 +85,38 @@ public enum Mode { DELETE, CONTROL } - + static final int LINE_GRID = 0; static final int DOT_GRID = 1; - + private int gridType = LINE_GRID; - + private boolean readonly; private Mode mode; private boolean drawGrid = true; - + private Orientation orientation; private Direction direction; private TileType tileType; - + private Point mouseLocation = new Point(); - + private final ExecutorService executor; - + private Tile selectedTile; - + private RoutesDialog routesDialog; - + public LayoutCanvas() { this(false); } - + public LayoutCanvas(boolean readonly) { super(); setLayout(null); setOpaque(true); setDoubleBuffered(true); - + this.readonly = readonly; this.executor = Executors.newSingleThreadExecutor(); //this.executor = Executors.newCachedThreadPool(); @@ -124,24 +124,24 @@ public LayoutCanvas(boolean readonly) { this.mode = Mode.SELECT; this.orientation = Orientation.EAST; this.direction = Direction.CENTER; - + initComponents(); postInit(); } - + private void postInit() { routesDialog = new RoutesDialog(getParentFrame(), false, this, this.readonly); } - + public boolean isReadonly() { return readonly; } - + @Override public void paint(Graphics g) { //long started = System.currentTimeMillis(); super.paint(g); - + if (drawGrid) { if (this.gridType == LINE_GRID) { paintLineGrid(g); @@ -153,7 +153,7 @@ public void paint(Graphics g) { //long now = System.currentTimeMillis(); //Logger.trace("Duration: " + (now - started) + " ms."); } - + @Override public Component add(Component component) { super.add(component); @@ -162,7 +162,7 @@ public Component add(Component component) { } return component; } - + @Override public Component add(String name, Component component) { if (component instanceof Tile tile) { @@ -173,14 +173,14 @@ public Component add(String name, Component component) { } return component; } - + private void paintDotGrid(Graphics g) { int width = getWidth(); int height = getHeight(); Graphics2D gc = (Graphics2D) g; Paint p = gc.getPaint(); gc.setPaint(Color.black); - + int xOffset = 0; int yOffset = 0; for (int r = 0; r < width; r++) { @@ -190,7 +190,7 @@ private void paintDotGrid(Graphics g) { } gc.setPaint(p); } - + private void paintLineGrid(Graphics g) { int width = getWidth(); int height = getHeight(); @@ -198,7 +198,7 @@ private void paintLineGrid(Graphics g) { Paint p = gc.getPaint(); gc.setPaint(Color.black); gc.setPaint(Color.lightGray); - + gc.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); for (int x = 0; x < width; x += 40) { gc.drawLine(x, 0, x, height); @@ -208,12 +208,12 @@ private void paintLineGrid(Graphics g) { } gc.setPaint(p); } - + void setMode(LayoutCanvas.Mode mode) { this.mode = mode; Logger.trace("Mode: " + mode); } - + void setDrawGrid(boolean flag) { if (flag) { switch (gridType) { @@ -228,16 +228,16 @@ void setDrawGrid(boolean flag) { drawGrid = flag; repaint(); } - + void setTileType(TileBean.TileType tileType) { this.tileType = tileType; Logger.trace("TileType: " + tileType + " Current mode: " + mode); } - + void setDirection(Direction direction) { this.direction = direction; } - + void loadLayoutInBackground() { this.executor.execute(() -> loadTiles()); @@ -252,13 +252,35 @@ void loadLayoutInBackground() { // } // }).start(); } - + private void loadTiles() { List tiles = TileCache.loadTiles(readonly); - + removeAll(); selectedTile = null; - + + Dimension minSize = TileCache.getMinCanvasSize(); + setMinimumSize(minSize); + + //Check if we must enlarge the canvas + int w = getPreferredSize().width; + int h = getPreferredSize().height; + boolean changeSize = false; + if (w < minSize.width) { + w = minSize.width; + changeSize = true; + } + if (h < minSize.height) { + h = minSize.height; + changeSize = true; + } + + if (changeSize) { + setPreferredSize(new Dimension(w, h)); + setSize(new Dimension(w, h)); + Logger.trace("Changed size to w: " + w + " h: " + h); + } + for (Tile tile : tiles) { add(tile); boolean showCenter = "true".equalsIgnoreCase(System.getProperty("tile.show.center", "false")); @@ -267,7 +289,7 @@ private void loadTiles() { } } } - + private void mouseMoveAction(MouseEvent evt) { Point sp = LayoutUtil.snapToGrid(evt.getPoint()); if (selectedTile != null) { @@ -276,7 +298,7 @@ private void mouseMoveAction(MouseEvent evt) { setCursor(Cursor.getDefaultCursor()); } } - + private void mousePressedAction(MouseEvent evt) { Logger.trace("@ (" + evt.getX() + "," + evt.getY() + ")"); Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); @@ -287,13 +309,13 @@ private void mousePressedAction(MouseEvent evt) { if (selectedTile != null && CONTROL != mode) { selectedTile.setSelected(true); } - + if (previousSelected != null && selectedTile != null && previousSelected.getId().equals(selectedTile.getId())) { Logger.trace("Same tile " + selectedTile.getId() + " selected"); } else if (previousSelected != null) { previousSelected.setSelected(false); } - + switch (mode) { case CONTROL -> { if (selectedTile != null) { @@ -344,11 +366,11 @@ private void mousePressedAction(MouseEvent evt) { } } } - + private Tile addTile(Point p, TileType tileType, Orientation orientation, Direction direction, boolean selected, boolean showCenter) { Logger.trace("Adding: " + tileType + " @ " + p + " O: " + orientation + " D: " + direction); Tile tile = TileCache.createTile(tileType, orientation, direction, p); - + if (TileCache.canMoveTo(tile, p)) { tile.setSelected(selected); tile.setDrawCenterPoint(showCenter); @@ -362,7 +384,7 @@ private Tile addTile(Point p, TileType tileType, Orientation orientation, Direct return null; } } - + void removeTile(Tile tile) { Tile toBeDeleted = (Tile) getComponentAt(tile.getCenter()); if (toBeDeleted != null) { @@ -371,7 +393,7 @@ void removeTile(Tile tile) { TileCache.deleteTile(tile); } } - + private void mouseDragAction(MouseEvent evt) { //Logger.trace("@ (" + evt.getX() + "," + evt.getY() + ")"); Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); @@ -379,13 +401,13 @@ private void mouseDragAction(MouseEvent evt) { int z = getComponentZOrder(selectedTile); setComponentZOrder(selectedTile, 0); Logger.trace("Moving: " + selectedTile.getId() + " @ " + selectedTile.xyToString() + " P: " + snapPoint.x + "," + snapPoint.y + ")"); - + if (TileCache.canMoveTo(selectedTile, snapPoint)) { selectedTile.setSelectedColor(Tile.DEFAULT_SELECTED_COLOR); } else { selectedTile.setSelectedColor(Tile.DEFAULT_WARN_COLOR); } - + int curX, curY; switch (selectedTile.getTileType()) { case BLOCK -> { @@ -426,7 +448,7 @@ private void mouseDragAction(MouseEvent evt) { selectedTile.setBounds(curX, curY, selectedTile.getWidth(), selectedTile.getHeight()); } } - + private void mouseReleasedAction(MouseEvent evt) { Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); if (!Mode.CONTROL.equals(mode) && MouseEvent.BUTTON1 == evt.getButton() && selectedTile != null) { @@ -438,7 +460,7 @@ private void mouseReleasedAction(MouseEvent evt) { } } } - + private void executeControlActionForTile(Tile tile, Point p) { TileBean.TileType tt = tile.getTileType(); switch (tt) { @@ -455,7 +477,7 @@ private void executeControlActionForTile(Tile tile, Point p) { Block block = (Block) tile; BlockControlDialog bcd = new BlockControlDialog(getParentFrame(), block); bcd.setVisible(true); - + Logger.trace("Block properties closed"); this.repaint(block.getTileBounds()); } @@ -472,7 +494,7 @@ private void executeControlActionForTile(Tile tile, Point p) { } } } - + private void editSelectedTileProperties() { //the first tile should be the selected one boolean showProperties = false; @@ -480,11 +502,11 @@ private void editSelectedTileProperties() { boolean showRotate = false; boolean showMove = false; boolean showDelete = false; - + if (selectedTile != null) { TileBean.TileType tt = selectedTile.getTileType(); Logger.trace("Selected tile " + selectedTile.getId() + " TileType " + tt); - + switch (tt) { case END -> { showRotate = true; @@ -529,7 +551,7 @@ private void editSelectedTileProperties() { repaint(); } } - + private void showBlockPopupMenu(Tile tile, Point p) { if (tile == null || p == null) { return; @@ -545,18 +567,18 @@ private void showBlockPopupMenu(Tile tile, Point p) { this.toggleLocomotiveDirectionMI.setEnabled(hasLoco); this.reverseArrivalSideMI.setEnabled(hasLoco); this.resetGhostMI.setEnabled(isGhost); - + this.toggleOutOfOrderMI.setEnabled(!hasLoco); - + if (BlockBean.BlockState.OUT_OF_ORDER == ((Block) tile).getBlockState()) { this.toggleOutOfOrderMI.setText("Enable Block"); } else { this.toggleOutOfOrderMI.setText("Set Out of Order"); } - + this.blockPopupMenu.show(this, p.x, p.y); } - + private void showOperationsPopupMenu(Tile tile, Point p) { if (tile == null || p == null) { return; @@ -570,7 +592,7 @@ private void showOperationsPopupMenu(Tile tile, Point p) { boolean showMove = false; @SuppressWarnings("UnusedAssignment") boolean showDelete = false; - + TileType tt = tile.getTileType(); switch (tt) { case SENSOR -> { @@ -606,16 +628,16 @@ private void showOperationsPopupMenu(Tile tile, Point p) { } } this.xyMI.setVisible(true); - + String extra = ""; if (tile instanceof Sensor s) { if (s.getSensorBean() != null) { extra = " " + s.getSensorBean().getName(); } } - + this.xyMI.setText(tile.getId() + extra + " (" + p.x + "," + p.y + ") O: " + tile.getOrientation().getOrientation() + " D: " + tile.getDirection()); - + this.propertiesMI.setVisible(showProperties); this.flipHorizontalMI.setVisible(showFlip); this.flipVerticalMI.setVisible(showFlip); @@ -624,36 +646,36 @@ private void showOperationsPopupMenu(Tile tile, Point p) { this.deleteMI.setVisible(showDelete); this.operationsPM.show(this, p.x, p.y); } - + private JFrame getParentFrame() { JFrame frame = (JFrame) SwingUtilities.getRoot(this); return frame; } - + public void rotateSelectedTile() { Logger.trace("Selected Tile " + selectedTile.getId()); selectedTile = TileCache.rotateTile(selectedTile); selectedTile.setBounds(selectedTile.getTileBounds()); } - + public void flipSelectedTileHorizontal() { selectedTile = TileCache.flipHorizontal(selectedTile); selectedTile.setBounds(selectedTile.getTileBounds()); } - + public void flipSelectedTileVertical() { selectedTile = TileCache.flipVertical(selectedTile); selectedTile.setBounds(selectedTile.getTileBounds()); } - + void routeLayout() { this.executor.execute(() -> routeLayoutWithAStar()); } - + private void routeLayoutWithAStar() { //Make sure the layout is saved TileCache.persistAllTiles(); - + AStar astar = new AStar(); astar.buildGraph(TileCache.getTiles()); astar.routeAll(); @@ -662,7 +684,7 @@ private void routeLayoutWithAStar() { routesDialog.loadRoutes(); } } - + void showRoutesDialog() { routesDialog.setVisible(true); } @@ -856,8 +878,8 @@ public void actionPerformed(ActionEvent evt) { blockPopupMenu.add(blockPropertiesMI); setBackground(new Color(255, 255, 255)); - setMinimumSize(new Dimension(1398, 848)); - setPreferredSize(new Dimension(1398, 848)); + setMinimumSize(new Dimension(1000, 760)); + setPreferredSize(new Dimension(1000, 760)); addMouseMotionListener(new MouseMotionAdapter() { public void mouseDragged(MouseEvent evt) { formMouseDragged(evt); @@ -888,7 +910,7 @@ private void formMouseReleased(MouseEvent evt) {//GEN-FIRST:event_formMouseRelea private void horizontalMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_horizontalMIActionPerformed Logger.trace(this.orientation + ", " + evt.getModifiers() + ", " + evt.paramString()); - + if (this.mouseLocation != null && evt.getModifiers() == ActionEvent.MOUSE_EVENT_MASK) { this.mouseLocation = null; } @@ -896,7 +918,7 @@ private void horizontalMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_hor private void verticalMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_verticalMIActionPerformed Logger.trace(this.orientation + ", " + evt.getModifiers() + ", " + evt.paramString()); - + if (this.mouseLocation != null && evt.getModifiers() == ActionEvent.MOUSE_EVENT_MASK) { this.mouseLocation = null; } @@ -904,7 +926,7 @@ private void verticalMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_verti private void rightMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_rightMIActionPerformed Logger.trace(this.orientation + ", " + evt.getModifiers() + ", " + evt.paramString()); - + if (this.mouseLocation != null && evt.getModifiers() == ActionEvent.MOUSE_EVENT_MASK) { this.mouseLocation = null; } @@ -912,7 +934,7 @@ private void rightMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_rightMIA private void leftMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_leftMIActionPerformed Logger.trace(this.orientation + ", " + evt.getModifiers() + ", " + evt.paramString()); - + if (this.mouseLocation != null && evt.getModifiers() == ActionEvent.MOUSE_EVENT_MASK) { this.mouseLocation = null; } @@ -974,7 +996,7 @@ private void resetDispatcherMIActionPerformed(ActionEvent evt) {//GEN-FIRST:even if (this.selectedTile != null) { Block block = (Block) selectedTile; LocomotiveBean locomotive = block.getBlockBean().getLocomotive(); - + this.executor.execute(() -> { AutoPilot.resetDispatcher(locomotive); repaint(); @@ -984,7 +1006,7 @@ private void resetDispatcherMIActionPerformed(ActionEvent evt) {//GEN-FIRST:even private void removeLocMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_removeLocMIActionPerformed if (selectedTile != null && selectedTile.isBlock()) { - LocomotiveBean locomotive = selectedTile.getLocomotive(); + LocomotiveBean locomotive = selectedTile.getLocomotive(); locomotive.setDispatcherDirection(null); selectedTile.setLocomotive(null); @@ -1011,7 +1033,7 @@ private void blockPropertiesMIActionPerformed(ActionEvent evt) {//GEN-FIRST:even private void reverseArrivalSideMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_reverseArrivalSideMIActionPerformed if (this.selectedTile != null) { Block block = (Block) selectedTile; - + String suffix = block.getArrivalSuffix(); if ("+".equals(suffix)) { block.setArrivalSuffix("-"); @@ -1029,7 +1051,7 @@ private void toggleLocomotiveDirectionMIActionPerformed(ActionEvent evt) {//GEN- if (selectedTile != null) { Block block = (Block) selectedTile; LocomotiveBean locomotive = block.getLocomotive(); - + LocomotiveBean.Direction curDir; if (block.getLogicalDirection() != null) { curDir = block.getLogicalDirection(); @@ -1039,7 +1061,7 @@ private void toggleLocomotiveDirectionMIActionPerformed(ActionEvent evt) {//GEN- LocomotiveBean.Direction newDir = LocomotiveBean.toggle(curDir); block.setLogicalDirection(newDir); Logger.trace(block.getId() + " LogicalDir changed from " + curDir + " to " + newDir + " for " + locomotive.getName()); - + this.executor.execute(() -> { PersistenceFactory.getService().persist(block.getTileBean()); }); @@ -1055,7 +1077,7 @@ private void toggleOutOfOrderMIActionPerformed(ActionEvent evt) {//GEN-FIRST:eve } else if (BlockState.OUT_OF_ORDER == currentState) { block.setBlockState(BlockState.FREE); } - + if (currentState != block.getBlockState()) { this.executor.execute(() -> { PersistenceFactory.getService().persist(block.getBlockBean()); @@ -1068,7 +1090,7 @@ private void resetGhostMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_res if (this.selectedTile != null) { Block block = (Block) selectedTile; BlockBean.BlockState currentState = block.getBlockState(); - + if (BlockBean.BlockState.GHOST == currentState) { if (block.getLocomotive() != null) { block.setBlockState(BlockBean.BlockState.OCCUPIED); diff --git a/src/main/java/jcs/ui/layout/LayoutPanel.form b/src/main/java/jcs/ui/layout/LayoutPanel.form index 1942d961..8f2962af 100755 --- a/src/main/java/jcs/ui/layout/LayoutPanel.form +++ b/src/main/java/jcs/ui/layout/LayoutPanel.form @@ -116,11 +116,11 @@ - + - + @@ -138,7 +138,7 @@ - + @@ -149,10 +149,10 @@ - + - + @@ -171,7 +171,7 @@ - + @@ -917,17 +917,19 @@ - - + - + + + + @@ -939,11 +941,11 @@ - + - + diff --git a/src/main/java/jcs/ui/layout/LayoutPanel.java b/src/main/java/jcs/ui/layout/LayoutPanel.java index 9917b52c..932cbcfd 100755 --- a/src/main/java/jcs/ui/layout/LayoutPanel.java +++ b/src/main/java/jcs/ui/layout/LayoutPanel.java @@ -312,9 +312,9 @@ public void actionPerformed(ActionEvent evt) { }); operationsPM.add(deleteMI); - setMinimumSize(new Dimension(1400, 900)); + setMinimumSize(new Dimension(1002, 772)); setOpaque(false); - setPreferredSize(new Dimension(1400, 900)); + setPreferredSize(new Dimension(1002, 772)); addComponentListener(new ComponentAdapter() { public void componentHidden(ComponentEvent evt) { formComponentHidden(evt); @@ -329,8 +329,8 @@ public void componentShown(ComponentEvent evt) { setLayout(new BorderLayout()); topPanel.setMaximumSize(new Dimension(32767, 50)); - topPanel.setMinimumSize(new Dimension(1400, 50)); - topPanel.setPreferredSize(new Dimension(1400, 50)); + topPanel.setMinimumSize(new Dimension(1000, 50)); + topPanel.setPreferredSize(new Dimension(1000, 50)); FlowLayout flowLayout1 = new FlowLayout(FlowLayout.LEFT); flowLayout1.setAlignOnBaseline(true); topPanel.setLayout(flowLayout1); @@ -338,7 +338,7 @@ public void componentShown(ComponentEvent evt) { toolBar.setMaximumSize(new Dimension(1200, 42)); toolBar.setMinimumSize(new Dimension(1150, 42)); toolBar.setName(""); // NOI18N - toolBar.setPreferredSize(new Dimension(1000, 42)); + toolBar.setPreferredSize(new Dimension(980, 42)); loadBtn.setIcon(new ImageIcon(getClass().getResource("/media/load-24.png"))); // NOI18N loadBtn.setToolTipText("Load"); @@ -716,17 +716,17 @@ public void actionPerformed(ActionEvent evt) { add(topPanel, BorderLayout.NORTH); - canvasScrollPane.setDoubleBuffered(true); - canvasScrollPane.setMinimumSize(new Dimension(1024, 850)); - canvasScrollPane.setPreferredSize(new Dimension(1024, 850)); + canvasScrollPane.setMinimumSize(new Dimension(1000, 740)); + canvasScrollPane.setPreferredSize(new Dimension(980, 700)); canvasScrollPane.setViewportView(canvas); - canvas.setMinimumSize(new Dimension(800, 700)); + canvas.setMinimumSize(new Dimension(1000, 720)); canvas.setName(""); // NOI18N - canvas.setPreferredSize(new Dimension(800, 700)); + canvas.setPreferredSize(new Dimension(1000, 720)); canvasScrollPane.setViewportView(canvas); add(canvasScrollPane, BorderLayout.CENTER); + canvasScrollPane.getAccessibleContext().setAccessibleDescription(""); }// //GEN-END:initComponents private void horizontalMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_horizontalMIActionPerformed diff --git a/src/main/java/jcs/ui/layout/tiles/TileCache.java b/src/main/java/jcs/ui/layout/tiles/TileCache.java index ade3c9c2..3b8dd766 100644 --- a/src/main/java/jcs/ui/layout/tiles/TileCache.java +++ b/src/main/java/jcs/ui/layout/tiles/TileCache.java @@ -15,6 +15,7 @@ */ package jcs.ui.layout.tiles; +import java.awt.Dimension; import java.awt.Point; import java.util.HashMap; import java.util.List; @@ -41,6 +42,7 @@ import static jcs.entities.TileBean.TileType.STRAIGHT_DIR; import static jcs.entities.TileBean.TileType.SWITCH; import jcs.commandStation.events.JCSActionEvent; +import static jcs.ui.layout.tiles.Tile.GRID; /** * Factory object to create Tiles and cache pointMap @@ -68,6 +70,9 @@ public class TileCache { private static final ConcurrentLinkedQueue eventsQueue = new ConcurrentLinkedQueue(); private static final TileActionEventHandler actionEventQueueHandler = new TileActionEventHandler(eventsQueue); + private static int maxX; + private static int maxY; + static { actionEventQueueHandler.start(); } @@ -320,11 +325,14 @@ public static List loadTiles(boolean showvalues) { altPointMap.clear(); pointMap.clear(); idMap.clear(); + maxX = 0; + maxY = 0; List tileBeans = PersistenceFactory.getService().getTileBeans(); for (TileBean tb : tileBeans) { Tile tile = createTile(tb, showvalues); + calculateMaxCoordinates(tile.tileX, tile.tileY); idMap.put(tile.id, tile); pointMap.put(tile.getCenter(), tile); //Alternative point(s) to be able to find all pointIds @@ -336,7 +344,7 @@ public static List loadTiles(boolean showvalues) { } } - Logger.trace("Loaded " + idMap.size() + " Tiles..."); + Logger.trace("Loaded " + idMap.size() + " Tiles. Max: (" + maxX + "," + maxY + ")"); return idMap.values().stream().collect(Collectors.toList()); } @@ -344,6 +352,21 @@ public static List getTiles() { return idMap.values().stream().collect(Collectors.toList()); } + static void calculateMaxCoordinates(int tileX, int tileY) { + if (maxX < tileX) { + maxX = tileX; + } + if (maxY < tileY) { + maxY = tileY; + } + } + + public static Dimension getMinCanvasSize() { + int w = maxX + GRID; + int h = maxY + GRID; + return new Dimension(w, h); + } + public static Tile addAndSaveTile(Tile tile) { if (tile == null) { throw new IllegalArgumentException("Tile cannot be null"); diff --git a/src/main/resources/tinylog-dev.properties b/src/main/resources/tinylog-dev.properties index eb46adc1..0766ee23 100755 --- a/src/main/resources/tinylog-dev.properties +++ b/src/main/resources/tinylog-dev.properties @@ -36,5 +36,5 @@ exception = strip: jdk.internal level@jcs.util = info #level@jcs.commandStation = debug -level@jcs.ui.layout = info +#level@jcs.ui.layout = info level@jcs.commandStation.esu.ecos.EcosMessage = info \ No newline at end of file From 005eb4a60060f308452f31b74c343beaec1cca6c Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Thu, 20 Feb 2025 21:03:00 +0100 Subject: [PATCH 25/70] Work on Markin side. support for mDNS implemented. VNC now works with both ESU and Marklin --- .../jcs/commandStation/entities/InfoBean.java | 31 +----- .../esu/ecos/EsuEcosCommandStationImpl.java | 17 +-- .../marklin/cs/MarklinCentralStationImpl.java | 31 ++++-- .../marklin/cs/net/CSConnectionFactory.java | 51 ++++++--- ...PConnection.java => CSHTTPConnection.java} | 6 +- ...CPConnection.java => CSTCPConnection.java} | 104 +++++++++--------- src/main/java/jcs/ui/VNCPanel.java | 39 +------ .../cs/net/CSConnectionFactoryTest.java | 8 +- 8 files changed, 129 insertions(+), 158 deletions(-) rename src/main/java/jcs/commandStation/marklin/cs/net/{HTTPConnection.java => CSHTTPConnection.java} (98%) rename src/main/java/jcs/commandStation/marklin/cs/net/{TCPConnection.java => CSTCPConnection.java} (83%) diff --git a/src/main/java/jcs/commandStation/entities/InfoBean.java b/src/main/java/jcs/commandStation/entities/InfoBean.java index f140c2cf..20b87228 100644 --- a/src/main/java/jcs/commandStation/entities/InfoBean.java +++ b/src/main/java/jcs/commandStation/entities/InfoBean.java @@ -15,7 +15,6 @@ */ package jcs.commandStation.entities; - import jakarta.persistence.Transient; import jcs.entities.CommandStationBean; @@ -30,38 +29,10 @@ public class InfoBean extends CommandStationBean { private String productName; private String articleNumber; private String hostname; + private String ipAddress; private String gfpUid; private String guiUid; -//private String id; -// private String description; -// private String shortName; -// private String className; -// private String connectVia; -// private String serialPort; -// private String ipAddress; -// private Integer networkPort; -// private boolean ipAutoConfiguration; -// private boolean decoderControlSupport; -// private boolean accessoryControlSupport; -// private boolean feedbackSupport; -// private boolean locomotiveSynchronizationSupport; -// private boolean accessorySynchronizationSupport; -// private boolean locomotiveImageSynchronizationSupport; -// private boolean locomotiveFunctionSynchronizationSupport; -// private String protocols; -// private boolean defaultCs; -// private boolean enabled; -// private String lastUsedSerial; -// private String supConnTypesStr; -// private boolean virtual; -// -// private String feedbackModuleIdentifier; -// private Integer feedbackChannelCount; -// private Integer feedbackBus0ModuleCount; -// private Integer feedbackBus1ModuleCount; -// private Integer feedbackBus2ModuleCount; -// private Integer feedbackBus3ModuleCount; public InfoBean() { } diff --git a/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java b/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java index 86379a6a..95d5d8ff 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java @@ -271,13 +271,16 @@ public InfoBean getCommandStationInfo() { InfoBean ib = new InfoBean(this.commandStationBean); if (this.ecosManager != null) { - ib.setArticleNumber(this.ecosManager.getName().replace(this.ecosManager.getCommandStationType() + "-", "")); - ib.setDescription(this.ecosManager.getName()); - ib.setArticleNumber(this.ecosManager.getName().replace(this.ecosManager.getCommandStationType() + "-", "")); - ib.setSerialNumber(this.ecosManager.getSerialNumber()); - ib.setHardwareVersion(this.ecosManager.getHardwareVersion()); - ib.setSoftwareVersion(this.ecosManager.getApplicationVersion()); - ib.setHostname(this.getIp()); + ib.setArticleNumber(ecosManager.getName().replace(this.ecosManager.getCommandStationType() + "-", "")); + ib.setDescription(ecosManager.getName()); + ib.setArticleNumber(ecosManager.getName().replace(this.ecosManager.getCommandStationType() + "-", "")); + ib.setSerialNumber(ecosManager.getSerialNumber()); + ib.setHardwareVersion(ecosManager.getHardwareVersion()); + ib.setSoftwareVersion(ecosManager.getApplicationVersion()); + ib.setHostname(getIp()); + if (ib.getIpAddress() == null) { + ib.setIpAddress(getIp()); + } } else { ib.setDescription("Not Connected"); ib.setHostname("Not Connected"); diff --git a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java index 09c31a62..f431d053 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java +++ b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java @@ -51,7 +51,7 @@ import jcs.commandStation.marklin.cs.events.SystemListener; import jcs.commandStation.marklin.cs.net.CSConnection; import jcs.commandStation.marklin.cs.net.CSConnectionFactory; -import jcs.commandStation.marklin.cs.net.HTTPConnection; +import jcs.commandStation.marklin.cs.net.CSHTTPConnection; import jcs.commandStation.marklin.cs2.AccessoryBeanParser; import jcs.commandStation.marklin.cs2.ChannelDataParser; import jcs.commandStation.marklin.cs2.LocomotiveBeanParser; @@ -228,7 +228,7 @@ public final synchronized boolean connect() { //Based on the info in this file it is quicker to know whether the CS is a version 2 or 3. //In case of a 3 the data can ve retreived via JSON else use CAN private InfoBean getCSInfo() { - HTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(); + CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(); String geraet = httpCon.getInfoFile(); InfoBean ib = InfoBeanParser.parseFile(geraet); @@ -238,6 +238,11 @@ private InfoBean getCSInfo() { ib = InfoBeanParser.parseJson(json); httpCon.setCs3(true); } + + if (ib.getIpAddress() == null) { + ib.setIpAddress(connection.getControllerAddress().getHostAddress()); + } + return ib; } @@ -249,7 +254,7 @@ private InfoBean getCSInfo() { * This data can also be obtained using the CAN Member PING command, but The JSON gives a little more detail. */ private void getAppDevicesCs3() { - HTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(); + CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(); String devJson = httpCon.getDevicesJSON(); List devs = DeviceJSONParser.parse(devJson); @@ -325,9 +330,11 @@ public boolean isPower() { } /** - * System Stop and GO When on = true then the GO command is issued: The track format processor activates the operation and supplies electrical energy. Any speed levels/functions that may still exist - * or have been saved will be sent again. when false the Stop command is issued: Track format processor stops operation on main and programming track. Electrical energy is no longer supplied. All - * speed levels/function values and settings are retained. + * System Stop and GO When on = true then the GO command is issued:
+ * The track format processor activates the operation and supplies electrical energy.
+ * Any speed levels/functions that may still exist or have been saved will be sent again.
+ * When false the Stop command is issued: Track format processor stops operation on main and programming track.
+ * Electrical energy is no longer supplied. All speed levels/function values and settings are retained. * * @param on true Track power On else Off * @return true the Track power is On else Off @@ -651,14 +658,14 @@ List getLocomotivesViaCAN() { } List getLocomotivesViaHttp() { - HTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(); + CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(); String csLocos = httpCon.getLocomotivesFile(); LocomotiveBeanParser lp = new LocomotiveBeanParser(); return lp.parseLocomotivesFile(csLocos); } List getLocomotivesViaJSON() { - HTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(); + CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(); String json = httpCon.getLocomotivesJSON(); LocomotiveBeanJSONParser lp = new LocomotiveBeanJSONParser(); return lp.parseLocomotives(json); @@ -686,7 +693,7 @@ public List getLocomotives() { } List getAccessoriesViaHttp() { - HTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(); + CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(); if (isCS3() && System.getProperty("accessory.list.via", "JSON").equalsIgnoreCase("JSON")) { String json = httpCon.getAccessoriesJSON(); return AccessoryBeanParser.parseAccessoryJSON(json, commandStationBean.getId(), commandStationBean.getShortName()); @@ -716,14 +723,14 @@ public List getAccessories() { @Override public Image getLocomotiveImage(String icon) { - HTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(); + CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(); Image locIcon = httpCon.getLocomotiveImage(icon); return locIcon; } @Override public Image getLocomotiveFunctionImage(String icon) { - HTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(); + CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(); if (this.isCS3()) { if (!FunctionSvgToPngConverter.isSvgCacheLoaded()) { Logger.trace("Loading SVG Cache"); @@ -979,7 +986,7 @@ public void onLocomotiveMessage(CanMessage message) { } } -//////////// For Testing only.....////// + //////////// For Testing only.....////// public static void main(String[] a) { RunUtil.loadExternalProperties(); diff --git a/src/main/java/jcs/commandStation/marklin/cs/net/CSConnectionFactory.java b/src/main/java/jcs/commandStation/marklin/cs/net/CSConnectionFactory.java index 7228197a..d17551a6 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/net/CSConnectionFactory.java +++ b/src/main/java/jcs/commandStation/marklin/cs/net/CSConnectionFactory.java @@ -36,7 +36,10 @@ import org.tinylog.Logger; /** - * Try to connect with a Marklin CS 2/3. A "ping" is send to the broadcast address like the mobile app does. The CS 2/3 response reveals the IP address. + * Try to connect with a Marklin CS 2/3.
+ * The Latest software version of the CS-3 support mDNS, so mDNS is first used to discover the CS.
+ * When mDNS does not work the "old" manner the mobile app uses is used.
+ * A "magic" ping is send to the broadcast address the CS 2/3 response reveals the IP address. * * @author Frans Jacobs */ @@ -47,7 +50,7 @@ public class CSConnectionFactory { private static CSConnectionFactory instance; private CSConnection controllerConnection; - private HTTPConnection httpConnection; + private CSHTTPConnection httpConnection; private InetAddress controllerHost; private static final String BROADCAST_ADDRESS = "255.255.255.255"; @@ -72,7 +75,7 @@ CSConnection getConnectionImpl() { if (lastUsedIp != null) { try { if (Ping.IsReachable(lastUsedIp)) { - this.controllerHost = InetAddress.getByName(lastUsedIp); + controllerHost = InetAddress.getByName(lastUsedIp); Logger.trace("Using last used IP Address: " + lastUsedIp); } else { Logger.trace("Last used IP Address: " + lastUsedIp + " is not reachable"); @@ -83,10 +86,15 @@ CSConnection getConnectionImpl() { } } - if (this.controllerHost == null) { + if (controllerHost == null) { Logger.trace("Try to discover a Marklin CS..."); JCS.logProgress("Discovering a Marklin Central Station..."); - sendMobileAppPing(); + //First try with mdns + controllerHost = discoverCs(); + if (controllerHost == null) { + //try the "old" way by sending a "ping" + controllerHost = sendMobileAppPing(); + } } if (controllerHost != null) { @@ -96,7 +104,7 @@ CSConnection getConnectionImpl() { } Logger.trace("CS ip: " + controllerHost.getHostName()); - controllerConnection = new TCPConnection(controllerHost); + controllerConnection = new CSTCPConnection(controllerHost); } else { Logger.warn("Can't find a Marklin Controller host!"); JCS.logProgress("Can't find a Marklin Central Station on the Network"); @@ -122,21 +130,29 @@ public static void disconnectAll() { instance.controllerHost = null; } - HTTPConnection getHTTPConnectionImpl() { + CSHTTPConnection getHTTPConnectionImpl() { if (controllerConnection == null) { getConnectionImpl(); } if (httpConnection == null) { - httpConnection = new HTTPConnection(controllerHost); + httpConnection = new CSHTTPConnection(controllerHost); } return httpConnection; } - public static HTTPConnection getHTTPConnection() { + public static CSHTTPConnection getHTTPConnection() { return getInstance().getHTTPConnectionImpl(); } - void sendMobileAppPing() { + /** + * Try to Automatically discover the Marklin CS 2/3 IP Address on the local network.
+ * A "magic" CAN message is send as broadcast on the network on the CS RX port.
+ * This method was used by the "old" mobile app to find the Central station. + * + * @return the IP Address of the Marklin Central Station or null if not discovered. + */ + public static InetAddress sendMobileAppPing() { + InetAddress csIp = null; try { InetAddress localAddress; if (RunUtil.isLinux()) { @@ -168,9 +184,7 @@ void sendMobileAppPing() { Logger.trace("Received: " + response + " from: " + replyHost.getHostAddress()); if (response.getCommand() == CanMessage.PING_REQ) { - if (this.controllerHost == null) { - this.controllerHost = replyHost; - } + csIp = replyHost; JCS.logProgress("Found a Central Station in the network with IP: " + replyHost.getHostAddress()); } else { Logger.debug("Received wrong command: " + response.getCommand() + " != " + CanMessage.PING_REQ + "..."); @@ -181,11 +195,12 @@ void sendMobileAppPing() { } catch (IOException ex) { Logger.error(ex); } + return csIp; } String getControllerIpImpl() { - if (this.controllerHost != null) { - return this.controllerHost.getHostAddress(); + if (controllerHost != null) { + return controllerHost.getHostAddress(); } else { return "Unknown"; } @@ -196,10 +211,10 @@ public static String getControllerIp() { } /** - * Try to Automatically discover the ESU ECoS IP Address on the local network.
- * mDNS is used to discover the ECoS + * Try to Automatically discover the Marklin Central Station IP Address on the local network.
+ * mDNS is now supported by the CS-3, not sure whether the CS-2 also supports it. * - * @return the IP Address of the ECoS of null if not discovered. + * @return the IP Address of the Marklin Central Station of null if not discovered. */ public static InetAddress discoverCs() { InetAddress csIp = null; diff --git a/src/main/java/jcs/commandStation/marklin/cs/net/HTTPConnection.java b/src/main/java/jcs/commandStation/marklin/cs/net/CSHTTPConnection.java similarity index 98% rename from src/main/java/jcs/commandStation/marklin/cs/net/HTTPConnection.java rename to src/main/java/jcs/commandStation/marklin/cs/net/CSHTTPConnection.java index 2e771de7..accdd806 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/net/HTTPConnection.java +++ b/src/main/java/jcs/commandStation/marklin/cs/net/CSHTTPConnection.java @@ -36,7 +36,7 @@ * * @author Frans Jacobs */ -public class HTTPConnection { +public class CSHTTPConnection { private final InetAddress csAddress; private boolean cs3; @@ -67,7 +67,7 @@ public class HTTPConnection { // http://cs3host/app/api/mags // http://cs3host/app/api/info // - HTTPConnection(InetAddress csAddress) { + CSHTTPConnection(InetAddress csAddress) { this.csAddress = csAddress; //Assume a CS2 this.cs3 = false; @@ -321,7 +321,7 @@ public static void main(String[] args) throws Exception { } else { inetAddr = InetAddress.getByName("192.168.178.86"); } - HTTPConnection hc = new HTTPConnection(inetAddr); + CSHTTPConnection hc = new CSHTTPConnection(inetAddr); hc.setCs3(cs3); String serial; diff --git a/src/main/java/jcs/commandStation/marklin/cs/net/TCPConnection.java b/src/main/java/jcs/commandStation/marklin/cs/net/CSTCPConnection.java similarity index 83% rename from src/main/java/jcs/commandStation/marklin/cs/net/TCPConnection.java rename to src/main/java/jcs/commandStation/marklin/cs/net/CSTCPConnection.java index 9a3a8a0c..85d72dff 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/net/TCPConnection.java +++ b/src/main/java/jcs/commandStation/marklin/cs/net/CSTCPConnection.java @@ -22,6 +22,8 @@ import java.net.InetAddress; import java.net.Socket; import java.net.SocketException; +import java.util.concurrent.LinkedTransferQueue; +import java.util.concurrent.TransferQueue; import jcs.commandStation.marklin.cs.can.CanMessage; import org.tinylog.Logger; import jcs.commandStation.marklin.cs.events.CanPingListener; @@ -34,7 +36,7 @@ * * @author Frans Jacobs */ -class TCPConnection implements CSConnection { +class CSTCPConnection implements CSConnection { private final InetAddress centralStationAddress; @@ -48,9 +50,14 @@ class TCPConnection implements CSConnection { private boolean debug = false; - TCPConnection(InetAddress csAddress) { + private final TransferQueue transferQueue; + private final TransferQueue eventQueue; + + CSTCPConnection(InetAddress csAddress) { centralStationAddress = csAddress; debug = System.getProperty("message.debug", "false").equalsIgnoreCase("true"); + transferQueue = new LinkedTransferQueue<>(); + eventQueue = new LinkedTransferQueue<>(); checkConnection(); } @@ -127,61 +134,61 @@ public boolean isResponseComplete() { public synchronized CanMessage sendCanMessage(CanMessage message) { ResponseCallback callback = null; - if (message != null) { - if (message.expectsResponse() || message.expectsLongResponse()) { - //Message is expecting response so lets register for response - callback = new ResponseCallback(message); - this.messageReceiver.registerResponseCallback(callback); - } + //if (message != null) { + if (message.expectsResponse() || message.expectsLongResponse()) { + //Message is expecting response so lets register for response + callback = new ResponseCallback(message); + this.messageReceiver.registerResponseCallback(callback); + } - try { - byte[] bytes = message.getMessage(); - //Send the message - dos.write(bytes); - dos.flush(); - } catch (IOException ex) { - Logger.error(ex); - } + try { + byte[] bytes = message.getMessage(); + //Send the message + dos.write(bytes); + dos.flush(); + } catch (IOException ex) { + Logger.error(ex); + } - if (CanMessage.PING_RESP != message.getCommand()) { - //Do not log the ping response as this message is send every 5 seconds or so as a response to the CS ping request. - if (debug) { - Logger.trace("TX: " + message); - } + if (CanMessage.PING_RESP != message.getCommand()) { + //Do not log the ping response as this message is send every 5 seconds or so as a response to the CS ping request. + if (debug) { + Logger.trace("TX: " + message); } + } - long now = System.currentTimeMillis(); - long start = now; - long timeout; + long now = System.currentTimeMillis(); + long start = now; + long timeout; - if (message.expectsLongResponse()) { - timeout = now + LONG_TIMEOUT; - } else if (message.expectsResponse()) { - timeout = now + SHORT_TIMEOUT; - } else { - timeout = now; + if (message.expectsLongResponse()) { + timeout = now + LONG_TIMEOUT; + } else if (message.expectsResponse()) { + timeout = now + SHORT_TIMEOUT; + } else { + timeout = now; + } + + if (callback != null) { + //Wait for the response + boolean responseComplete = callback.isResponseComplete(); + while (!responseComplete && now < timeout) { + responseComplete = callback.isResponseComplete(); + now = System.currentTimeMillis(); } - if (callback != null) { - //Wait for the response - boolean responseComplete = callback.isResponseComplete(); - while (!responseComplete && now < timeout) { - responseComplete = callback.isResponseComplete(); - now = System.currentTimeMillis(); + if (debug) { + if (responseComplete) { + Logger.trace("Got Response in " + (now - start) + " ms"); + } else { + Logger.trace("No Response for " + message + " in " + (now - start) + " ms"); } - - if (debug) { - if (responseComplete) { - Logger.trace("Got Response in " + (now - start) + " ms"); - } else { - Logger.trace("No Response for " + message + " in " + (now - start) + " ms"); - } - } - - //Remove the callback - this.messageReceiver.unRegisterResponseCallback(); } + + //Remove the callback + this.messageReceiver.unRegisterResponseCallback(); } + //} return message; } @@ -373,7 +380,7 @@ public void run() { // uid = 1129552448; // } // -// TCPConnection c = new TCPConnection(inetAddr); +// CSTCPConnection c = new CSTCPConnection(inetAddr); // // while (!c.messageReceiver.isRunning()) { // @@ -395,5 +402,4 @@ public void run() { // } // // } - } diff --git a/src/main/java/jcs/ui/VNCPanel.java b/src/main/java/jcs/ui/VNCPanel.java index c3ba8bc1..51ca4516 100644 --- a/src/main/java/jcs/ui/VNCPanel.java +++ b/src/main/java/jcs/ui/VNCPanel.java @@ -33,7 +33,6 @@ import static java.awt.Toolkit.getDefaultToolkit; import java.awt.datatransfer.StringSelection; import static java.lang.Math.min; -import java.net.InetAddress; import java.net.URL; import javax.swing.ImageIcon; import javax.swing.JFrame; @@ -43,16 +42,15 @@ import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import jcs.JCS; -import jcs.commandStation.esu.ecos.net.EcosConnectionFactory; import org.tinylog.Logger; /** * * Inspired on the work of https://github.com/shinyhut/vernacular-vnc
* My ESU Ecos 50000 has a defect in the screen.
- * This Java viewer is helping the development. In hind site I thin is a welcome addition to add to the main frame in due time + * This Java viewer is helping the development.
+ * In hind site I think is a welcome addition, hance this is added into the main frame * - * @author frans */ public class VNCPanel extends javax.swing.JPanel { @@ -61,9 +59,6 @@ public class VNCPanel extends javax.swing.JPanel { private VernacularClient client; private static final int DEFAULT_VNC_PORT = 5900; - /** - * Creates new form VNCPanel - */ public VNCPanel() { initComponents(); initVnc(); @@ -75,18 +70,9 @@ private void initVnc() { addDrawingSurface(); //clipboardMonitor.start(); initialiseVernacularClient(); - String host = JCS.getJcsCommandStation().getCommandStationInfo().getHostname(); - - //InetAddress ia = EcosConnectionFactory.discoverEcos(); - //InetAddress ia = CSConnectionFactory.discoverCs(); - //if (ia != null) { - // host = ia.getHostAddress(); - //} else { - // Logger.warn("Use a default host ip....."); - // host = "192.168.1.110"; - //} + String ip = JCS.getJcsCommandStation().getCommandStationInfo().getIpAddress(); int port = DEFAULT_VNC_PORT; - this.connect(host, port); + connect(ip, port); } } } @@ -382,8 +368,6 @@ public static void main(String args[]) { VNCPanel vncPanel = new VNCPanel(); JFrame testFrame = new JFrame("VNCPanel Tester"); - //this.setIconImage(Toolkit.getDefaultToolkit().getImage(getClass().getResource("/media/jcs-train-64.png"))); - //URL iconUrl = KeyboardSensorPanel.class.getResource("/media/jcs-train-2-512.png"); URL iconUrl = KeyboardSensorPanel.class.getResource("/media/jcs-train-64.png"); if (iconUrl != null) { testFrame.setIconImage(new ImageIcon(iconUrl).getImage()); @@ -401,21 +385,6 @@ public void windowClosing(java.awt.event.WindowEvent e) { //For now disable the connections possibilities vncPanel.menuPanel.setVisible(false); - - //String host = "192.168.1.110"; -// String host; -// InetAddress ia = EcosConnectionFactory.discoverEcos(); -// //InetAddress ia = CSConnectionFactory.discoverCs(); -// -// if (ia != null) { -// host = ia.getHostAddress(); -// } else { -// Logger.warn("Use a default host ip....."); -// host = "192.168.1.110"; -// } -// -// int port = DEFAULT_VNC_PORT; -// vncPanel.connect(host, port); testFrame.pack(); testFrame.setLocationRelativeTo(null); testFrame.setVisible(true); diff --git a/src/test/java/jcs/commandStation/marklin/cs/net/CSConnectionFactoryTest.java b/src/test/java/jcs/commandStation/marklin/cs/net/CSConnectionFactoryTest.java index b338a8f6..fb7c9190 100644 --- a/src/test/java/jcs/commandStation/marklin/cs/net/CSConnectionFactoryTest.java +++ b/src/test/java/jcs/commandStation/marklin/cs/net/CSConnectionFactoryTest.java @@ -97,8 +97,8 @@ public void testDisconnectAll() { public void testGetHTTPConnectionImpl() { System.out.println("getHTTPConnectionImpl"); CSConnectionFactory instance = null; - HTTPConnection expResult = null; - HTTPConnection result = instance.getHTTPConnectionImpl(); + CSHTTPConnection expResult = null; + CSHTTPConnection result = instance.getHTTPConnectionImpl(); assertEquals(expResult, result); // TODO review the generated test code and remove the default call to fail. fail("The test case is a prototype."); @@ -110,8 +110,8 @@ public void testGetHTTPConnectionImpl() { //@Test public void testGetHTTPConnection() { System.out.println("getHTTPConnection"); - HTTPConnection expResult = null; - HTTPConnection result = CSConnectionFactory.getHTTPConnection(); + CSHTTPConnection expResult = null; + CSHTTPConnection result = CSConnectionFactory.getHTTPConnection(); assertEquals(expResult, result); // TODO review the generated test code and remove the default call to fail. fail("The test case is a prototype."); From 4d24380d436315f9a67d5994c60441969e55b441 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Sat, 22 Feb 2025 21:14:40 +0100 Subject: [PATCH 26/70] Bring Marklin Implementation inline with the HAL. WIP --- .../esu/ecos/net/EcosTCPConnection.java | 3 +- .../marklin/cs/MarklinCentralStationImpl.java | 414 ++++++++---------- .../marklin/cs/can/CanMessage.java | 58 +-- .../marklin/cs/can/MarklinCan.java | 2 +- .../marklin/cs/net/CSConnection.java | 26 +- .../marklin/cs/net/CSTCPConnection.java | 188 ++------ .../marklin/cs2/ChannelDataParser.java | 8 + 7 files changed, 282 insertions(+), 417 deletions(-) diff --git a/src/main/java/jcs/commandStation/esu/ecos/net/EcosTCPConnection.java b/src/main/java/jcs/commandStation/esu/ecos/net/EcosTCPConnection.java index a7a613e9..de735e57 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/net/EcosTCPConnection.java +++ b/src/main/java/jcs/commandStation/esu/ecos/net/EcosTCPConnection.java @@ -259,8 +259,7 @@ public void run() { EcosMessage emsg = new EcosMessage(sb.toString()); Logger.trace("Complete: " + emsg.isResponseComplete() + "\n" + emsg.getMessage() + "\n" + emsg.getResponse()); - eventQueue.put(emsg); - + eventQueue.offer(emsg); } } diff --git a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java index f431d053..d4b94648 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java +++ b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java @@ -21,6 +21,7 @@ import java.util.List; import java.util.Map; import java.util.concurrent.Executors; +import java.util.concurrent.TransferQueue; import java.util.stream.Collectors; import jcs.JCS; import jcs.commandStation.AbstractController; @@ -44,11 +45,6 @@ import static jcs.commandStation.marklin.cs.can.CanMessageFactory.getStatusDataConfigResponse; import jcs.commandStation.marklin.cs.can.parser.MessageInflator; import jcs.commandStation.marklin.cs.can.parser.SystemStatus; -import jcs.commandStation.marklin.cs.events.AccessoryListener; -import jcs.commandStation.marklin.cs.events.CanPingListener; -import jcs.commandStation.marklin.cs.events.FeedbackListener; -import jcs.commandStation.marklin.cs.events.LocomotiveListener; -import jcs.commandStation.marklin.cs.events.SystemListener; import jcs.commandStation.marklin.cs.net.CSConnection; import jcs.commandStation.marklin.cs.net.CSConnectionFactory; import jcs.commandStation.marklin.cs.net.CSHTTPConnection; @@ -73,12 +69,9 @@ import jcs.commandStation.marklin.cs2.PowerEventParser; import jcs.commandStation.marklin.cs2.SensorMessageParser; import jcs.commandStation.VirtualConnection; +import jcs.commandStation.events.DisconnectionEvent; +import jcs.commandStation.events.DisconnectionEventListener; import jcs.entities.LocomotiveBean; -import jcs.entities.LocomotiveBean.DecoderType; -import static jcs.entities.LocomotiveBean.DecoderType.DCC; -import static jcs.entities.LocomotiveBean.DecoderType.MFX; -import static jcs.entities.LocomotiveBean.DecoderType.MFXP; -import static jcs.entities.LocomotiveBean.DecoderType.SX1; import jcs.entities.LocomotiveBean.Direction; import jcs.entities.SensorBean; import jcs.util.RunUtil; @@ -88,7 +81,7 @@ * * @author Frans Jacobs */ -public class MarklinCentralStationImpl extends AbstractController implements DecoderController, AccessoryController, FeedbackController { +public class MarklinCentralStationImpl extends AbstractController implements DecoderController, AccessoryController, FeedbackController, DisconnectionEventListener { private CSConnection connection; @@ -97,6 +90,7 @@ public class MarklinCentralStationImpl extends AbstractController implements Dec private DeviceBean mainDevice; private DeviceBean feedbackDevice; private int csUid; + private EventMessageHandler eventMessageHandler; Map analogChannels; @@ -150,6 +144,8 @@ public final synchronized boolean connect() { } CSConnection csConnection = CSConnectionFactory.getConnection(); + csConnection.addDisconnectionEventListener(this); + connection = csConnection; if (connection != null) { @@ -166,19 +162,9 @@ public final synchronized boolean connect() { } if (connected) { - //Prepare the observers (listeners) which need to react on message events from the Central Station - CanPingMessageListener pingListener = new CanPingMessageListener(this); - CanFeedbackMessageListener feedbackListener = new CanFeedbackMessageListener(this); - CanSystemMessageListener systemEventListener = new CanSystemMessageListener(this); - CanAccessoryMessageListener accessoryListener = new CanAccessoryMessageListener(this); - CanLocomotiveMessageListener locomotiveListener = new CanLocomotiveMessageListener(this); - - this.connection.setCanPingListener(pingListener); - this.connection.setFeedbackListener(feedbackListener); - this.connection.setSystemListener(systemEventListener); - this.connection.setAccessoryListener(accessoryListener); - this.connection.setLocomotiveListener(locomotiveListener); - + //The eventMessageHandler Thread is in charge to handle all event messages which are sende from the CS to JCS + eventMessageHandler = new EventMessageHandler(connection); + eventMessageHandler.start(); JCS.logProgress("Obtaining Device information..."); infoBean = getCSInfo(); @@ -224,9 +210,9 @@ public final synchronized boolean connect() { return connected; } - //The Central station has a "geraet.vrs" files which can be retrieved via HTTP. + //The Central station has a "geraet.vrs" file which can be retrieved via HTTP. //Based on the info in this file it is quicker to know whether the CS is a version 2 or 3. - //In case of a 3 the data can ve retreived via JSON else use CAN + //In case of a CS-3 the information can be retrieved via JSON else use CAN private InfoBean getCSInfo() { CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(); String geraet = httpCon.getInfoFile(); @@ -358,6 +344,9 @@ public boolean power(boolean on) { public void disconnect() { try { if (connection != null) { + if (eventMessageHandler != null) { + eventMessageHandler.quit(); + } connection.close(); connected = false; } @@ -375,6 +364,16 @@ public void disconnect() { Logger.trace("Disconnected"); } + @Override + public void onDisconnect(DisconnectionEvent event) { + String s = event.getSource(); + disconnect(); + + for (DisconnectionEventListener listener : disconnectionEventListeners) { + listener.onDisconnect(event); + } + } + void getMembers() { CanMessage msg = CanMessageFactory.getMembersPing(); this.connection.sendCanMessage(msg); @@ -544,8 +543,8 @@ public synchronized Map getTrackMeasurements() { * @return the CanMessage with responses */ private CanMessage sendMessage(CanMessage canMessage) { - if (this.connection != null) { - this.connection.sendCanMessage(canMessage); + if (connection != null) { + connection.sendCanMessage(canMessage); } else { Logger.warn("NOT connected!"); Logger.trace("Message: " + canMessage + " NOT Send!"); @@ -553,47 +552,46 @@ private CanMessage sendMessage(CanMessage canMessage) { return canMessage; } - private int getLocoAddres(int address, DecoderType decoderType) { - int locoAddress; - locoAddress = switch (decoderType) { - case MFX -> - 0x4000 + address; - case MFXP -> - 0x4000 + address; - case DCC -> - 0xC000 + address; - case SX1 -> - 0x0800 + address; - default -> - address; - }; - - return locoAddress; - } - +// private int getLocoAddres(int address, DecoderType decoderType) { +// int locoAddress; +// locoAddress = switch (decoderType) { +// case MFX -> +// 0x4000 + address; +// case MFXP -> +// 0x4000 + address; +// case DCC -> +// 0xC000 + address; +// case SX1 -> +// 0x0800 + address; +// default -> +// address; +// }; +// +// return locoAddress; +// } @Override public void changeDirection(int locUid, Direction direction) { - if (this.power && this.connected) { + if (power && connected) { CanMessage message = sendMessage(CanMessageFactory.setDirection(locUid, direction.getMarklinValue(), this.csUid)); LocomotiveDirectionEvent dme = LocomotiveDirectionEventParser.parseMessage(message); - this.notifyLocomotiveDirectionEventListeners(dme); + notifyLocomotiveDirectionEventListeners(dme); } } @Override public void changeVelocity(int locUid, int speed, Direction direction) { - if (this.power && this.connected) { + if (power && connected) { CanMessage message = sendMessage(CanMessageFactory.setLocSpeed(locUid, speed, this.csUid)); LocomotiveSpeedEvent vme = LocomotiveSpeedEventParser.parseMessage(message); - this.notifyLocomotiveSpeedEventListeners(vme); + notifyLocomotiveSpeedEventListeners(vme); } } @Override public void changeFunctionValue(int locUid, int functionNumber, boolean flag) { - if (this.power && this.connected) { + if (power && connected) { CanMessage message = sendMessage(CanMessageFactory.setFunction(locUid, functionNumber, flag, this.csUid)); - this.notifyLocomotiveFunctionEventListeners(LocomotiveFunctionEventParser.parseMessage(message)); + notifyLocomotiveFunctionEventListeners(LocomotiveFunctionEventParser.parseMessage(message)); } } @@ -604,7 +602,7 @@ public void switchAccessory(Integer address, AccessoryValue value) { @Override public void switchAccessory(Integer address, AccessoryValue value, Integer switchTime) { - if (this.power && this.connected) { + if (power && connected) { //make sure a time is set! int st; if (switchTime == null || switchTime == 0) { @@ -650,7 +648,7 @@ private void sentJCSInformationMessage() { List getLocomotivesViaCAN() { CanMessage message = CanMessageFactory.requestConfigData(csUid, "loks"); - this.connection.sendCanMessage(message); + connection.sendCanMessage(message); String lokomotive = MessageInflator.inflateConfigDataStream(message, "locomotive"); LocomotiveBeanParser lp = new LocomotiveBeanParser(); @@ -744,11 +742,6 @@ public Image getLocomotiveFunctionImage(String icon) { } private void notifyPowerEventListeners(final PowerEvent powerEvent) { - this.power = powerEvent.isPower(); - executor.execute(() -> fireAllPowerEventListeners(powerEvent)); - } - - private void fireAllPowerEventListeners(final PowerEvent powerEvent) { this.power = powerEvent.isPower(); for (PowerEventListener listener : powerEventListeners) { listener.onPowerChange(powerEvent); @@ -764,26 +757,18 @@ public void fireSensorEventListeners(final SensorEvent sensorEvent) { @Override public void simulateSensor(SensorEvent sensorEvent) { - if (this.connection instanceof VirtualConnection virtualConnection) { + if (connection instanceof VirtualConnection virtualConnection) { virtualConnection.sendEvent(sensorEvent); } } - private void notifySensorEventListeners(final SensorEvent sensorEvent) { - executor.execute(() -> fireSensorEventListeners(sensorEvent)); - } - - private void fireAllAccessoryEventListeners(final AccessoryEvent accessoryEvent) { + private void notifyAccessoryEventListeners(final AccessoryEvent accessoryEvent) { for (AccessoryEventListener listener : this.accessoryEventListeners) { listener.onAccessoryChange(accessoryEvent); } } - private void notifyAccessoryEventListeners(final AccessoryEvent accessoryEvent) { - executor.execute(() -> fireAllAccessoryEventListeners(accessoryEvent)); - } - - private void fireAllFunctionEventListeners(final LocomotiveFunctionEvent functionEvent) { + private void notifyLocomotiveFunctionEventListeners(final LocomotiveFunctionEvent functionEvent) { if (functionEvent.isValid()) { for (LocomotiveFunctionEventListener listener : this.locomotiveFunctionEventListeners) { listener.onFunctionChange(functionEvent); @@ -791,11 +776,7 @@ private void fireAllFunctionEventListeners(final LocomotiveFunctionEvent functio } } - private void notifyLocomotiveFunctionEventListeners(final LocomotiveFunctionEvent functionEvent) { - executor.execute(() -> fireAllFunctionEventListeners(functionEvent)); - } - - private void fireAllDirectionEventListeners(final LocomotiveDirectionEvent directionEvent) { + private void notifyLocomotiveDirectionEventListeners(final LocomotiveDirectionEvent directionEvent) { if (directionEvent.isValid()) { for (LocomotiveDirectionEventListener listener : this.locomotiveDirectionEventListeners) { listener.onDirectionChange(directionEvent); @@ -803,11 +784,7 @@ private void fireAllDirectionEventListeners(final LocomotiveDirectionEvent direc } } - private void notifyLocomotiveDirectionEventListeners(final LocomotiveDirectionEvent directionEvent) { - executor.execute(() -> fireAllDirectionEventListeners(directionEvent)); - } - - private void fireAllLocomotiveSpeedEventListeners(final LocomotiveSpeedEvent speedEvent) { + private void notifyLocomotiveSpeedEventListeners(final LocomotiveSpeedEvent speedEvent) { if (speedEvent.isValid()) { for (LocomotiveSpeedEventListener listener : this.locomotiveSpeedEventListeners) { listener.onSpeedChange(speedEvent); @@ -815,174 +792,162 @@ private void fireAllLocomotiveSpeedEventListeners(final LocomotiveSpeedEvent spe } } - private void notifyLocomotiveSpeedEventListeners(final LocomotiveSpeedEvent locomotiveEvent) { - executor.execute(() -> fireAllLocomotiveSpeedEventListeners(locomotiveEvent)); - } + /** + * Handle Event Message, which are unsolicited messages from the CS. + */ + private class EventMessageHandler extends Thread { - private class CanFeedbackMessageListener implements FeedbackListener { + @SuppressWarnings("FieldMayBeFinal") + private boolean stop = false; + private boolean quit = true; - private final MarklinCentralStationImpl controller; + private final TransferQueue eventMessageQueue; - CanFeedbackMessageListener(MarklinCentralStationImpl controller) { - this.controller = controller; + public EventMessageHandler(CSConnection csConnection) { + eventMessageQueue = csConnection.getEventQueue(); } - @Override - public void onFeedbackMessage(final CanMessage message) { - int cmd = message.getCommand(); - switch (cmd) { - case CanMessage.S88_EVENT_RESPONSE -> { - if (CanMessage.DLC_8 == message.getDlc()) { - SensorBean sb = SensorMessageParser.parseMessage(message, new Date()); - SensorEvent sme = new SensorEvent(sb); - if (sme.getSensorBean() != null) { - controller.notifySensorEventListeners(sme); - } - } - } - } + void quit() { + this.quit = true; } - } - - private class CanPingMessageListener implements CanPingListener { - private final MarklinCentralStationImpl controller; - - CanPingMessageListener(MarklinCentralStationImpl controller) { - this.controller = controller; + boolean isRunning() { + return !this.quit; } - @Override - public void onCanPingRequestMessage(final CanMessage message) { - int cmd = message.getCommand(); - int dlc = message.getDlc(); - //int uid = message.getDeviceUidNumberFromMessage(); - switch (cmd) { - case CanMessage.PING_REQ -> { - //Lets do this the when we know all of the CS... - if (controller.mainDevice != null) { - if (CanMessage.DLC_0 == dlc) { - controller.sendJCSUID(); - } - } - } - } + boolean isFinished() { + return this.stop; } @Override - public void onCanPingResponseMessage(final CanMessage message - ) { - int cmd = message.getCommand(); - int dlc = message.getDlc(); - switch (cmd) { - case CanMessage.PING_RESP -> { - if (CanMessage.DLC_8 == dlc) { - controller.updateMember(message); - } - } - } - } - - @Override - public void onCanStatusConfigRequestMessage(final CanMessage message) { - int cmd = message.getCommand(); - int dlc = message.getDlc(); - int uid = message.getDeviceUidNumberFromMessage(); - switch (cmd) { - case CanMessage.STATUS_CONFIG -> { - if (CanMessage.JCS_UID == uid && CanMessage.DLC_5 == dlc) { - controller.sendJCSInformation(); - } - } - } - } - } + public void run() { + quit = false; + Thread.currentThread().setName("CS-EVENT-MESSAGE-HANDLER"); + + Logger.trace("Event Handler Started..."); + + while (isRunning()) { + try { + CanMessage eventMessage = eventMessageQueue.take(); + Logger.trace("# " + eventMessage); + + int command = eventMessage.getCommand(); + int dlc = eventMessage.getDlc(); + int uid = eventMessage.getDeviceUidNumberFromMessage(); + int subcmd = eventMessage.getSubCommand(); + + switch (command) { + case CanMessage.PING_REQ -> { + //Lets do this the when we know all of the CS... + if (mainDevice != null) { + if (CanMessage.DLC_0 == dlc) { + sendJCSUID(); + } + } + } + case CanMessage.PING_RESP -> { + if (CanMessage.DLC_8 == dlc) { + updateMember(eventMessage); + } + } + case CanMessage.STATUS_CONFIG -> { + if (CanMessage.JCS_UID == uid && CanMessage.DLC_5 == dlc) { + sendJCSInformation(); + } + } + case CanMessage.STATUS_CONFIG_RESP -> { - private class CanSystemMessageListener implements SystemListener { + } + case CanMessage.S88_EVENT_RESPONSE -> { + if (CanMessage.DLC_8 == dlc) { + SensorBean sb = SensorMessageParser.parseMessage(eventMessage, new Date()); + SensorEvent sme = new SensorEvent(sb); + if (sme.getSensorBean() != null) { + fireSensorEventListeners(sme); + } + } + } + case CanMessage.SX1_EVENT -> { + if (CanMessage.DLC_8 == dlc) { + SensorBean sb = SensorMessageParser.parseMessage(eventMessage, new Date()); + SensorEvent sme = new SensorEvent(sb); + if (sme.getSensorBean() != null) { + fireSensorEventListeners(sme); + } + } + } + case CanMessage.SYSTEM_COMMAND -> { - private final MarklinCentralStationImpl controller; + } + case CanMessage.SYSTEM_COMMAND_RESP -> { + switch (subcmd) { + case CanMessage.STOP_SUB_CMD -> { + PowerEvent spe = PowerEventParser.parseMessage(eventMessage); + notifyPowerEventListeners(spe); + } + case CanMessage.GO_SUB_CMD -> { + PowerEvent gpe = PowerEventParser.parseMessage(eventMessage); + notifyPowerEventListeners(gpe); + } + case CanMessage.HALT_SUB_CMD -> { + PowerEvent gpe = PowerEventParser.parseMessage(eventMessage); + notifyPowerEventListeners(gpe); + } + case CanMessage.LOC_STOP_SUB_CMD -> { + PowerEvent gpe = PowerEventParser.parseMessage(eventMessage); + notifyPowerEventListeners(gpe); + } + case CanMessage.OVERLOAD_SUB_CMD -> { + PowerEvent gpe = PowerEventParser.parseMessage(eventMessage); + notifyPowerEventListeners(gpe); + } + } + } + case CanMessage.ACCESSORY_SWITCHING -> { - CanSystemMessageListener(MarklinCentralStationImpl controller) { - this.controller = controller; - } + } + case CanMessage.ACCESSORY_SWITCHING_RESP -> { + AccessoryEvent ae = AccessoryEventParser.parseMessage(eventMessage); + if (ae.isKnownAccessory()) { + notifyAccessoryEventListeners(ae); + } + } + case CanMessage.LOC_VELOCITY -> { - @Override - public void onSystemMessage(CanMessage message) { - int cmd = message.getCommand(); - int subcmd = message.getSubCommand(); - - switch (cmd) { - case CanMessage.SYSTEM_COMMAND_RESP -> { - switch (subcmd) { - case CanMessage.STOP_SUB_CMD -> { - PowerEvent spe = PowerEventParser.parseMessage(message); - controller.notifyPowerEventListeners(spe); } - case CanMessage.GO_SUB_CMD -> { - PowerEvent gpe = PowerEventParser.parseMessage(message); - controller.notifyPowerEventListeners(gpe); + case CanMessage.LOC_VELOCITY_RESP -> { + notifyLocomotiveSpeedEventListeners(LocomotiveSpeedEventParser.parseMessage(eventMessage)); + } + case CanMessage.LOC_DIRECTION -> { + } - case CanMessage.HALT_SUB_CMD -> { - PowerEvent gpe = PowerEventParser.parseMessage(message); - controller.notifyPowerEventListeners(gpe); + case CanMessage.LOC_DIRECTION_RESP -> { + notifyLocomotiveDirectionEventListeners(LocomotiveDirectionEventParser.parseMessage(eventMessage)); + } - case CanMessage.LOC_STOP_SUB_CMD -> { - PowerEvent gpe = PowerEventParser.parseMessage(message); - controller.notifyPowerEventListeners(gpe); + case CanMessage.LOC_FUNCTION -> { + } - case CanMessage.OVERLOAD_SUB_CMD -> { - PowerEvent gpe = PowerEventParser.parseMessage(message); - controller.notifyPowerEventListeners(gpe); + case CanMessage.LOC_FUNCTION_RESP -> { + notifyLocomotiveFunctionEventListeners(LocomotiveFunctionEventParser.parseMessage(eventMessage)); } default -> { + if (CanMessage.BOOTLOADER_CAN != 0x36) { + //Do not log the bootloader message. it is not used in JCS. + if (debug) { + Logger.trace("# " + eventMessage); + } + } } } - } - } - } - } - - private class CanAccessoryMessageListener implements AccessoryListener { - - private final MarklinCentralStationImpl controller; - CanAccessoryMessageListener(MarklinCentralStationImpl controller) { - this.controller = controller; - } - - @Override - public void onAccessoryMessage(CanMessage message) { - int cmd = message.getCommand(); - switch (cmd) { - case CanMessage.ACCESSORY_SWITCHING_RESP -> { - AccessoryEvent ae = AccessoryEventParser.parseMessage(message); - if (ae.isKnownAccessory()) { - controller.notifyAccessoryEventListeners(ae); - } + } catch (InterruptedException ex) { + Logger.error(ex); } } - } - } - private class CanLocomotiveMessageListener implements LocomotiveListener { + Logger.debug("Stop Event handling"); - private final MarklinCentralStationImpl controller; - - CanLocomotiveMessageListener(MarklinCentralStationImpl controller) { - this.controller = controller; - } - - @Override - public void onLocomotiveMessage(CanMessage message) { - int cmd = message.getCommand(); - switch (cmd) { - case CanMessage.LOC_FUNCTION_RESP -> - controller.notifyLocomotiveFunctionEventListeners(LocomotiveFunctionEventParser.parseMessage(message)); - case CanMessage.LOC_DIRECTION_RESP -> - controller.notifyLocomotiveDirectionEventListeners(LocomotiveDirectionEventParser.parseMessage(message)); - case CanMessage.LOC_VELOCITY_RESP -> - controller.notifyLocomotiveSpeedEventListeners(LocomotiveSpeedEventParser.parseMessage(message)); - } } } @@ -1015,10 +980,10 @@ public static void main(String[] a) { //cs.getLocomotivesViaCAN(); //cs.getAccessoriesViaCan(); - //cs3.pause(2000); + //cs.pause(2000); //Logger.trace("getStatusDataConfig CS3"); - //cs3.getStatusDataConfigCS3(); - //cs3.pause(2000); + //cs.getStatusDataConfigCS3(); + //cs.pause(2000); //Logger.trace("getStatusDataConfig"); //cs3.getStatusDataConfig(); //cs3.pause(1000); @@ -1037,9 +1002,10 @@ public static void main(String[] a) { //cs3.sendJCSInfo(); //SystemConfiguration data Map measurements = cs.getTrackMeasurements(); - for (ChannelBean ch : measurements.values()) { - Logger.trace("Channel " + ch.getNumber() + ": " + ch.getHumanValue() + " " + ch.getUnit()); + if (ch != null) { + Logger.trace("Channel " + ch.getNumber() + ": " + ch.getHumanValue() + " " + ch.getUnit()); + } } // Logger.debug("Channel 1: " + cs.channelData1.getChannel().getHumanValue() + " " + cs.channelData1.getChannel().getUnit()); diff --git a/src/main/java/jcs/commandStation/marklin/cs/can/CanMessage.java b/src/main/java/jcs/commandStation/marklin/cs/can/CanMessage.java index 6566133e..8d5d3d9f 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/can/CanMessage.java +++ b/src/main/java/jcs/commandStation/marklin/cs/can/CanMessage.java @@ -274,43 +274,43 @@ public boolean isResponseFor(CanMessage other) { } } - public boolean isPingResponse() { - return this.command == PING_RESP; - } +// public boolean isPingResponse() { +// return this.command == PING_RESP; +// } - public boolean isPingRequest() { - return this.command == PING_REQ; - } +// public boolean isPingRequest() { +// return this.command == PING_REQ; +// } - public boolean isStatusConfigRequest() { - return this.command == STATUS_CONFIG; - } +// public boolean isStatusConfigRequest() { +// return this.command == STATUS_CONFIG; +// } - public boolean isSensorResponse() { - return this.command == S88_EVENT_RESP; - } +// public boolean isSensorResponse() { +// return this.command == S88_EVENT_RESP; +// } - public boolean isStatusDataConfigMessage() { - return this.command == STATUS_CONFIG | this.command == STATUS_CONFIG + 1; - } +// public boolean isStatusDataConfigMessage() { +// return this.command == STATUS_CONFIG | this.command == STATUS_CONFIG + 1; +// } - public boolean isSensorMessage() { - return this.command == S88_EVENT || this.command == SX1_EVENT; - } +// public boolean isSensorMessage() { +// return this.command == S88_EVENT || this.command == SX1_EVENT; +// } - public boolean isAccessoryMessage() { - return this.command == ACCESSORY_SWITCHING || this.command == ACCESSORY_SWITCHING_RESP; - } +// public boolean isAccessoryMessage() { +// return this.command == ACCESSORY_SWITCHING || this.command == ACCESSORY_SWITCHING_RESP; +// } - public boolean isLocomotiveMessage() { - return this.command == LOC_VELOCITY || this.command == LOC_VELOCITY_RESP - || this.command == LOC_DIRECTION || this.command == LOC_DIRECTION_RESP - || this.command == LOC_FUNCTION || this.command == LOC_FUNCTION_RESP; - } +// public boolean isLocomotiveMessage() { +// return this.command == LOC_VELOCITY || this.command == LOC_VELOCITY_RESP +// || this.command == LOC_DIRECTION || this.command == LOC_DIRECTION_RESP +// || this.command == LOC_FUNCTION || this.command == LOC_FUNCTION_RESP; +// } - public boolean isSystemMessage() { - return this.command == SYSTEM_COMMAND || this.command == SYSTEM_COMMAND_RESP; - } +// public boolean isSystemMessage() { +// return this.command == SYSTEM_COMMAND || this.command == SYSTEM_COMMAND_RESP; +// } public boolean hasValidResponse() { if (this.responses == null || this.responses.isEmpty()) { diff --git a/src/main/java/jcs/commandStation/marklin/cs/can/MarklinCan.java b/src/main/java/jcs/commandStation/marklin/cs/can/MarklinCan.java index 0a668163..a5a7b04a 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/can/MarklinCan.java +++ b/src/main/java/jcs/commandStation/marklin/cs/can/MarklinCan.java @@ -107,7 +107,7 @@ interface MarklinCan { //Sensor messages public final static int S88_EVENT = 0x22; - public final static int S88_EVENT_RESP = 0x23; + //public final static int S88_EVENT_RESP = 0x23; public final static int SX1_EVENT = 0x24; diff --git a/src/main/java/jcs/commandStation/marklin/cs/net/CSConnection.java b/src/main/java/jcs/commandStation/marklin/cs/net/CSConnection.java index c49d47d5..98570204 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/net/CSConnection.java +++ b/src/main/java/jcs/commandStation/marklin/cs/net/CSConnection.java @@ -16,17 +16,10 @@ package jcs.commandStation.marklin.cs.net; import java.net.InetAddress; +import java.util.concurrent.TransferQueue; +import jcs.commandStation.events.DisconnectionEventListener; import jcs.commandStation.marklin.cs.can.CanMessage; -import jcs.commandStation.marklin.cs.events.CanPingListener; -import jcs.commandStation.marklin.cs.events.AccessoryListener; -import jcs.commandStation.marklin.cs.events.FeedbackListener; -import jcs.commandStation.marklin.cs.events.LocomotiveListener; -import jcs.commandStation.marklin.cs.events.SystemListener; -/** - * - * @author Frans Jacobs - */ public interface CSConnection extends AutoCloseable { static final int MAX_ERRORS = 15; @@ -37,18 +30,13 @@ public interface CSConnection extends AutoCloseable { CanMessage sendCanMessage(CanMessage message); - void setCanPingListener(CanPingListener canPingListener); - - void setFeedbackListener(FeedbackListener feedbackListener); - - void setSystemListener(SystemListener systemListener); - - void setAccessoryListener(AccessoryListener accessoryListener); - - void setLocomotiveListener(LocomotiveListener locomotiveListener); - InetAddress getControllerAddress(); boolean isConnected(); + TransferQueue getEventQueue(); + + void addDisconnectionEventListener(DisconnectionEventListener listener); + + } diff --git a/src/main/java/jcs/commandStation/marklin/cs/net/CSTCPConnection.java b/src/main/java/jcs/commandStation/marklin/cs/net/CSTCPConnection.java index 85d72dff..cd660b93 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/net/CSTCPConnection.java +++ b/src/main/java/jcs/commandStation/marklin/cs/net/CSTCPConnection.java @@ -22,15 +22,14 @@ import java.net.InetAddress; import java.net.Socket; import java.net.SocketException; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.LinkedTransferQueue; import java.util.concurrent.TransferQueue; +import jcs.commandStation.events.DisconnectionEvent; +import jcs.commandStation.events.DisconnectionEventListener; import jcs.commandStation.marklin.cs.can.CanMessage; import org.tinylog.Logger; -import jcs.commandStation.marklin.cs.events.CanPingListener; -import jcs.commandStation.marklin.cs.events.AccessoryListener; -import jcs.commandStation.marklin.cs.events.FeedbackListener; -import jcs.commandStation.marklin.cs.events.LocomotiveListener; -import jcs.commandStation.marklin.cs.events.SystemListener; /** * @@ -44,20 +43,20 @@ class CSTCPConnection implements CSConnection { private DataOutputStream dos; private ClientMessageReceiver messageReceiver; + private final List disconnectionEventListeners; private static final long SHORT_TIMEOUT = 1000L; private static final long LONG_TIMEOUT = 5000L; private boolean debug = false; - private final TransferQueue transferQueue; private final TransferQueue eventQueue; CSTCPConnection(InetAddress csAddress) { centralStationAddress = csAddress; debug = System.getProperty("message.debug", "false").equalsIgnoreCase("true"); - transferQueue = new LinkedTransferQueue<>(); eventQueue = new LinkedTransferQueue<>(); + disconnectionEventListeners = new ArrayList<>(); checkConnection(); } @@ -80,8 +79,18 @@ private void checkConnection() { } } + @Override + public TransferQueue getEventQueue() { + return this.eventQueue; + } + + @Override + public void addDisconnectionEventListener(DisconnectionEventListener listener) { + this.disconnectionEventListeners.add(listener); + } + private void disconnect() { - this.messageReceiver.quit(); + messageReceiver.quit(); if (dos != null) { try { dos.close(); @@ -90,6 +99,8 @@ private void disconnect() { Logger.trace(ex); } } + + disconnectionEventListeners.clear(); if (clientSocket != null) { try { clientSocket.close(); @@ -101,7 +112,6 @@ private void disconnect() { } private class ResponseCallback { - private final CanMessage tx; private boolean done = false; @@ -132,13 +142,17 @@ public boolean isResponseComplete() { @Override public synchronized CanMessage sendCanMessage(CanMessage message) { + if (message == null) { + Logger.warn("Message is NULL?"); + return null; + } + ResponseCallback callback = null; - //if (message != null) { if (message.expectsResponse() || message.expectsLongResponse()) { //Message is expecting response so lets register for response callback = new ResponseCallback(message); - this.messageReceiver.registerResponseCallback(callback); + messageReceiver.registerResponseCallback(callback); } try { @@ -186,45 +200,10 @@ public synchronized CanMessage sendCanMessage(CanMessage message) { } //Remove the callback - this.messageReceiver.unRegisterResponseCallback(); - } - //} - return message; - } - - @Override - public void setCanPingListener(CanPingListener pingListener) { - if (messageReceiver != null) { - this.messageReceiver.registerCanPingListener(pingListener); - } - } - - @Override - public void setFeedbackListener(FeedbackListener feedbackListener) { - if (messageReceiver != null) { - this.messageReceiver.registerFeedbackListener(feedbackListener); + messageReceiver.unRegisterResponseCallback(); } - } - - @Override - public void setSystemListener(SystemListener systemEventListener) { - if (messageReceiver != null) { - this.messageReceiver.registerSystemListener(systemEventListener); - } - } - @Override - public void setAccessoryListener(AccessoryListener accessoryEventListener) { - if (messageReceiver != null) { - this.messageReceiver.registerAccessoryListener(accessoryEventListener); - } - } - - @Override - public void setLocomotiveListener(LocomotiveListener locomotiveListener) { - if (messageReceiver != null) { - this.messageReceiver.registerLocomotiveListener(locomotiveListener); - } + return message; } @Override @@ -239,7 +218,7 @@ public InetAddress getControllerAddress() { @Override public boolean isConnected() { - return this.messageReceiver != null && this.messageReceiver.isRunning(); + return messageReceiver != null && messageReceiver.isRunning(); } private class ClientMessageReceiver extends Thread { @@ -247,12 +226,6 @@ private class ClientMessageReceiver extends Thread { private boolean quit = true; private DataInputStream din; - private CanPingListener pingListener; - private FeedbackListener feedbackListener; - private SystemListener systemListener; - private AccessoryListener accessoryListener; - private LocomotiveListener locomotiveListener; - private ResponseCallback callBack; public ClientMessageReceiver(Socket socket) { @@ -269,42 +242,22 @@ void registerResponseCallback(ResponseCallback callBack) { } void unRegisterResponseCallback() { - this.callBack = null; - } - - void registerCanPingListener(CanPingListener pingListener) { - this.pingListener = pingListener; - } - - void registerFeedbackListener(FeedbackListener feedbackListener) { - this.feedbackListener = feedbackListener; - } - - void registerSystemListener(SystemListener systemListener) { - this.systemListener = systemListener; - } - - void registerAccessoryListener(AccessoryListener accessoryListener) { - this.accessoryListener = accessoryListener; - } - - void registerLocomotiveListener(LocomotiveListener locomotiveListener) { - this.locomotiveListener = locomotiveListener; + callBack = null; } synchronized void quit() { - this.quit = true; + quit = true; } synchronized boolean isRunning() { - return !this.quit; + return !quit; } @Override public void run() { - Thread.currentThread().setName("CAN-RX"); + Thread.currentThread().setName("CS-CAN-RX"); - this.quit = false; + quit = false; Logger.trace("Started listening on port " + clientSocket.getLocalPort() + "..."); while (isRunning()) { @@ -325,32 +278,23 @@ public void run() { //Logger.trace("RX: "+rx +"; "+ din.available()); if (this.callBack != null && this.callBack.isSubscribedfor(cmd)) { this.callBack.addResponse(rx, din.available()); - } else if (rx.isPingResponse() && pingListener != null) { - this.pingListener.onCanPingResponseMessage(rx); - } else if (rx.isPingRequest() && pingListener != null) { - this.pingListener.onCanPingRequestMessage(rx); - } else if (rx.isStatusConfigRequest() && pingListener != null) { - this.pingListener.onCanStatusConfigRequestMessage(rx); - } else if (rx.isSensorResponse() && feedbackListener != null) { - this.feedbackListener.onFeedbackMessage(rx); - } else if (rx.isSystemMessage() && systemListener != null) { - this.systemListener.onSystemMessage(rx); - } else if (rx.isAccessoryMessage() && accessoryListener != null) { - this.accessoryListener.onAccessoryMessage(rx); - } else if (rx.isLocomotiveMessage() && locomotiveListener != null) { - this.locomotiveListener.onLocomotiveMessage(rx); } else { - if (CanMessage.BOOTLOADER_CAN != 0x36) { - //Do not log the bootloader message. it is not used in JCS. No idea what this message is for. - if (debug) { - Logger.trace("#RX: " + rx); - } - } + eventQueue.offer(rx); + //Logger.trace("Enqueued: " + rx + " QueueSize: " + eventQueue.size()); } + } catch (SocketException se) { + if (!quit) { + String msg = "Host " + centralStationAddress.getHostName(); + DisconnectionEvent de = new DisconnectionEvent(msg); + for (DisconnectionEventListener listener : disconnectionEventListeners) { + listener.onDisconnect(de); + } + } + quit(); - } catch (IOException ioe) { - Logger.error(ioe); + } catch (IOException ex) { + Logger.error(ex); } } @@ -362,44 +306,4 @@ public void run() { } } } - -// public static void main(String[] a) throws UnknownHostException { -// boolean cs3 = true; -// -// InetAddress inetAddr; -// if (cs3) { -// inetAddr = InetAddress.getByName("192.168.178.180"); -// } else { -// inetAddr = InetAddress.getByName("192.168.178.86"); -// } -// -// int uid; -// if (cs3) { -// uid = 1668498828; -// } else { -// uid = 1129552448; -// } -// -// CSTCPConnection c = new CSTCPConnection(inetAddr); -// -// while (!c.messageReceiver.isRunning()) { -// -// } -// -// //CanMessage m = c.sendCanMessage(CanMessageFactory.getMembersPing()); -// CanMessage m = c.sendCanMessage(CanMessageFactory.querySystem(uid)); -// -// Logger.trace("TX: " + m); -// for (CanMessage r : m.getResponses()) { -// Logger.trace("RSP: " + r); -// } -// -// CanMessage m2 = c.sendCanMessage(CanMessageFactory.querySystem(uid)); -// -// Logger.trace("TX: " + m2); -// for (CanMessage r : m2.getResponses()) { -// Logger.trace("RSP: " + r); -// } -// -// } } diff --git a/src/main/java/jcs/commandStation/marklin/cs2/ChannelDataParser.java b/src/main/java/jcs/commandStation/marklin/cs2/ChannelDataParser.java index c5c34816..152b4350 100644 --- a/src/main/java/jcs/commandStation/marklin/cs2/ChannelDataParser.java +++ b/src/main/java/jcs/commandStation/marklin/cs2/ChannelDataParser.java @@ -44,7 +44,11 @@ private int getStringLength(byte[] data) { private int getNumberOfPackets(CanMessage message) { int packets = -1; List responses = message.getResponses(); + Logger.trace("Response count: "+responses.size()); + if(responses.isEmpty()) { + return 0; + } int lastIdx = responses.size(); if (lastIdx > 0) { lastIdx = lastIdx - 1; @@ -67,6 +71,10 @@ public ChannelBean parseConfigMessage(CanMessage message) { if (message.getCommand() == CanMessage.STATUS_CONFIG) { List responses = message.getResponses(); int packets = getNumberOfPackets(message); + if(packets == 0) { + Logger.trace("No packets avaliable"); + return null; + } //Create one array with data byte[] data = new byte[8 * packets]; From 9bc3357dc223d98bdac82f6ef7ace13502485c30 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Fri, 28 Feb 2025 21:20:24 +0100 Subject: [PATCH 27/70] Initial entry for Marklin Virtual CS, some refactoring --- .../commandStation/events/AccessoryEvent.java | 26 +- .../marklin/cs/MarklinCentralStationImpl.java | 174 +++--- .../marklin/cs/can/CanMessage.java | 85 +-- .../can/parser/AccessoryMessageParser.java} | 33 +- .../marklin/cs/can/parser/SystemStatus.java | 69 +- .../marklin/cs/net/CSConnectionFactory.java | 99 +-- .../marklin/cs/net/CSHTTPConnection.java | 381 +----------- .../marklin/cs/net/CSHTTPConnectionImpl.java | 392 ++++++++++++ .../marklin/cs/net/CSHTTPConnectionVirt.java | 587 ++++++++++++++++++ .../marklin/cs/net/CSTCPConnection.java | 16 +- .../marklin/cs/net/CSVirtualConnection.java | 252 ++++++++ .../marklin/cs2/AccessoryBeanParser.java | 47 +- .../marklin/cs3/DeviceJSONParser.java | 56 +- .../marklin/cs3/LocomotiveBeanJSONParser.java | 28 +- src/main/java/jcs/ui/JCSFrame.form | 6 - src/main/java/jcs/ui/JCSFrame.java | 1 + .../cs/net/CSConnectionFactoryTest.java | 8 +- 17 files changed, 1583 insertions(+), 677 deletions(-) rename src/main/java/jcs/commandStation/marklin/{cs2/AccessoryEventParser.java => cs/can/parser/AccessoryMessageParser.java} (66%) mode change 100755 => 100644 src/main/java/jcs/commandStation/marklin/cs/net/CSHTTPConnection.java create mode 100755 src/main/java/jcs/commandStation/marklin/cs/net/CSHTTPConnectionImpl.java create mode 100644 src/main/java/jcs/commandStation/marklin/cs/net/CSHTTPConnectionVirt.java create mode 100644 src/main/java/jcs/commandStation/marklin/cs/net/CSVirtualConnection.java diff --git a/src/main/java/jcs/commandStation/events/AccessoryEvent.java b/src/main/java/jcs/commandStation/events/AccessoryEvent.java index ab2c04d9..03ee2d36 100755 --- a/src/main/java/jcs/commandStation/events/AccessoryEvent.java +++ b/src/main/java/jcs/commandStation/events/AccessoryEvent.java @@ -31,28 +31,40 @@ public AccessoryBean getAccessoryBean() { return accessoryBean; } - public boolean isKnownAccessory() { - return this.accessoryBean != null && (this.accessoryBean.getAddress() != null || this.accessoryBean.getId() != null); + public boolean isValid() { + return accessoryBean != null && (accessoryBean.getAddress() != null || accessoryBean.getId() != null); } public boolean isEventFor(AccessoryBean accessory) { - boolean addressEquals = this.accessoryBean.getAddress().equals(accessory.getAddress()); - boolean idEquals = this.accessoryBean.getId().equals(accessory.getId()); + boolean addressEquals = accessoryBean.getAddress().equals(accessory.getAddress()); + boolean idEquals = accessoryBean.getId().equals(accessory.getId()); return addressEquals || idEquals; } public SignalValue getSignalValue() { - return this.accessoryBean.getSignalValue(); + return accessoryBean.getSignalValue(); } public AccessoryValue getValue() { - return this.accessoryBean.getAccessoryValue(); + return accessoryBean.getAccessoryValue(); + } + + public boolean isGreen() { + return AccessoryValue.GREEN == accessoryBean.getAccessoryValue(); + } + + public boolean isRed() { + return AccessoryValue.RED == accessoryBean.getAccessoryValue(); + } + + public Integer getAddress() { + return accessoryBean.getAddress(); } @Override public String getId() { - return this.accessoryBean.getId(); + return accessoryBean.getId(); } } diff --git a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java index d4b94648..04775bb8 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java +++ b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java @@ -47,7 +47,6 @@ import jcs.commandStation.marklin.cs.can.parser.SystemStatus; import jcs.commandStation.marklin.cs.net.CSConnection; import jcs.commandStation.marklin.cs.net.CSConnectionFactory; -import jcs.commandStation.marklin.cs.net.CSHTTPConnection; import jcs.commandStation.marklin.cs2.AccessoryBeanParser; import jcs.commandStation.marklin.cs2.ChannelDataParser; import jcs.commandStation.marklin.cs2.LocomotiveBeanParser; @@ -60,7 +59,7 @@ import jcs.entities.CommandStationBean; import jcs.commandStation.entities.DeviceBean; import jcs.commandStation.entities.InfoBean; -import jcs.commandStation.marklin.cs2.AccessoryEventParser; +import jcs.commandStation.marklin.cs.can.parser.AccessoryMessageParser; import jcs.entities.FeedbackModuleBean; import jcs.commandStation.marklin.cs2.InfoBeanParser; import jcs.commandStation.marklin.cs2.LocomotiveDirectionEventParser; @@ -76,6 +75,7 @@ import jcs.entities.SensorBean; import jcs.util.RunUtil; import org.tinylog.Logger; +import jcs.commandStation.marklin.cs.net.CSHTTPConnection; /** * @@ -135,15 +135,24 @@ public String getIp() { return CSConnectionFactory.getControllerIp(); } + @Override + public void setVirtual(boolean flag) { + this.virtual = flag; + Logger.info("Switching Virtual Mode " + (flag ? "On" : "Off")); + disconnect(); + connect(); + } + @Override public final synchronized boolean connect() { if (!connected) { - Logger.trace("Connecting to a Central Station " + (commandStationBean != null ? commandStationBean.getDescription() : "Unknown")); + Logger.trace("Connecting to a " + (virtual ? "Virtual " : "") + "Central Station " + (commandStationBean != null ? commandStationBean.getDescription() : "Unknown")); + if (executor == null || executor.isShutdown()) { executor = Executors.newCachedThreadPool(); } - CSConnection csConnection = CSConnectionFactory.getConnection(); + CSConnection csConnection = CSConnectionFactory.getConnection(virtual); csConnection.addDisconnectionEventListener(this); connection = csConnection; @@ -162,11 +171,11 @@ public final synchronized boolean connect() { } if (connected) { - //The eventMessageHandler Thread is in charge to handle all event messages which are sende from the CS to JCS + //The eventMessageHandler Thread is in charge to handle all event messages which are send from the CS to JCS eventMessageHandler = new EventMessageHandler(connection); eventMessageHandler.start(); - JCS.logProgress("Obtaining Device information..."); + JCS.logProgress("Obtaining Device information..."); infoBean = getCSInfo(); //request all members on the Marklin CAN bus to give a response @@ -189,12 +198,12 @@ public final synchronized boolean connect() { if (mainDevice != null) { Logger.trace("Found " + mainDevice.getName() + ", " + mainDevice.getArticleNumber() + " SerialNumber: " + mainDevice.getSerial() + " in " + (now - start) + " ms"); JCS.logProgress("Connected with " + infoBean.getProductName()); - - power = isPower(); - JCS.logProgress("Power is " + (power ? "On" : "Off")); } else { Logger.warn("No main Device found yet..."); } + + power = isPower(); + JCS.logProgress("Power is " + (power ? "On" : "Off")); } Logger.trace("Connected: " + connected + " Default Accessory SwitchTime: " + this.defaultSwitchTime); } else { @@ -210,21 +219,24 @@ public final synchronized boolean connect() { return connected; } + //The device information can be retrieved via CAN, but using a shortcut via http goes much faster. //The Central station has a "geraet.vrs" file which can be retrieved via HTTP. //Based on the info in this file it is quicker to know whether the CS is a version 2 or 3. //In case of a CS-3 the information can be retrieved via JSON else use CAN private InfoBean getCSInfo() { - CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(); + CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(virtual); String geraet = httpCon.getInfoFile(); InfoBean ib = InfoBeanParser.parseFile(geraet); + //CS3? if ("60126".equals(ib.getArticleNumber()) || "60226".equals(ib.getArticleNumber())) { - //CS3 String json = httpCon.getInfoJSON(); ib = InfoBeanParser.parseJson(json); httpCon.setCs3(true); } + csUid = Integer.parseUnsignedInt(ib.getGfpUid(), 16); + if (ib.getIpAddress() == null) { ib.setIpAddress(connection.getControllerAddress().getHostAddress()); } @@ -240,29 +252,27 @@ private InfoBean getCSInfo() { * This data can also be obtained using the CAN Member PING command, but The JSON gives a little more detail. */ private void getAppDevicesCs3() { - CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(); + CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(virtual); String devJson = httpCon.getDevicesJSON(); List devs = DeviceJSONParser.parse(devJson); //Update the devices for (DeviceBean d : devs) { if (devices.containsKey(d.getUidAsInt())) { - //Logger.trace("Updating " + d.getUid() + ", " + d.getName()); devices.put(d.getUidAsInt(), d); } else { - //Logger.trace("Adding " + d.getUid() + ", " + d.getName()); devices.put(d.getUidAsInt(), d); } String an = d.getArticleNumber(); if ("60213".equals(an) || "60214".equals(an) || "60215".equals(an) || "60126".equals(an) || "60226".equals(an)) { this.csUid = d.getUidAsInt(); this.mainDevice = d; - Logger.trace("MainDevice: " + d); + Logger.trace("MainDevice: " + d.getName()); } if ("60883".equals(an)) { this.feedbackDevice = d; - Logger.trace("FeedbackDevice: " + d); + Logger.trace("FeedbackDevice: " + d.getName()); } } @@ -302,17 +312,12 @@ public List getFeedbackModules() { */ @Override public boolean isPower() { - if (this.connected) { - CanMessage m = sendMessage(CanMessageFactory.querySystem(this.csUid)); - if (debug) { - Logger.trace("Received " + m.getResponses().size() + " responses. RX: " + m.getResponse()); - } - SystemStatus ss = new SystemStatus(m); - this.power = ss.isPower(); + if (connected) { + power = SystemStatus.parseSystemPowerMessage(sendMessage(CanMessageFactory.querySystem(csUid))); } else { - this.power = false; + power = false; } - return this.power; + return power; } /** @@ -327,13 +332,11 @@ public boolean isPower() { */ @Override public boolean power(boolean on) { - if (this.connected) { - SystemStatus ss = new SystemStatus(sendMessage(CanMessageFactory.systemStopGo(on, csUid))); - this.power = ss.isPower(); - - PowerEvent pe = new PowerEvent(this.power); + if (connected) { + Logger.trace("Switch Track Power " + (on ? "On" : "Off")); + power = SystemStatus.parseSystemPowerMessage(sendMessage(CanMessageFactory.systemStopGo(on, csUid))); + PowerEvent pe = new PowerEvent(power); notifyPowerEventListeners(pe); - return power; } else { return false; @@ -376,7 +379,7 @@ public void onDisconnect(DisconnectionEvent event) { void getMembers() { CanMessage msg = CanMessageFactory.getMembersPing(); - this.connection.sendCanMessage(msg); + connection.sendCanMessage(msg); if (debug) { Logger.trace(msg); @@ -431,9 +434,9 @@ void getMembers() { Logger.trace("Main Device: " + d); } if (System.getProperty("cs.article") == null) { - System.setProperty("cs.article", this.mainDevice.getArticleNumber()); - System.setProperty("cs.serial", this.mainDevice.getSerial()); - System.setProperty("cs.name", this.mainDevice.getName()); + System.setProperty("cs.article", mainDevice.getArticleNumber()); + System.setProperty("cs.serial", mainDevice.getSerial()); + System.setProperty("cs.name", mainDevice.getName()); System.setProperty("cs.cs3", (isCS3() ? "true" : "false")); } } else { @@ -445,20 +448,16 @@ void getMembers() { } } - private void updateMember(CanMessage message) { - executor.execute(() -> updateDevice(message)); - } - private void updateDevice(final CanMessage message) { if (CanMessage.PING_RESP == message.getCommand()) { int uid = message.getDeviceUidNumberFromMessage(); DeviceBean device; - if (this.devices.containsKey(uid)) { - device = this.devices.get(uid); + if (devices.containsKey(uid)) { + device = devices.get(uid); } else { device = new DeviceBean(message); - this.devices.put(device.getUidAsInt(), device); + devices.put(device.getUidAsInt(), device); } if (!device.isDataComplete()) { @@ -468,10 +467,10 @@ private void updateDevice(final CanMessage message) { Logger.trace("Updated: " + device); } //Can the main device be set from the avaliable data - for (DeviceBean d : this.devices.values()) { + for (DeviceBean d : devices.values()) { if (d.isDataComplete() && ("60214".equals(d.getArticleNumber()) || "60226".equals(d.getArticleNumber()) || "60126".equals(d.getArticleNumber()))) { - this.csUid = d.getUidAsInt(); - this.mainDevice = d; + csUid = d.getUidAsInt(); + mainDevice = d; if (debug) { Logger.trace("Main Device: " + d); } @@ -479,11 +478,11 @@ private void updateDevice(final CanMessage message) { } } - if (this.mainDevice == null) { + if (mainDevice == null) { //Lets send a ping again getMembers(); } else { - if (this.mainDevice != null && this.mainDevice.isDataComplete()) { + if (mainDevice != null && this.mainDevice.isDataComplete()) { if (System.getProperty("cs.article") == null) { System.setProperty("cs.article", this.mainDevice.getArticleNumber()); System.setProperty("cs.serial", this.mainDevice.getSerial()); @@ -505,6 +504,7 @@ public boolean isSupportTrackMeasurements() { @Override public synchronized Map getTrackMeasurements() { + Logger.trace("Perform measurement..."); if (this.connected && this.mainDevice != null) { //main device int nrOfChannels = this.mainDevice.getAnalogChannels().size(); @@ -614,7 +614,7 @@ public void switchAccessory(Integer address, AccessoryValue value, Integer switc st = st / 10; CanMessage message = sendMessage(CanMessageFactory.switchAccessory(address, value, true, st, this.csUid)); //Notify listeners - AccessoryEvent ae = AccessoryEventParser.parseMessage(message); + AccessoryEvent ae = AccessoryMessageParser.parse(message); notifyAccessoryEventListeners(ae); } else { @@ -627,18 +627,10 @@ public void switchAccessory(String id, AccessoryValue value) { throw new UnsupportedOperationException("Not supported yet."); } - private void sendJCSUID() { - executor.execute(() -> sendJCSUIDMessage()); - } - private void sendJCSUIDMessage() { sendMessage(CanMessageFactory.getMemberPingResponse(CanMessage.JCS_UID, 1, CanMessage.JCS_DEVICE_ID)); } - private void sendJCSInformation() { - executor.execute(() -> sentJCSInformationMessage()); - } - private void sentJCSInformationMessage() { List messages = getStatusDataConfigResponse(CanMessage.JCS_SERIAL, 0, 0, "JCS", "Java Central Station", CanMessage.JCS_UID); for (CanMessage msg : messages) { @@ -656,14 +648,14 @@ List getLocomotivesViaCAN() { } List getLocomotivesViaHttp() { - CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(); + CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(virtual); String csLocos = httpCon.getLocomotivesFile(); LocomotiveBeanParser lp = new LocomotiveBeanParser(); return lp.parseLocomotivesFile(csLocos); } List getLocomotivesViaJSON() { - CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(); + CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(virtual); String json = httpCon.getLocomotivesJSON(); LocomotiveBeanJSONParser lp = new LocomotiveBeanJSONParser(); return lp.parseLocomotives(json); @@ -691,7 +683,7 @@ public List getLocomotives() { } List getAccessoriesViaHttp() { - CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(); + CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(virtual); if (isCS3() && System.getProperty("accessory.list.via", "JSON").equalsIgnoreCase("JSON")) { String json = httpCon.getAccessoriesJSON(); return AccessoryBeanParser.parseAccessoryJSON(json, commandStationBean.getId(), commandStationBean.getShortName()); @@ -721,14 +713,14 @@ public List getAccessories() { @Override public Image getLocomotiveImage(String icon) { - CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(); + CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(virtual); Image locIcon = httpCon.getLocomotiveImage(icon); return locIcon; } @Override public Image getLocomotiveFunctionImage(String icon) { - CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(); + CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(virtual); if (this.isCS3()) { if (!FunctionSvgToPngConverter.isSvgCacheLoaded()) { Logger.trace("Loading SVG Cache"); @@ -742,7 +734,7 @@ public Image getLocomotiveFunctionImage(String icon) { } private void notifyPowerEventListeners(final PowerEvent powerEvent) { - this.power = powerEvent.isPower(); + power = powerEvent.isPower(); for (PowerEventListener listener : powerEventListeners) { listener.onPowerChange(powerEvent); } @@ -792,6 +784,7 @@ private void notifyLocomotiveSpeedEventListeners(final LocomotiveSpeedEvent spee } } + //TODO Watchdog and measurements als a kind of data table... /** * Handle Event Message, which are unsolicited messages from the CS. */ @@ -829,7 +822,7 @@ public void run() { while (isRunning()) { try { CanMessage eventMessage = eventMessageQueue.take(); - Logger.trace("# " + eventMessage); + //Logger.trace("# " + eventMessage); int command = eventMessage.getCommand(); int dlc = eventMessage.getDlc(); @@ -841,22 +834,26 @@ public void run() { //Lets do this the when we know all of the CS... if (mainDevice != null) { if (CanMessage.DLC_0 == dlc) { - sendJCSUID(); + Logger.trace("Answering Ping RQ: " + eventMessage); + sendJCSUIDMessage(); } } } case CanMessage.PING_RESP -> { if (CanMessage.DLC_8 == dlc) { - updateMember(eventMessage); + Logger.trace("Ping Response RX: " + eventMessage); + + updateDevice(eventMessage); } } case CanMessage.STATUS_CONFIG -> { if (CanMessage.JCS_UID == uid && CanMessage.DLC_5 == dlc) { - sendJCSInformation(); + Logger.trace("StatusConfig RQ: " + eventMessage); + sentJCSInformationMessage(); } } case CanMessage.STATUS_CONFIG_RESP -> { - + Logger.trace("StatusConfigResponse RX: " + eventMessage); } case CanMessage.S88_EVENT_RESPONSE -> { if (CanMessage.DLC_8 == dlc) { @@ -877,7 +874,7 @@ public void run() { } } case CanMessage.SYSTEM_COMMAND -> { - + Logger.trace("SystemConfigCommand RX: " + eventMessage); } case CanMessage.SYSTEM_COMMAND_RESP -> { switch (subcmd) { @@ -904,11 +901,11 @@ public void run() { } } case CanMessage.ACCESSORY_SWITCHING -> { - + Logger.trace("AccessorySwitching RX: " + eventMessage); } case CanMessage.ACCESSORY_SWITCHING_RESP -> { - AccessoryEvent ae = AccessoryEventParser.parseMessage(eventMessage); - if (ae.isKnownAccessory()) { + AccessoryEvent ae = AccessoryMessageParser.parse(eventMessage); + if (ae.isValid()) { notifyAccessoryEventListeners(ae); } } @@ -923,7 +920,6 @@ public void run() { } case CanMessage.LOC_DIRECTION_RESP -> { notifyLocomotiveDirectionEventListeners(LocomotiveDirectionEventParser.parseMessage(eventMessage)); - } case CanMessage.LOC_FUNCTION -> { @@ -951,7 +947,9 @@ public void run() { } } - //////////// For Testing only.....////// + //////////// For Testing only.....////// + /// @param a + /// public static void main(String[] a) { RunUtil.loadExternalProperties(); @@ -971,12 +969,22 @@ public static void main(String[] a) { csb.setProtocols("DCC,MFX,MM"); csb.setDefault(true); csb.setEnabled(true); + csb.setVirtual(true); MarklinCentralStationImpl cs = new MarklinCentralStationImpl(csb, false); Logger.debug((cs.connect() ? "Connected" : "NOT Connected")); if (cs.isConnected()) { Logger.debug("Power is " + (cs.isPower() ? "ON" : "Off")); + cs.power(false); + Logger.debug("Power is " + (cs.isPower() ? "ON" : "Off")); + cs.power(true); + + Logger.debug("Switch Accessory 2 to Red"); + cs.switchAccessory(2,AccessoryValue.RED,250); + + Logger.debug("Switch Accessory 2 to Green"); + cs.switchAccessory(2,AccessoryValue.GREEN,250); //cs.getLocomotivesViaCAN(); //cs.getAccessoriesViaCan(); @@ -988,9 +996,7 @@ public static void main(String[] a) { //cs3.getStatusDataConfig(); //cs3.pause(1000); //cs3.pause(4000); - //cs3.power(false); - //Logger.debug("Power is " + (cs.isPower() ? "ON" : "Off")); - //cs3.power(true); + // //cs3.pause(500); //Logger.debug("Power is " + (cs.isPower() ? "ON" : "Off")); //cs3.sendJCSInfo(); @@ -1001,12 +1007,12 @@ public static void main(String[] a) { //Logger.debug("Power is " + (cs.isPower() ? "ON" : "Off")); //cs3.sendJCSInfo(); //SystemConfiguration data - Map measurements = cs.getTrackMeasurements(); - for (ChannelBean ch : measurements.values()) { - if (ch != null) { - Logger.trace("Channel " + ch.getNumber() + ": " + ch.getHumanValue() + " " + ch.getUnit()); - } - } +// Map measurements = cs.getTrackMeasurements(); +// for (ChannelBean ch : measurements.values()) { +// if (ch != null) { +// Logger.trace("Channel " + ch.getNumber() + ": " + ch.getHumanValue() + " " + ch.getUnit()); +// } +// } // Logger.debug("Channel 1: " + cs.channelData1.getChannel().getHumanValue() + " " + cs.channelData1.getChannel().getUnit()); // Logger.debug("Channel 2: " + cs.channelData2.getChannel().getHumanValue() + " " + cs.channelData2.getChannel().getUnit()); @@ -1077,9 +1083,9 @@ public static void main(String[] a) { // } cs.pause(40000); cs.disconnect(); - cs.pause(100L); +// cs.pause(100L); Logger.debug("DONE"); - //System.exit(0); + System.exit(0); } //for (int i = 0; i < 16; i++) { // cs.requestFeedbackEvents(i + 1); diff --git a/src/main/java/jcs/commandStation/marklin/cs/can/CanMessage.java b/src/main/java/jcs/commandStation/marklin/cs/can/CanMessage.java index 8d5d3d9f..bc63274c 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/can/CanMessage.java +++ b/src/main/java/jcs/commandStation/marklin/cs/can/CanMessage.java @@ -15,7 +15,6 @@ */ package jcs.commandStation.marklin.cs.can; -import java.io.Serializable; import java.util.Arrays; import java.util.LinkedList; import java.util.List; @@ -24,7 +23,7 @@ /** * CS 2/3 CAN message. */ -public class CanMessage implements MarklinCan, Serializable { +public class CanMessage implements MarklinCan { private int priority; private int command; @@ -96,6 +95,11 @@ public static String toString(byte[] data) { return new String(data); } + public static final byte toByte(int value) { + byte[] bts = to2Bytes(value); + return bts[1]; + } + public static final byte[] to2Bytes(int value) { byte[] bts = new byte[]{ (byte) ((value >> 8) & 0xFF), @@ -274,44 +278,6 @@ public boolean isResponseFor(CanMessage other) { } } -// public boolean isPingResponse() { -// return this.command == PING_RESP; -// } - -// public boolean isPingRequest() { -// return this.command == PING_REQ; -// } - -// public boolean isStatusConfigRequest() { -// return this.command == STATUS_CONFIG; -// } - -// public boolean isSensorResponse() { -// return this.command == S88_EVENT_RESP; -// } - -// public boolean isStatusDataConfigMessage() { -// return this.command == STATUS_CONFIG | this.command == STATUS_CONFIG + 1; -// } - -// public boolean isSensorMessage() { -// return this.command == S88_EVENT || this.command == SX1_EVENT; -// } - -// public boolean isAccessoryMessage() { -// return this.command == ACCESSORY_SWITCHING || this.command == ACCESSORY_SWITCHING_RESP; -// } - -// public boolean isLocomotiveMessage() { -// return this.command == LOC_VELOCITY || this.command == LOC_VELOCITY_RESP -// || this.command == LOC_DIRECTION || this.command == LOC_DIRECTION_RESP -// || this.command == LOC_FUNCTION || this.command == LOC_FUNCTION_RESP; -// } - -// public boolean isSystemMessage() { -// return this.command == SYSTEM_COMMAND || this.command == SYSTEM_COMMAND_RESP; -// } - public boolean hasValidResponse() { if (this.responses == null || this.responses.isEmpty()) { return false; @@ -468,6 +434,42 @@ public static final byte[] generateHash(int gfpUid) { return to2Bytes(hash); } + /** + * Create a CanMessage from a String. This method is used to ease testing.
+ * The message should be in the format:
+ * 0x00 0x00 0x07 0x69 0x04 0x00 0x00 0x00 0x00 0x00 0xab 0x00 0xfc + * + * @param message a CAN message with content as in the given String + */ + public static CanMessage parse(String message) { + return parse(message, false); + } + + /** + * Create a CanMessage from a String. This method is used to ease testing.
+ * The message should be in the format:
+ * 0x00 0x00 0x07 0x69 0x04 0x00 0x00 0x00 0x00 0x00 0xab 0x00 0xfc + * + * @param message a CAN message with content as in the given String + * @param response force the response bit set + */ + public static CanMessage parse(String message, boolean response) { + String[] sa = message.split(" "); + byte[] ba = new byte[MESSAGE_SIZE]; + for (int i = 0; i < ba.length; i++) { + String bs = sa[i]; + bs = bs.replace("0x", ""); + ba[i] = toByte(Integer.parseUnsignedInt(bs, 16)); + + if (i == 1 && response) { + ba[i]++; + } + + } + + return new CanMessage(ba); + } + @Override public int hashCode() { int h = 5; @@ -506,8 +508,6 @@ public boolean equals(Object obj) { return Arrays.equals(this.data, other.data); } -} - // public String print() { // StringBuilder sb = new StringBuilder(); // sb.append(getMessageName()); @@ -611,3 +611,4 @@ public boolean equals(Object obj) { // return "Unknown: " + cmd; // } // } +} diff --git a/src/main/java/jcs/commandStation/marklin/cs2/AccessoryEventParser.java b/src/main/java/jcs/commandStation/marklin/cs/can/parser/AccessoryMessageParser.java similarity index 66% rename from src/main/java/jcs/commandStation/marklin/cs2/AccessoryEventParser.java rename to src/main/java/jcs/commandStation/marklin/cs/can/parser/AccessoryMessageParser.java index ead78225..42255419 100644 --- a/src/main/java/jcs/commandStation/marklin/cs2/AccessoryEventParser.java +++ b/src/main/java/jcs/commandStation/marklin/cs/can/parser/AccessoryMessageParser.java @@ -13,40 +13,47 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package jcs.commandStation.marklin.cs2; +package jcs.commandStation.marklin.cs.can.parser; import jcs.commandStation.events.AccessoryEvent; import jcs.commandStation.marklin.cs.can.CanMessage; import jcs.entities.AccessoryBean; import org.tinylog.Logger; -public class AccessoryEventParser { +public class AccessoryMessageParser { + + private AccessoryMessageParser() { + + } - public static AccessoryEvent parseMessage(CanMessage message) { - CanMessage resp; + public static AccessoryEvent parse(CanMessage message) { + CanMessage msg; if (!message.isResponseMessage()) { - resp = message.getResponse(); + msg = message.getResponse(); } else { - resp = message; + msg = message; } - if (resp.isResponseMessage() && CanMessage.ACCESSORY_SWITCHING_RESP == resp.getCommand()) { - byte[] data = resp.getData(); + int cmd = msg.getCommand(); + int dlc = msg.getDlc(); + byte[] data = msg.getData(); + + if (CanMessage.ACCESSORY_SWITCHING_RESP == cmd || CanMessage.ACCESSORY_SWITCHING == cmd) { int address = data[3]; int position = data[4]; //CS is zero based address = address + 1; - String id = address + ""; - + String id = Integer.toString(address); AccessoryBean accessoryBean = new AccessoryBean(id, address, null, null, position, null, null, null, CanMessage.MARKLIN_COMMANDSTATION_ID); - if (resp.getDlc() == CanMessage.DLC_8) { + + //TODO DCC support + if (CanMessage.DLC_8 == dlc) { int switchTime = CanMessage.toInt(new byte[]{data[6], data[7]}); accessoryBean.setSwitchTime(switchTime); } - return new AccessoryEvent(accessoryBean); } else { - Logger.warn("Can't parse message, not an Accessory Response! " + resp); + Logger.warn("Can't parse message, not an Accessory Message! " + message); return null; } } diff --git a/src/main/java/jcs/commandStation/marklin/cs/can/parser/SystemStatus.java b/src/main/java/jcs/commandStation/marklin/cs/can/parser/SystemStatus.java index a255d97d..33c9e90f 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/can/parser/SystemStatus.java +++ b/src/main/java/jcs/commandStation/marklin/cs/can/parser/SystemStatus.java @@ -15,69 +15,28 @@ */ package jcs.commandStation.marklin.cs.can.parser; -import java.io.Serializable; import java.util.List; import jcs.commandStation.marklin.cs.can.CanMessage; -import jcs.util.ByteUtil; -import org.tinylog.Logger; /** - * - * @author Frans Jacobs + * SystemStatus parser */ -public class SystemStatus implements Serializable { - - private boolean power; - private byte[] gfpUid; - - public SystemStatus(CanMessage message) { - parseMessage(message); - } +public class SystemStatus { - //There might be more than 1 responses. - //when there are more use the one which contains a valid gfp uid - private void parseMessage(CanMessage message) { - if (message != null) { - CanMessage resp = null; - List respList = message.getResponses(); - if (respList.isEmpty()) { - Logger.warn("No response for: " + message); - gfpUid = message.getDeviceUidFromMessage(); - int status = message.getData()[4]; - power = status == 1; - } else { - for (CanMessage cm : respList) { - if (cm.isResponseMessage() && cm.isDeviceUidValid()) { - resp = cm; - } - } - if (resp == null) { - resp = message; - } - - if (CanMessage.SYSTEM_COMMAND_RESP == resp.getCommand() && resp.isDeviceUidValid()) { - byte[] data = resp.getData(); - gfpUid = resp.getDeviceUidFromMessage(); - int status = data[4]; - power = status == 1; + public static boolean parseSystemPowerMessage(CanMessage message) { + if (message == null) { + return false; + } + List respList = message.getResponses(); + if (respList.isEmpty()) { + return message.getData()[4] == 1; + } else { + for (CanMessage cm : respList) { + if (CanMessage.SYSTEM_COMMAND_RESP == cm.getCommand() && cm.getDlc() == CanMessage.DLC_5) { + return message.getData()[4] == 1; } } - } else { - power = false; - gfpUid = new byte[]{0, 0, 0, 0}; } - } - - @Override - public String toString() { - return "SystemStatus{" + " power: " + (power ? "On" : "Off") + " GFP UID: " + ByteUtil.toHexString(gfpUid) + " }"; - } - - public boolean isPower() { - return power; - } - - public byte[] getGfpUid() { - return gfpUid; + return false; } } diff --git a/src/main/java/jcs/commandStation/marklin/cs/net/CSConnectionFactory.java b/src/main/java/jcs/commandStation/marklin/cs/net/CSConnectionFactory.java index d17551a6..bf6d8307 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/net/CSConnectionFactory.java +++ b/src/main/java/jcs/commandStation/marklin/cs/net/CSConnectionFactory.java @@ -57,7 +57,10 @@ public class CSConnectionFactory { private static final String LAST_USED_IP_PROP_FILE = RunUtil.DEFAULT_PATH + "last-used-marklin-cs-ip.properties"; + private boolean forceVirtual = false; + private CSConnectionFactory() { + forceVirtual = "true".equals(System.getProperty("connection.always.virtual", "false")); } public static CSConnectionFactory getInstance() { @@ -67,54 +70,63 @@ public static CSConnectionFactory getInstance() { return instance; } - CSConnection getConnectionImpl() { - if (controllerConnection == null) { - - String lastUsedIp = RunUtil.readProperty(LAST_USED_IP_PROP_FILE, "ip-address"); - - if (lastUsedIp != null) { - try { - if (Ping.IsReachable(lastUsedIp)) { - controllerHost = InetAddress.getByName(lastUsedIp); - Logger.trace("Using last used IP Address: " + lastUsedIp); - } else { - Logger.trace("Last used IP Address: " + lastUsedIp + " is not reachable"); + CSConnection getConnectionImpl(boolean flag) { + boolean virtual = flag; + if (!virtual && forceVirtual) { + virtual = forceVirtual; + Logger.info("Forcing a virtual connection!"); + } + if (!virtual) { + if (controllerConnection == null) { + String lastUsedIp = RunUtil.readProperty(LAST_USED_IP_PROP_FILE, "ip-address"); + + if (lastUsedIp != null) { + try { + if (Ping.IsReachable(lastUsedIp)) { + controllerHost = InetAddress.getByName(lastUsedIp); + Logger.trace("Using last used IP Address: " + lastUsedIp); + } else { + Logger.trace("Last used IP Address: " + lastUsedIp + " is not reachable"); + } + } catch (UnknownHostException ex) { + Logger.trace("Last used CS IP: " + lastUsedIp + " is invalid!"); + lastUsedIp = null; } - } catch (UnknownHostException ex) { - Logger.trace("Last used CS IP: " + lastUsedIp + " is invalid!"); - lastUsedIp = null; } - } - if (controllerHost == null) { - Logger.trace("Try to discover a Marklin CS..."); - JCS.logProgress("Discovering a Marklin Central Station..."); - //First try with mdns - controllerHost = discoverCs(); if (controllerHost == null) { - //try the "old" way by sending a "ping" - controllerHost = sendMobileAppPing(); + Logger.trace("Try to discover a Marklin CS..."); + JCS.logProgress("Discovering a Marklin Central Station..."); + //First try with mdns + controllerHost = discoverCs(); + if (controllerHost == null) { + //try the "old" way by sending a "ping" + controllerHost = sendMobileAppPing(); + } } - } - if (controllerHost != null) { - if (lastUsedIp == null) { - //Write the last used IP Addres for faster discovery next time - RunUtil.writeProperty(LAST_USED_IP_PROP_FILE, "ip-address", controllerHost.getHostAddress()); - } - Logger.trace("CS ip: " + controllerHost.getHostName()); + if (controllerHost != null) { + if (lastUsedIp == null) { + //Write the last used IP Addres for faster discovery next time + RunUtil.writeProperty(LAST_USED_IP_PROP_FILE, "ip-address", controllerHost.getHostAddress()); + } + Logger.trace("CS ip: " + controllerHost.getHostName()); - controllerConnection = new CSTCPConnection(controllerHost); - } else { - Logger.warn("Can't find a Marklin Controller host!"); - JCS.logProgress("Can't find a Marklin Central Station on the Network"); + controllerConnection = new CSTCPConnection(controllerHost); + } else { + Logger.warn("Can't find a Marklin Controller host!"); + JCS.logProgress("Can't find a Marklin Central Station on the Network"); + } } + } else { + controllerConnection = new CSVirtualConnection(NetworkUtil.getIPv4HostAddress()); } + return this.controllerConnection; } - public static CSConnection getConnection() { - return getInstance().getConnectionImpl(); + public static CSConnection getConnection(boolean flag) { + return getInstance().getConnectionImpl(flag); } public static void disconnectAll() { @@ -130,18 +142,23 @@ public static void disconnectAll() { instance.controllerHost = null; } - CSHTTPConnection getHTTPConnectionImpl() { + CSHTTPConnection getHTTPConnectionImpl(boolean flag) { if (controllerConnection == null) { - getConnectionImpl(); + getConnectionImpl(flag); } if (httpConnection == null) { - httpConnection = new CSHTTPConnection(controllerHost); + if (!flag) { + httpConnection = new CSHTTPConnectionImpl(controllerHost); + } else { + httpConnection = new CSHTTPConnectionVirt(controllerHost); + + } } return httpConnection; } - public static CSHTTPConnection getHTTPConnection() { - return getInstance().getHTTPConnectionImpl(); + public static CSHTTPConnection getHTTPConnection(boolean flag) { + return getInstance().getHTTPConnectionImpl(flag); } /** diff --git a/src/main/java/jcs/commandStation/marklin/cs/net/CSHTTPConnection.java b/src/main/java/jcs/commandStation/marklin/cs/net/CSHTTPConnection.java old mode 100755 new mode 100644 index accdd806..3a9bd622 --- a/src/main/java/jcs/commandStation/marklin/cs/net/CSHTTPConnection.java +++ b/src/main/java/jcs/commandStation/marklin/cs/net/CSHTTPConnection.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Frans Jacobs. + * Copyright 2025 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,360 +16,33 @@ package jcs.commandStation.marklin.cs.net; import java.awt.Image; -import java.awt.image.BufferedImage; -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.InetAddress; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLConnection; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import javax.imageio.IIOException; -import javax.imageio.ImageIO; -import org.tinylog.Logger; -/** - * - * @author Frans Jacobs - */ -public class CSHTTPConnection { - - private final InetAddress csAddress; - private boolean cs3; - - private final static String HTTP = "http://"; - private final static String CONFIG = "/config/"; - private final static String LOCOMOTIVE = "lokomotive.cs2"; - private final static String LOCOMOTIVE_JSON = "/app/api/loks"; - - private final static String MAGNETARTIKEL = "magnetartikel.cs2"; - private final static String ACCESSORIES_URL = "/app/api/mags"; - - private final static String DEVICE = "geraet.vrs"; - - private final static String IMAGE_FOLDER_CS3 = "/app/assets/lok/"; - private final static String IMAGE_FOLDER_CS2 = "/icons/"; - private final static String FUNCTION_IMAGE_FOLDER = "/fcticons/"; - - private final static String FUNCTION_SVG_URL = "/images/svgSprites/fcticons.json"; - private final static String ACCESSORIES_SVG_URL = "/images/svgSprites/magicons.json"; - - private final static String CS3_INFO_JSON = "/app/api/info"; - private final static String DEVICES = "/app/api/devs"; +public interface CSHTTPConnection extends AutoCloseable { + + boolean isConnected(); + + void setCs3(boolean cs3); + + String getLocomotivesFile(); + + String getLocomotivesJSON(); + + String getAccessoriesFile(); + + String getFunctionsSvgJSON(); + + String getAccessoriesSvgJSON(); + + String getAccessoriesJSON(); + + String getDevicesJSON(); + + String getInfoFile(); + + String getInfoJSON(); + + Image getLocomotiveImage(String imageName); - //TODO: investigate the JSON which can be found on - // http://cs3host/images/svgSprites/magicons.json - // http://cs3host/app/api/loks - // http://cs3host/app/api/mags - // http://cs3host/app/api/info - // - CSHTTPConnection(InetAddress csAddress) { - this.csAddress = csAddress; - //Assume a CS2 - this.cs3 = false; - } - - public boolean isConnected() { - return csAddress != null && csAddress.getHostAddress() != null; - } - - public void setCs3(boolean cs3) { - this.cs3 = cs3; - Logger.trace("Changed Connection settings for a " + (cs3 ? "CS3" : "CS2")); - } - - private static String fixURL(String url) { - return url.replace(" ", "%20"); - } - - public String getLocomotivesFile() { - StringBuilder locs = new StringBuilder(); - try { - URL cs = new URL(HTTP + csAddress.getHostAddress() + CONFIG + LOCOMOTIVE); - URLConnection lc = cs.openConnection(); - try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { - String inputLine; - while ((inputLine = in.readLine()) != null) { - locs.append(inputLine.strip()); - locs.append("\n"); - } - } - } catch (MalformedURLException ex) { - Logger.error(ex); - } catch (IOException ex) { - Logger.error(ex); - } - return locs.toString(); - } - - public String getLocomotivesJSON() { - StringBuilder loks = new StringBuilder(); - try { - URL url = new URL(HTTP + csAddress.getHostAddress() + LOCOMOTIVE_JSON); - URLConnection lc = url.openConnection(); - try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { - String inputLine; - while ((inputLine = in.readLine()) != null) { - loks.append(inputLine.strip()); - loks.append("\n"); - } - } - } catch (MalformedURLException ex) { - Logger.error(ex); - } catch (IOException ex) { - Logger.error(ex); - } - return loks.toString(); - } - - public String getAccessoriesFile() { - StringBuilder locs = new StringBuilder(); - try { - URL url = new URL(HTTP + csAddress.getHostAddress() + CONFIG + MAGNETARTIKEL); - URLConnection lc = url.openConnection(); - try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { - String inputLine; - while ((inputLine = in.readLine()) != null) { - locs.append(inputLine.strip()); - locs.append("\n"); - } - } - } catch (MalformedURLException ex) { - Logger.error(ex); - } catch (IOException ex) { - Logger.error(ex); - } - return locs.toString(); - } - - public String getFunctionsSvgJSON() { - StringBuilder json = new StringBuilder(); - try { - URL url = new URL(HTTP + csAddress.getHostAddress() + FUNCTION_SVG_URL); - URLConnection lc = url.openConnection(); - try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { - String inputLine; - while ((inputLine = in.readLine()) != null) { - json.append(inputLine.strip()); - json.append("\n"); - } - } - } catch (MalformedURLException ex) { - Logger.error(ex); - } catch (IOException ex) { - Logger.error(ex); - } - return json.toString(); - } - - public String getAccessoriesSvgJSON() { - StringBuilder json = new StringBuilder(); - try { - URL url = new URL(HTTP + csAddress.getHostAddress() + ACCESSORIES_SVG_URL); - URLConnection lc = url.openConnection(); - try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { - String inputLine; - while ((inputLine = in.readLine()) != null) { - json.append(inputLine.strip()); - json.append("\n"); - } - } - } catch (MalformedURLException ex) { - Logger.error(ex); - } catch (IOException ex) { - Logger.error(ex); - } - return json.toString(); - } - - public String getAccessoriesJSON() { - StringBuilder json = new StringBuilder(); - try { - URL url = new URL(HTTP + csAddress.getHostAddress() + ACCESSORIES_URL); - URLConnection lc = url.openConnection(); - try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { - String inputLine; - while ((inputLine = in.readLine()) != null) { - json.append(inputLine.strip()); - json.append("\n"); - } - } - } catch (MalformedURLException ex) { - Logger.error(ex); - } catch (IOException ex) { - Logger.error(ex); - } - return json.toString(); - } - - public String getDevicesJSON() { - StringBuilder device = new StringBuilder(); - if (this.csAddress != null && csAddress.getHostAddress() != null) { - try { - URL url = new URL(HTTP + csAddress.getHostAddress() + DEVICES); - URLConnection lc = url.openConnection(); - try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { - String inputLine; - while ((inputLine = in.readLine()) != null) { - device.append(inputLine.strip()); - device.append("\n"); - } - } - } catch (MalformedURLException ex) { - Logger.error(ex); - } catch (IOException ex) { - Logger.error(ex); - } - } else { - Logger.warn("Not Connected to CS3!"); - } - return device.toString(); - } - - public String getInfoFile() { - StringBuilder device = new StringBuilder(); - try { - URL url = new URL(HTTP + csAddress.getHostAddress() + CONFIG + DEVICE); - URLConnection lc = url.openConnection(); - try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { - String inputLine; - while ((inputLine = in.readLine()) != null) { - device.append(inputLine.strip()); - device.append("\n"); - } - } - } catch (MalformedURLException ex) { - Logger.error(ex); - } catch (IOException ex) { - Logger.error(ex); - } - return device.toString(); - } - - public String getInfoJSON() { - StringBuilder device = new StringBuilder(); - if (this.csAddress != null && csAddress.getHostAddress() != null) { - try { - URL url = new URL(HTTP + csAddress.getHostAddress() + CS3_INFO_JSON); - URLConnection lc = url.openConnection(); - try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { - String inputLine; - while ((inputLine = in.readLine()) != null) { - device.append(inputLine.strip()); - device.append("\n"); - } - } - } catch (MalformedURLException ex) { - Logger.error(ex); - } catch (IOException ex) { - Logger.error(ex); - } - } else { - Logger.warn("Not Connected to CS3!"); - } - return device.toString(); - } - - public Image getLocomotiveImage(String imageName) { - BufferedImage image = null; - try { - URL url; - if (cs3) { - url = new URL(fixURL(HTTP + csAddress.getHostAddress() + IMAGE_FOLDER_CS3 + imageName + ".png")); - } else { - url = new URL(fixURL(HTTP + csAddress.getHostAddress() + IMAGE_FOLDER_CS2 + imageName + ".png")); - } - - Logger.trace("image URL: " + url); - image = ImageIO.read(url); - } catch (MalformedURLException ex) { - Logger.error(ex); - } catch (IOException ex) { - Logger.error(ex); - } - return image; - } - - public Image getFunctionImageCS2(String imageName) { - BufferedImage image = null; - String iurl = fixURL(HTTP + csAddress.getHostAddress() + FUNCTION_IMAGE_FOLDER + imageName + ".png"); - - try { - URL url = new URL(iurl); - image = ImageIO.read(url); - } catch (IIOException iio) { - //Image not avalable - Logger.warn("Image: " + iurl + " is not available"); - } catch (MalformedURLException ex) { - Logger.error(ex); - } catch (IOException ex) { - Logger.error(ex); - } - return image; - } - - public static void main(String[] args) throws Exception { - boolean cs3 = true; - - InetAddress inetAddr; - if (cs3) { - inetAddr = InetAddress.getByName("192.168.178.180"); - } else { - inetAddr = InetAddress.getByName("192.168.178.86"); - } - CSHTTPConnection hc = new CSHTTPConnection(inetAddr); - hc.setCs3(cs3); - - String serial; - if (cs3) { - serial = "2374"; - } else { - serial = "13344"; - } + Image getFunctionImageCS2(String imageName); -// Path fPath = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "cache" + File.separator + "zfunctions"); -// if (!Files.exists(fPath)) { -// Files.createDirectories(fPath); -// Logger.trace("Created new directory " + fPath); -// } -// -// Path aPath = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "cache" + File.separator + "zaccessories"); -// if (!Files.exists(aPath)) { -// Files.createDirectories(aPath); -// Logger.trace("Created new directory " + aPath); -// } - Path info = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "info.json"); - String json = hc.getInfoJSON(); - Files.writeString(info, json); - - Path devices = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "devices.json"); - json = hc.getDevicesJSON(); - Files.writeString(devices, json); - - Path locomotives = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "locomotives.json"); - json = hc.getLocomotivesJSON(); - Files.writeString(locomotives, json); - - Path accessories = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "mags.json"); - json = hc.getAccessoriesJSON(); - Files.writeString(accessories, json); - - Path fcticons = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "fcticons.json"); - json = hc.getFunctionsSvgJSON(); - Files.writeString(fcticons, json); - - Path magicons = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "magicons.json"); - json = hc.getAccessoriesSvgJSON(); - Files.writeString(magicons, json); - - Path accessoryFile = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "magnetartikel.cs2"); - String file = hc.getAccessoriesFile(); - Logger.trace(file); - Files.writeString(accessoryFile, file); - - } } diff --git a/src/main/java/jcs/commandStation/marklin/cs/net/CSHTTPConnectionImpl.java b/src/main/java/jcs/commandStation/marklin/cs/net/CSHTTPConnectionImpl.java new file mode 100755 index 00000000..90ac3453 --- /dev/null +++ b/src/main/java/jcs/commandStation/marklin/cs/net/CSHTTPConnectionImpl.java @@ -0,0 +1,392 @@ +/* + * Copyright 2023 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.commandStation.marklin.cs.net; + +import java.awt.Image; +import java.awt.image.BufferedImage; +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.InetAddress; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import javax.imageio.IIOException; +import javax.imageio.ImageIO; +import org.tinylog.Logger; + +/** + * + * @author Frans Jacobs + */ +public class CSHTTPConnectionImpl implements CSHTTPConnection { + + private final InetAddress csAddress; + private boolean cs3; + + private final static String HTTP = "http://"; + private final static String CONFIG = "/config/"; + private final static String LOCOMOTIVE = "lokomotive.cs2"; + private final static String LOCOMOTIVE_JSON = "/app/api/loks"; + + private final static String MAGNETARTIKEL = "magnetartikel.cs2"; + private final static String ACCESSORIES_URL = "/app/api/mags"; + + private final static String DEVICE = "geraet.vrs"; + + private final static String IMAGE_FOLDER_CS3 = "/app/assets/lok/"; + private final static String IMAGE_FOLDER_CS2 = "/icons/"; + private final static String FUNCTION_IMAGE_FOLDER = "/fcticons/"; + + private final static String FUNCTION_SVG_URL = "/images/svgSprites/fcticons.json"; + private final static String ACCESSORIES_SVG_URL = "/images/svgSprites/magicons.json"; + + private final static String CS3_INFO_JSON = "/app/api/info"; + private final static String DEVICES = "/app/api/devs"; + + //TODO: investigate the JSON which can be found on + // http://cs3host/images/svgSprites/magicons.json + // http://cs3host/app/api/loks + // http://cs3host/app/api/mags + // http://cs3host/app/api/info + // + CSHTTPConnectionImpl(InetAddress csAddress) { + this.csAddress = csAddress; + //Assume a CS2 + this.cs3 = false; + } + + @Override + public boolean isConnected() { + return csAddress != null && csAddress.getHostAddress() != null; + } + + @Override + public void setCs3(boolean cs3) { + this.cs3 = cs3; + Logger.trace("Changed Connection settings for a " + (cs3 ? "CS3" : "CS2")); + } + + private static String fixURL(String url) { + return url.replace(" ", "%20"); + } + + @Override + public String getLocomotivesFile() { + StringBuilder locs = new StringBuilder(); + try { + URL cs = new URL(HTTP + csAddress.getHostAddress() + CONFIG + LOCOMOTIVE); + URLConnection lc = cs.openConnection(); + try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { + String inputLine; + while ((inputLine = in.readLine()) != null) { + locs.append(inputLine.strip()); + locs.append("\n"); + } + } + } catch (MalformedURLException ex) { + Logger.error(ex); + } catch (IOException ex) { + Logger.error(ex); + } + return locs.toString(); + } + + @Override + public String getLocomotivesJSON() { + StringBuilder loks = new StringBuilder(); + try { + URL url = new URL(HTTP + csAddress.getHostAddress() + LOCOMOTIVE_JSON); + URLConnection lc = url.openConnection(); + try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { + String inputLine; + while ((inputLine = in.readLine()) != null) { + loks.append(inputLine.strip()); + loks.append("\n"); + } + } + } catch (MalformedURLException ex) { + Logger.error(ex); + } catch (IOException ex) { + Logger.error(ex); + } + return loks.toString(); + } + + @Override + public String getAccessoriesFile() { + StringBuilder locs = new StringBuilder(); + try { + URL url = new URL(HTTP + csAddress.getHostAddress() + CONFIG + MAGNETARTIKEL); + URLConnection lc = url.openConnection(); + try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { + String inputLine; + while ((inputLine = in.readLine()) != null) { + locs.append(inputLine.strip()); + locs.append("\n"); + } + } + } catch (MalformedURLException ex) { + Logger.error(ex); + } catch (IOException ex) { + Logger.error(ex); + } + return locs.toString(); + } + + @Override + public String getFunctionsSvgJSON() { + StringBuilder json = new StringBuilder(); + try { + URL url = new URL(HTTP + csAddress.getHostAddress() + FUNCTION_SVG_URL); + URLConnection lc = url.openConnection(); + try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { + String inputLine; + while ((inputLine = in.readLine()) != null) { + json.append(inputLine.strip()); + json.append("\n"); + } + } + } catch (MalformedURLException ex) { + Logger.error(ex); + } catch (IOException ex) { + Logger.error(ex); + } + return json.toString(); + } + + @Override + public String getAccessoriesSvgJSON() { + StringBuilder json = new StringBuilder(); + try { + URL url = new URL(HTTP + csAddress.getHostAddress() + ACCESSORIES_SVG_URL); + URLConnection lc = url.openConnection(); + try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { + String inputLine; + while ((inputLine = in.readLine()) != null) { + json.append(inputLine.strip()); + json.append("\n"); + } + } + } catch (MalformedURLException ex) { + Logger.error(ex); + } catch (IOException ex) { + Logger.error(ex); + } + return json.toString(); + } + + @Override + public String getAccessoriesJSON() { + StringBuilder json = new StringBuilder(); + try { + URL url = new URL(HTTP + csAddress.getHostAddress() + ACCESSORIES_URL); + URLConnection lc = url.openConnection(); + try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { + String inputLine; + while ((inputLine = in.readLine()) != null) { + json.append(inputLine.strip()); + json.append("\n"); + } + } + } catch (MalformedURLException ex) { + Logger.error(ex); + } catch (IOException ex) { + Logger.error(ex); + } + return json.toString(); + } + + @Override + public String getDevicesJSON() { + StringBuilder device = new StringBuilder(); + if (this.csAddress != null && csAddress.getHostAddress() != null) { + try { + URL url = new URL(HTTP + csAddress.getHostAddress() + DEVICES); + URLConnection lc = url.openConnection(); + try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { + String inputLine; + while ((inputLine = in.readLine()) != null) { + device.append(inputLine.strip()); + device.append("\n"); + } + } + } catch (MalformedURLException ex) { + Logger.error(ex); + } catch (IOException ex) { + Logger.error(ex); + } + } else { + Logger.warn("Not Connected to CS3!"); + } + return device.toString(); + } + + @Override + public String getInfoFile() { + StringBuilder device = new StringBuilder(); + try { + URL url = new URL(HTTP + csAddress.getHostAddress() + CONFIG + DEVICE); + URLConnection lc = url.openConnection(); + try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { + String inputLine; + while ((inputLine = in.readLine()) != null) { + device.append(inputLine.strip()); + device.append("\n"); + } + } + } catch (MalformedURLException ex) { + Logger.error(ex); + } catch (IOException ex) { + Logger.error(ex); + } + return device.toString(); + } + + @Override + public String getInfoJSON() { + StringBuilder device = new StringBuilder(); + if (this.csAddress != null && csAddress.getHostAddress() != null) { + try { + URL url = new URL(HTTP + csAddress.getHostAddress() + CS3_INFO_JSON); + URLConnection lc = url.openConnection(); + try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { + String inputLine; + while ((inputLine = in.readLine()) != null) { + device.append(inputLine.strip()); + device.append("\n"); + } + } + } catch (MalformedURLException ex) { + Logger.error(ex); + } catch (IOException ex) { + Logger.error(ex); + } + } else { + Logger.warn("Not Connected to CS3!"); + } + return device.toString(); + } + + @Override + public Image getLocomotiveImage(String imageName) { + BufferedImage image = null; + try { + URL url; + if (cs3) { + url = new URL(fixURL(HTTP + csAddress.getHostAddress() + IMAGE_FOLDER_CS3 + imageName + ".png")); + } else { + url = new URL(fixURL(HTTP + csAddress.getHostAddress() + IMAGE_FOLDER_CS2 + imageName + ".png")); + } + + Logger.trace("image URL: " + url); + image = ImageIO.read(url); + } catch (MalformedURLException ex) { + Logger.error(ex); + } catch (IOException ex) { + Logger.error(ex); + } + return image; + } + + @Override + public Image getFunctionImageCS2(String imageName) { + BufferedImage image = null; + String iurl = fixURL(HTTP + csAddress.getHostAddress() + FUNCTION_IMAGE_FOLDER + imageName + ".png"); + + try { + URL url = new URL(iurl); + image = ImageIO.read(url); + } catch (IIOException iio) { + //Image not avalable + Logger.warn("Image: " + iurl + " is not available"); + } catch (MalformedURLException ex) { + Logger.error(ex); + } catch (IOException ex) { + Logger.error(ex); + } + return image; + } + + @Override + public void close() throws Exception { + } + + public static void main(String[] args) throws Exception { + boolean cs3 = true; + + InetAddress inetAddr; + if (cs3) { + inetAddr = InetAddress.getByName("192.168.178.180"); + } else { + inetAddr = InetAddress.getByName("192.168.178.86"); + } + CSHTTPConnectionImpl hc = new CSHTTPConnectionImpl(inetAddr); + hc.setCs3(cs3); + + String serial; + if (cs3) { + serial = "2374"; + } else { + serial = "13344"; + } + +// Path fPath = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "cache" + File.separator + "zfunctions"); +// if (!Files.exists(fPath)) { +// Files.createDirectories(fPath); +// Logger.trace("Created new directory " + fPath); +// } +// +// Path aPath = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "cache" + File.separator + "zaccessories"); +// if (!Files.exists(aPath)) { +// Files.createDirectories(aPath); +// Logger.trace("Created new directory " + aPath); +// } + Path info = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "info.json"); + String json = hc.getInfoJSON(); + Files.writeString(info, json); + + Path devices = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "devices.json"); + json = hc.getDevicesJSON(); + Files.writeString(devices, json); + + Path locomotives = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "locomotives.json"); + json = hc.getLocomotivesJSON(); + Files.writeString(locomotives, json); + + Path accessories = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "mags.json"); + json = hc.getAccessoriesJSON(); + Files.writeString(accessories, json); + + Path fcticons = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "fcticons.json"); + json = hc.getFunctionsSvgJSON(); + Files.writeString(fcticons, json); + + Path magicons = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "magicons.json"); + json = hc.getAccessoriesSvgJSON(); + Files.writeString(magicons, json); + + Path accessoryFile = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "magnetartikel.cs2"); + String file = hc.getAccessoriesFile(); + Logger.trace(file); + Files.writeString(accessoryFile, file); + + } +} diff --git a/src/main/java/jcs/commandStation/marklin/cs/net/CSHTTPConnectionVirt.java b/src/main/java/jcs/commandStation/marklin/cs/net/CSHTTPConnectionVirt.java new file mode 100644 index 00000000..a3d9039f --- /dev/null +++ b/src/main/java/jcs/commandStation/marklin/cs/net/CSHTTPConnectionVirt.java @@ -0,0 +1,587 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.commandStation.marklin.cs.net; + +import java.awt.Image; +import java.awt.image.BufferedImage; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.InetAddress; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import javax.imageio.IIOException; +import javax.imageio.ImageIO; +import org.tinylog.Logger; + +/** + * + * Virtual HTTP Connection for Simulator mode + */ +public class CSHTTPConnectionVirt implements CSHTTPConnection { + + private final InetAddress csAddress; + private boolean cs3; + + private final static String HTTP = "http://"; + private final static String CONFIG = "/config/"; + private final static String LOCOMOTIVE = "lokomotive.cs2"; + private final static String LOCOMOTIVE_JSON = "/app/api/loks"; + + private final static String MAGNETARTIKEL = "magnetartikel.cs2"; + private final static String ACCESSORIES_URL = "/app/api/mags"; + + private final static String DEVICE = "geraet.vrs"; + + private final static String IMAGE_FOLDER_CS3 = "/app/assets/lok/"; + private final static String IMAGE_FOLDER_CS2 = "/icons/"; + private final static String FUNCTION_IMAGE_FOLDER = "/fcticons/"; + + private final static String FUNCTION_SVG_URL = "/images/svgSprites/fcticons.json"; + private final static String ACCESSORIES_SVG_URL = "/images/svgSprites/magicons.json"; + + private final static String CS3_INFO_JSON = "/app/api/info"; + private final static String DEVICES = "/app/api/devs"; + + public CSHTTPConnectionVirt(InetAddress csAddress) { + this.csAddress = csAddress; + //Assume a CS2 + this.cs3 = false; + } + + @Override + public boolean isConnected() { + return csAddress != null && csAddress.getHostAddress() != null; + } + + @Override + public void setCs3(boolean cs3) { + this.cs3 = cs3; + Logger.trace("Changed Connection settings for a " + (cs3 ? "CS3" : "CS2")); + } + + private static String fixURL(String url) { + return url.replace(" ", "%20"); + } + + @Override + public String getLocomotivesFile() { + StringBuilder locs = new StringBuilder(); + try { + URL cs = new URL(HTTP + csAddress.getHostAddress() + CONFIG + LOCOMOTIVE); + URLConnection lc = cs.openConnection(); + try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { + String inputLine; + while ((inputLine = in.readLine()) != null) { + locs.append(inputLine.strip()); + locs.append("\n"); + } + } + } catch (MalformedURLException ex) { + Logger.error(ex); + } catch (IOException ex) { + Logger.error(ex); + } + return locs.toString(); + } + + @Override + public String getLocomotivesJSON() { + StringBuilder loks = new StringBuilder(); + try { + URL url = new URL(HTTP + csAddress.getHostAddress() + LOCOMOTIVE_JSON); + URLConnection lc = url.openConnection(); + try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { + String inputLine; + while ((inputLine = in.readLine()) != null) { + loks.append(inputLine.strip()); + loks.append("\n"); + } + } + } catch (MalformedURLException ex) { + Logger.error(ex); + } catch (IOException ex) { + Logger.error(ex); + } + return loks.toString(); + } + + @Override + public String getAccessoriesFile() { + StringBuilder locs = new StringBuilder(); + try { + URL url = new URL(HTTP + csAddress.getHostAddress() + CONFIG + MAGNETARTIKEL); + URLConnection lc = url.openConnection(); + try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { + String inputLine; + while ((inputLine = in.readLine()) != null) { + locs.append(inputLine.strip()); + locs.append("\n"); + } + } + } catch (MalformedURLException ex) { + Logger.error(ex); + } catch (IOException ex) { + Logger.error(ex); + } + return locs.toString(); + } + + @Override + public String getFunctionsSvgJSON() { + StringBuilder json = new StringBuilder(); + try { + URL url = new URL(HTTP + csAddress.getHostAddress() + FUNCTION_SVG_URL); + URLConnection lc = url.openConnection(); + try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { + String inputLine; + while ((inputLine = in.readLine()) != null) { + json.append(inputLine.strip()); + json.append("\n"); + } + } + } catch (MalformedURLException ex) { + Logger.error(ex); + } catch (IOException ex) { + Logger.error(ex); + } + return json.toString(); + } + + @Override + public String getAccessoriesSvgJSON() { + StringBuilder json = new StringBuilder(); + try { + URL url = new URL(HTTP + csAddress.getHostAddress() + ACCESSORIES_SVG_URL); + URLConnection lc = url.openConnection(); + try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { + String inputLine; + while ((inputLine = in.readLine()) != null) { + json.append(inputLine.strip()); + json.append("\n"); + } + } + } catch (MalformedURLException ex) { + Logger.error(ex); + } catch (IOException ex) { + Logger.error(ex); + } + return json.toString(); + } + + @Override + public String getAccessoriesJSON() { + StringBuilder json = new StringBuilder(); + try { + URL url = new URL(HTTP + csAddress.getHostAddress() + ACCESSORIES_URL); + URLConnection lc = url.openConnection(); + try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { + String inputLine; + while ((inputLine = in.readLine()) != null) { + json.append(inputLine.strip()); + json.append("\n"); + } + } + } catch (MalformedURLException ex) { + Logger.error(ex); + } catch (IOException ex) { + Logger.error(ex); + } + return json.toString(); + } + + @Override + public String getDevicesJSON() { + StringBuilder json = new StringBuilder(); + json.append("{"); + json.append("\"0x8\": {"); + json.append("\"_uid\": \"0x8\","); + json.append("\"_name\": \"USB 0\","); + json.append("\"_kennung\": \"0xffff\","); + json.append("\"_typ\": \"65280\","); + json.append("\"_queryInterval\": \"5\","); + json.append("\"_version\": {"); + json.append("\"major\": \"16\""); + json.append("},"); + json.append("\"_kanal\": [],"); + json.append("\"_ready\": true,"); + json.append("\"path\": \"/media/usb0\","); + json.append("\"isPresent\": true,"); + json.append("\"isMounted\": true"); + json.append("},"); + json.append("\"0x9\": {"); + json.append("\"_uid\": \"0x9\","); + json.append("\"_name\": \"USB 1\","); + json.append("\"_kennung\": \"0xffff\","); + json.append("\"_typ\": \"65280\","); + json.append("\"_queryInterval\": \"5\","); + json.append("\"_version\": {"); + json.append("\"major\": \"77\""); + json.append("},"); + json.append("\"_kanal\": [],"); + json.append("\"_ready\": true,"); + json.append("\"path\": \"/media/usb1\","); + json.append("\"isPresent\": true,"); + json.append("\"isMounted\": true"); + json.append("},"); + json.append("\"0x53385c41\": {"); + json.append("\"_uid\": \"0x53385c41\","); + json.append("\"_name\": \"LinkS88-1\","); + json.append("\"_typname\": \"Link S88\","); + json.append("\"_kennung\": \"0x41\","); + json.append("\"_typ\": \"64\","); + json.append("\"_artikelnr\": \"60883\","); + json.append("\"_seriennr\": \"9281\","); + json.append("\"_queryInterval\": \"5\","); + json.append("\"_version\": {"); + json.append("\"major\": \"1\","); + json.append("\"minor\": \"1\""); + json.append("},"); + json.append("\"_kanal\": ["); + json.append("{"); + json.append("\"endWert\": \"8\","); + json.append("\"max\": \"8\","); + json.append("\"name\": \"Spalten Tastatur\","); + json.append("\"nr\": \"11\","); + json.append("\"startWert\": \"0\","); + json.append("\"typ\": \"2\","); + json.append("\"valueHuman\": \"0\""); + json.append("},"); + json.append("{"); + json.append("\"endWert\": \"15\","); + json.append("\"max\": \"15\","); + json.append("\"name\": \"Zeilen Tastatur\","); + json.append("\"nr\": \"12\","); + json.append("\"startWert\": \"0\","); + json.append("\"typ\": \"2\","); + json.append("\"valueHuman\": \"0\""); + json.append("},"); + json.append("{"); + json.append("\"auswahl\": \"Einzeln:Tastaturmatrix\","); + json.append("\"name\": \"Auswertung 1 - 16\","); + json.append("\"nr\": \"1\","); + json.append("\"typ\": \"1\","); + json.append("\"valueHuman\": \"0\""); + json.append("},"); + json.append("{"); + json.append("\"endWert\": \"31\","); + json.append("\"max\": \"31\","); + json.append("\"name\": \"Länge Bus 1 (RJ45-1)\","); + json.append("\"nr\": \"2\","); + json.append("\"startWert\": \"0\","); + json.append("\"typ\": \"2\","); + json.append("\"wert\": \"1\","); + json.append("\"valueHuman\": \"0\""); + json.append("},"); + json.append("{"); + json.append("\"endWert\": \"31\","); + json.append("\"max\": \"31\","); + json.append("\"name\": \"Länge Bus 2 (RJ45-2)\","); + json.append("\"nr\": \"3\","); + json.append("\"startWert\": \"0\","); + json.append("\"typ\": \"2\","); + json.append("\"wert\": \"2\","); + json.append("\"valueHuman\": \"0\""); + json.append("},"); + json.append("{"); + json.append("\"endWert\": \"31\","); + json.append("\"max\": \"31\","); + json.append("\"name\": \"Länge Bus 3 (6-Polig)\","); + json.append("\"nr\": \"4\","); + json.append("\"startWert\": \"0\","); + json.append("\"typ\": \"2\","); + json.append("\"wert\": \"1\","); + json.append("\"valueHuman\": \"0\""); + json.append("},"); + json.append("{"); + json.append("\"einheit\": \"ms\","); + json.append("\"endWert\": \"1000\","); + json.append("\"max\": \"1000\","); + json.append("\"min\": \"10\","); + json.append("\"name\": \"Zykluszeit Bus 1 (RJ45-1)\","); + json.append("\"nr\": \"5\","); + json.append("\"startWert\": \"10\","); + json.append("\"typ\": \"2\","); + json.append("\"wert\": \"100\","); + json.append("\"valueHuman\": \"0\""); + json.append("},"); + json.append("{"); + json.append("\"einheit\": \"ms\","); + json.append("\"endWert\": \"1000\","); + json.append("\"max\": \"1000\","); + json.append("\"min\": \"10\","); + json.append("\"name\": \"Zykluszeit Bus 2 (RJ45-2)\","); + json.append("\"nr\": \"6\","); + json.append("\"startWert\": \"10\","); + json.append("\"typ\": \"2\","); + json.append("\"wert\": \"100\","); + json.append("\"valueHuman\": \"0\""); + json.append("},"); + json.append("{"); + json.append("\"einheit\": \"ms\","); + json.append("\"endWert\": \"1000\","); + json.append("\"max\": \"1000\","); + json.append("\"min\": \"10\","); + json.append("\"name\": \"Zykluszeit Bus 3 (6-Polig)\","); + json.append("\"nr\": \"7\","); + json.append("\"startWert\": \"10\","); + json.append("\"typ\": \"2\","); + json.append("\"wert\": \"100\","); + json.append("\"valueHuman\": \"0\""); + json.append("},"); + json.append("{"); + json.append("\"einheit\": \"µs\","); + json.append("\"endWert\": \"1000\","); + json.append("\"max\": \"1000\","); + json.append("\"min\": \"100\","); + json.append("\"name\": \"Bitzeit S88\","); + json.append("\"nr\": \"8\","); + json.append("\"startWert\": \"100\","); + json.append("\"typ\": \"2\","); + json.append("\"wert\": \"167\","); + json.append("\"valueHuman\": \"0\""); + json.append("},"); + json.append("{"); + json.append("\"einheit\": \"ms\","); + json.append("\"endWert\": \"1000\","); + json.append("\"max\": \"1000\","); + json.append("\"min\": \"10\","); + json.append("\"name\": \"Zykluszeit 1 - 16\","); + json.append("\"nr\": \"9\","); + json.append("\"startWert\": \"10\","); + json.append("\"typ\": \"2\","); + json.append("\"wert\": \"100\","); + json.append("\"valueHuman\": \"0\""); + json.append("},"); + json.append("{"); + json.append("\"einheit\": \"ms\","); + json.append("\"endWert\": \"100\","); + json.append("\"max\": \"100\","); + json.append("\"min\": \"10\","); + json.append("\"name\": \"Zykluszeit Tastatur\","); + json.append("\"nr\": \"10\","); + json.append("\"startWert\": \"10\","); + json.append("\"typ\": \"2\","); + json.append("\"wert\": \"37\","); + json.append("\"valueHuman\": \"0\""); + json.append("}"); + json.append("],"); + json.append("\"_ready\": false,"); + json.append("\"isPresent\": true,"); + json.append("\"present\": \"1\","); + json.append("\"config\": \"12;ok\""); + json.append("},"); + json.append("\"0x6373458c\": {"); + json.append("\"_uid\": \"0x6373458c\","); + json.append("\"_name\": \"GFP3-1\","); + json.append("\"_typname\": \"Central Station 3\","); + json.append("\"_kennung\": \"0xffff\","); + json.append("\"_typ\": \"80\","); + json.append("\"_artikelnr\": \"60226\","); + json.append("\"_seriennr\": \"0000\","); + json.append("\"_queryInterval\": \"5\","); + json.append("\"_version\": {"); + json.append("\"major\": \"12\","); + json.append("\"minor\": \"113\""); + json.append("},"); + json.append("\"_kanal\": ["); + json.append("{"); + json.append("\"einheit\": \"A\","); + json.append("\"endWert\": \"5.50\","); + json.append("\"farbeGelb\": \"240\","); + json.append("\"farbeGruen\": \"48\","); + json.append("\"farbeMax\": \"192\","); + json.append("\"farbeRot\": \"22\","); + json.append("\"name\": \"MAIN\","); + json.append("\"nr\": \"1\","); + json.append("\"potenz\": \"253\","); + json.append("\"rangeGelb\": \"576\","); + json.append("\"rangeGruen\": \"552\","); + json.append("\"rangeMax\": \"660\","); + json.append("\"rangeRot\": \"600\","); + json.append("\"startWert\": \"0.00\","); + json.append("\"valueHuman\": \"0\""); + json.append("},"); + json.append("{"); + json.append("\"einheit\": \"A\","); + json.append("\"endWert\": \"2.30\","); + json.append("\"farbeGelb\": \"240\","); + json.append("\"farbeGruen\": \"48\","); + json.append("\"farbeMax\": \"192\","); + json.append("\"farbeRot\": \"224\","); + json.append("\"name\": \"PROG\","); + json.append("\"nr\": \"2\","); + json.append("\"potenz\": \"253\","); + json.append("\"rangeGelb\": \"363\","); + json.append("\"rangeGruen\": \"330\","); + json.append("\"rangeMax\": \"759\","); + json.append("\"rangeRot\": \"561\","); + json.append("\"startWert\": \"0.00\","); + json.append("\"valueHuman\": \"0\""); + json.append("},"); + json.append("{"); + json.append("\"einheit\": \"C\","); + json.append("\"endWert\": \"80.0\","); + json.append("\"farbeGelb\": \"8\","); + json.append("\"farbeGruen\": \"12\","); + json.append("\"farbeMax\": \"192\","); + json.append("\"farbeRot\": \"240\","); + json.append("\"name\": \"TEMP\","); + json.append("\"nr\": \"4\","); + json.append("\"rangeGelb\": \"145\","); + json.append("\"rangeGruen\": \"121\","); + json.append("\"rangeMax\": \"193\","); + json.append("\"rangeRot\": \"169\","); + json.append("\"startWert\": \"0.0\","); + json.append("\"valueHuman\": \"0\""); + json.append("},"); + json.append("{"); + json.append("\"auswahl\": \"60061:60101:L51095\","); + json.append("\"index\": \"1\","); + json.append("\"name\": \"Netzteil:\","); + json.append("\"nr\": \"1\","); + json.append("\"typ\": \"1\","); + json.append("\"valueHuman\": \"0\""); + json.append("}"); + json.append("],"); + json.append("\"_ready\": true,"); + json.append("\"isPresent\": true"); + json.append("},"); + json.append("\"0x6373458d\": {"); + json.append("\"_uid\": \"0x6373458d\","); + json.append("\"_name\": \"CS3 0000\","); + json.append("\"_typ\": \"65504\","); + json.append("\"_kanal\": [],"); + json.append("\"_ready\": true,"); + json.append("\"ip\": \"127.0.0.1\","); + json.append("\"isPresent\": true"); + json.append("},"); + json.append("}"); + + return json.toString(); + } + + @Override + public String getInfoFile() { + StringBuilder geraet = new StringBuilder(); + geraet.append("[geraet]\n"); + geraet.append("version\n"); + geraet.append(".major=0\n"); + geraet.append(".minor=1\n"); + geraet.append("geraet\n"); + geraet.append(".sernum=0000\n"); + geraet.append(".gfpuid=6373458c\n"); + geraet.append(".guiuid=6373458d\n"); + geraet.append(".hardvers=HW:03.04\n"); + geraet.append(".articleno=60226\n"); + geraet.append(".producer=Frans Jacobs.\n"); + geraet.append(".produkt=Virtual Central Station 3\n"); + + return geraet.toString(); + } + + @Override + public String getInfoJSON() { + StringBuilder json = new StringBuilder(); + json.append("{"); + json.append("\"softwareVersion\""); + json.append(":"); + json.append("\"2.5.1 (0)\""); + json.append(","); + + json.append("\"hardwareVersion\""); + json.append(":"); + json.append("\"HW:03.04\""); + json.append(","); + + json.append("\"serialNumber\""); + json.append(":"); + json.append("\"0000\""); + json.append(","); + + json.append("\"productName\""); + json.append(":"); + json.append("\"Virtual Central Station 3\""); + json.append(","); + + json.append("\"articleNumber\""); + json.append(":"); + json.append("\"60226\""); + json.append(","); + + json.append("\"hostname\""); + json.append(":"); + json.append("\"CS3-00000\""); + json.append(","); + + json.append("\"gfpUid\""); + json.append(":"); + json.append("\"6373458c\""); + json.append(","); + + json.append("\"guiUid\""); + json.append(":"); + json.append("\"6373458d\""); + json.append("}"); + return json.toString(); + } + + @Override + public Image getLocomotiveImage(String imageName) { + BufferedImage image = null; + try { + URL url; + if (cs3) { + url = new URL(fixURL(HTTP + csAddress.getHostAddress() + IMAGE_FOLDER_CS3 + imageName + ".png")); + } else { + url = new URL(fixURL(HTTP + csAddress.getHostAddress() + IMAGE_FOLDER_CS2 + imageName + ".png")); + } + + Logger.trace("image URL: " + url); + image = ImageIO.read(url); + } catch (MalformedURLException ex) { + Logger.error(ex); + } catch (IOException ex) { + Logger.error(ex); + } + return image; + } + + @Override + public Image getFunctionImageCS2(String imageName) { + BufferedImage image = null; + String iurl = fixURL(HTTP + csAddress.getHostAddress() + FUNCTION_IMAGE_FOLDER + imageName + ".png"); + + try { + URL url = new URL(iurl); + image = ImageIO.read(url); + } catch (IIOException iio) { + //Image not avalable + Logger.warn("Image: " + iurl + " is not available"); + } catch (MalformedURLException ex) { + Logger.error(ex); + } catch (IOException ex) { + Logger.error(ex); + } + return image; + } + + @Override + public void close() throws Exception { + } + +} diff --git a/src/main/java/jcs/commandStation/marklin/cs/net/CSTCPConnection.java b/src/main/java/jcs/commandStation/marklin/cs/net/CSTCPConnection.java index cd660b93..1dc50456 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/net/CSTCPConnection.java +++ b/src/main/java/jcs/commandStation/marklin/cs/net/CSTCPConnection.java @@ -99,7 +99,7 @@ private void disconnect() { Logger.trace(ex); } } - + disconnectionEventListeners.clear(); if (clientSocket != null) { try { @@ -112,6 +112,7 @@ private void disconnect() { } private class ResponseCallback { + private final CanMessage tx; private boolean done = false; @@ -203,6 +204,19 @@ public synchronized CanMessage sendCanMessage(CanMessage message) { messageReceiver.unRegisterResponseCallback(); } + //Capture messages for now to be able to develop the virtual mode + Logger.trace("#TX: " + message + " is response " + message.isResponseMessage()); + if (!message.isResponseMessage()) { + if (message.getResponses().size() > 1) { + List responses = message.getResponses(); + for (int i = 0; i < responses.size(); i++) { + Logger.trace("#RX " + i + ": " + message.getResponse(i)); + } + } else { + Logger.trace("#RX: " + message.getResponse()); + } + } + return message; } diff --git a/src/main/java/jcs/commandStation/marklin/cs/net/CSVirtualConnection.java b/src/main/java/jcs/commandStation/marklin/cs/net/CSVirtualConnection.java new file mode 100644 index 00000000..4e33e1ff --- /dev/null +++ b/src/main/java/jcs/commandStation/marklin/cs/net/CSVirtualConnection.java @@ -0,0 +1,252 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.commandStation.marklin.cs.net; + +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.LinkedTransferQueue; +import java.util.concurrent.TransferQueue; +import jcs.commandStation.VirtualConnection; +import jcs.commandStation.events.DisconnectionEvent; +import jcs.commandStation.events.DisconnectionEventListener; +import jcs.commandStation.events.SensorEvent; +import jcs.commandStation.marklin.cs.can.CanMessage; +import jcs.commandStation.marklin.cs.can.parser.SystemStatus; +import org.tinylog.Logger; + +/** + * Virtual Marklin CS Connection + */ +class CSVirtualConnection implements CSConnection, VirtualConnection { + + private boolean connected; + + private final InetAddress centralStationAddress; + + private PeriodicCSMessageSender periodicMessageSender; + private final List disconnectionEventListeners; + + private final TransferQueue eventQueue; + + CSVirtualConnection(InetAddress csAddress) { + centralStationAddress = csAddress; + eventQueue = new LinkedTransferQueue<>(); + //disconnectionEventListeners = new ArrayList<>(); + disconnectionEventListeners = Collections.synchronizedList(new ArrayList<>()); + this.connected = true; + + //initMessageSender(); + } + + @Override + public void sendEvent(SensorEvent sensorEvent) { + //Virtual + } + + private void initMessageSender() { + periodicMessageSender = new PeriodicCSMessageSender(); + periodicMessageSender.start(); + //periodicMessageSender.setDaemon(true); + } + + @Override + public TransferQueue getEventQueue() { + return this.eventQueue; + } + + @Override + public void addDisconnectionEventListener(DisconnectionEventListener listener) { + this.disconnectionEventListeners.add(listener); + } + + private void disconnect() { + this.connected = false; + if (periodicMessageSender != null) { + periodicMessageSender.quit(); + } + disconnectionEventListeners.clear(); + } + + @Override + public synchronized CanMessage sendCanMessage(CanMessage message) { + if (message == null) { + Logger.warn("Message is NULL?"); + return null; + } + + int command = message.getCommand(); + int dlc = message.getDlc(); + int uid = message.getDeviceUidNumberFromMessage(); + int subcmd = message.getSubCommand(); + + Logger.trace("TX: " + message); + + switch (command) { + case CanMessage.SYSTEM_COMMAND -> { + switch (subcmd) { + case CanMessage.STOP_SUB_CMD -> { + if (dlc == 4) { + //Power status Query, reply with On + message.addResponse(CanMessage.parse("0x00 0x01 0x03 0x26 0x05 0x63 0x73 0x45 0x8c 0x01 0x00 0x00 0x00")); + message.addResponse(CanMessage.parse("0x00 0x01 0x03 0x26 0x05 0x00 0x00 0x00 0x00 0x01 0x00 0x00 0x00")); + } else if (dlc == 5) { + if (SystemStatus.parseSystemPowerMessage(message)) { + message.addResponse(CanMessage.parse("0x00 0x01 0x03 0x26 0x05 0x63 0x73 0x45 0x8c 0x01 0x00 0x00 0x00")); + message.addResponse(CanMessage.parse("0x00 0x01 0x03 0x26 0x05 0x00 0x00 0x00 0x00 0x01 0x00 0x00 0x00")); + } else { + //Switch Power Off + message.addResponse(CanMessage.parse("0x00 0x01 0x03 0x26 0x05 0x63 0x73 0x45 0x8c 0x00 0x00 0x00 0x00")); + message.addResponse(CanMessage.parse("0x00 0x01 0x03 0x26 0x05 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00")); + } + } + } + case CanMessage.GO_SUB_CMD -> { + } + case CanMessage.HALT_SUB_CMD -> { + } + case CanMessage.LOC_STOP_SUB_CMD -> { + } + case CanMessage.OVERLOAD_SUB_CMD -> { + } + } + + } + case CanMessage.PING_REQ -> { + //Lets do this the when we know all of the CS... +// if (mainDevice != null) { +// if (CanMessage.DLC_0 == dlc) { +// Logger.trace("Ping RQ: " + eventMessage); +// sendJCSUIDMessage(); +// } +// } + } + case CanMessage.PING_RESP -> { +// if (CanMessage.DLC_8 == dlc) { +// Logger.trace("Ping Response RX: " + eventMessage); +// +// updateDevice(eventMessage); +// } + } + case CanMessage.STATUS_CONFIG -> { +// if (CanMessage.JCS_UID == uid && CanMessage.DLC_5 == dlc) { +// Logger.trace("StatusConfig RQ: " + eventMessage); +// sentJCSInformationMessage(); +// } + } + case CanMessage.STATUS_CONFIG_RESP -> { + } + case CanMessage.S88_EVENT_RESPONSE -> { +// if (CanMessage.DLC_8 == dlc) { +// SensorBean sb = SensorMessageParser.parseMessage(eventMessage, new Date()); +// SensorEvent sme = new SensorEvent(sb); +// if (sme.getSensorBean() != null) { +// fireSensorEventListeners(sme); +// } +// } + } + case CanMessage.SYSTEM_COMMAND_RESP -> { + } + case CanMessage.ACCESSORY_SWITCHING -> { + message.addResponse(CanMessage.parse(message.toString(), true)); + } + case CanMessage.ACCESSORY_SWITCHING_RESP -> { + } + case CanMessage.LOC_VELOCITY -> { + message.addResponse(CanMessage.parse(message.toString(), true)); + } + case CanMessage.LOC_VELOCITY_RESP -> { + } + case CanMessage.LOC_DIRECTION -> { + message.addResponse(CanMessage.parse(message.toString(), true)); + } + case CanMessage.LOC_DIRECTION_RESP -> { + } + case CanMessage.LOC_FUNCTION -> { + message.addResponse(CanMessage.parse(message.toString(), true)); + } + case CanMessage.LOC_FUNCTION_RESP -> { + } + default -> { + } + } + return message; + } + + @Override + public void close() throws Exception { + disconnect(); + } + + @Override + public InetAddress getControllerAddress() { + return centralStationAddress; + } + + @Override + public boolean isConnected() { + return this.connected; + } + + private class PeriodicCSMessageSender extends Thread { + + private boolean quit = true; + + public PeriodicCSMessageSender() { + } + + synchronized void quit() { + quit = true; + } + + synchronized boolean isRunning() { + return !quit; + } + + @Override + public void run() { + Thread.currentThread().setName("CS-VIRT-CAN-TX"); + + quit = false; + Logger.trace("Started sending periodic messages..."); + while (isRunning()) { + //Send a ping requests once and a while + CanMessage ping = CanMessage.parse("0x00 0x30 0x37 0x7e 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00"); + eventQueue.offer(ping); + Logger.trace("Enqueued: " + ping + " QueueSize: " + eventQueue.size()); + + synchronized (this) { + try { + wait(5000); + } catch (InterruptedException ex) { + Logger.trace(ex); + } + } + } + + String msg = "Host " + centralStationAddress.getHostName(); + DisconnectionEvent de = new DisconnectionEvent(msg); + for (DisconnectionEventListener listener : disconnectionEventListeners) { + listener.onDisconnect(de); + } + + Logger.trace("Stop sending"); + + } + } +} + diff --git a/src/main/java/jcs/commandStation/marklin/cs2/AccessoryBeanParser.java b/src/main/java/jcs/commandStation/marklin/cs2/AccessoryBeanParser.java index 945f8576..723648ef 100755 --- a/src/main/java/jcs/commandStation/marklin/cs2/AccessoryBeanParser.java +++ b/src/main/java/jcs/commandStation/marklin/cs2/AccessoryBeanParser.java @@ -67,7 +67,7 @@ public static List parseAccessoryFile(String file, String command } ab = new AccessoryBean(); ab.setSynchronize(true); - ab.setSource(source + ":"+MAGNETARTIKEL); + ab.setSource(source + ":" + MAGNETARTIKEL); ab.setCommandStationId(commandStationId); } case ".name" -> { @@ -165,7 +165,7 @@ public static List parseAccessoryJSON(String json, String command for (int i = 0; i < aa.length(); i++) { AccessoryBean ab = new AccessoryBean(); ab.setSynchronize(true); - ab.setSource(source + ":"+MAGS_JSON); + ab.setSource(source + ":" + MAGS_JSON); ab.setCommandStationId(commandStationId); JSONObject ajo = aa.getJSONObject(i); @@ -199,26 +199,25 @@ public static List parseAccessoryJSON(String json, String command return accessories; } - public static void main(String[] a) throws Exception { - - Path accessoryFile = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "magnetartikel.cs2"); - String file = Files.readString(accessoryFile); - List accessories = AccessoryBeanParser.parseAccessoryFile(file, "marklin.cs", "CS"); - for (AccessoryBean acc : accessories) { - Logger.trace(acc.toLogString()); - } - Logger.trace("Total " + accessories.size()); - - Path accessoryJson = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "mags.json"); - - String json = Files.readString(accessoryJson); - accessories = AccessoryBeanParser.parseAccessoryJSON(json, "marklin.cs", "CS"); - - for (AccessoryBean acc : accessories) { - Logger.trace(acc.toLogString()); - } - Logger.trace("Total " + accessories.size()); - - } - +// public static void main(String[] a) throws Exception { +// +// Path accessoryFile = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "magnetartikel.cs2"); +// String file = Files.readString(accessoryFile); +// List accessories = AccessoryBeanParser.parseAccessoryFile(file, "marklin.cs", "CS"); +// for (AccessoryBean acc : accessories) { +// Logger.trace(acc.toLogString()); +// } +// Logger.trace("Total " + accessories.size()); +// +// Path accessoryJson = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "mags.json"); +// +// String json = Files.readString(accessoryJson); +// accessories = AccessoryBeanParser.parseAccessoryJSON(json, "marklin.cs", "CS"); +// +// for (AccessoryBean acc : accessories) { +// Logger.trace(acc.toLogString()); +// } +// Logger.trace("Total " + accessories.size()); +// +// } } diff --git a/src/main/java/jcs/commandStation/marklin/cs3/DeviceJSONParser.java b/src/main/java/jcs/commandStation/marklin/cs3/DeviceJSONParser.java index 5b85c61d..b73893c2 100644 --- a/src/main/java/jcs/commandStation/marklin/cs3/DeviceJSONParser.java +++ b/src/main/java/jcs/commandStation/marklin/cs3/DeviceJSONParser.java @@ -15,16 +15,10 @@ */ package jcs.commandStation.marklin.cs3; -import java.io.File; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; -import jcs.entities.ChannelBean; import jcs.commandStation.entities.DeviceBean; import org.json.JSONObject; -import org.tinylog.Logger; /** * @@ -48,30 +42,32 @@ public static List parse(String json) { return devices; } - public static void main(String[] a) throws Exception { - Path path = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "devices.json"); - - String devicesFile = Files.readString(path); - - List devices = DeviceJSONParser.parse(devicesFile); - +// public static void main(String[] a) throws Exception { +// Path path = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "devices.json"); +// +// CSHTTPConnectionVirt virtC = new CSHTTPConnectionVirt(null); +// +// //String devicesFile = Files.readString(path); +// +// String devicesFile = virtC.getDevicesJSON(); +// +// Logger.trace(devicesFile); +// +// List devices = DeviceJSONParser.parse(devicesFile); +// // for (DeviceBean dev : devices) { -// Logger.trace(dev); +// if (dev.isFeedbackDevice()) { +// Logger.trace(dev); +// +// List cbl = dev.getChannels(); +// for (ChannelBean cb : cbl) { +// if (cb.isS88Bus()) { +// Logger.debug(cb); +// } +// } +// +// } // } - - for (DeviceBean dev : devices) { - if (dev.isFeedbackDevice()) { - Logger.trace(dev); - - List cbl = dev.getChannels(); - for (ChannelBean cb : cbl) { - if (cb.isS88Bus()) { - Logger.debug(cb); - } - } - - } - } - - } +// +// } } diff --git a/src/main/java/jcs/commandStation/marklin/cs3/LocomotiveBeanJSONParser.java b/src/main/java/jcs/commandStation/marklin/cs3/LocomotiveBeanJSONParser.java index d67ea1d8..5bba0e09 100644 --- a/src/main/java/jcs/commandStation/marklin/cs3/LocomotiveBeanJSONParser.java +++ b/src/main/java/jcs/commandStation/marklin/cs3/LocomotiveBeanJSONParser.java @@ -15,10 +15,6 @@ */ package jcs.commandStation.marklin.cs3; -import java.io.File; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; import java.util.LinkedList; import java.util.List; import jcs.entities.FunctionBean; @@ -144,17 +140,17 @@ public List parseLocomotives(String json) { return this.locomotives; } - public static void main(String[] a) throws Exception { - Path path = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "locomotives.json"); - - String loksFile = Files.readString(path); - - LocomotiveBeanJSONParser lp = new LocomotiveBeanJSONParser(); - List locs = lp.parseLocomotives(loksFile); - - for (LocomotiveBean loc : locs) { - Logger.trace(loc); - } - } +// public static void main(String[] a) throws Exception { +// Path path = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "locomotives.json"); +// +// String loksFile = Files.readString(path); +// +// LocomotiveBeanJSONParser lp = new LocomotiveBeanJSONParser(); +// List locs = lp.parseLocomotives(loksFile); +// +// for (LocomotiveBean loc : locs) { +// Logger.trace(loc); +// } +// } } diff --git a/src/main/java/jcs/ui/JCSFrame.form b/src/main/java/jcs/ui/JCSFrame.form index 9c5ed621..0b57c4d5 100755 --- a/src/main/java/jcs/ui/JCSFrame.form +++ b/src/main/java/jcs/ui/JCSFrame.form @@ -904,13 +904,7 @@
- - - - - - diff --git a/src/main/java/jcs/ui/JCSFrame.java b/src/main/java/jcs/ui/JCSFrame.java index b75af53d..528d57fa 100755 --- a/src/main/java/jcs/ui/JCSFrame.java +++ b/src/main/java/jcs/ui/JCSFrame.java @@ -902,6 +902,7 @@ private void showOverviewBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_ private void powerButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_powerButtonActionPerformed boolean on = ((JToggleButton) evt.getSource()).isSelected(); + Logger.trace("Switch Power "+(on?"On":"Off")); if (JCS.getJcsCommandStation() != null) { JCS.getJcsCommandStation().switchPower(on); } diff --git a/src/test/java/jcs/commandStation/marklin/cs/net/CSConnectionFactoryTest.java b/src/test/java/jcs/commandStation/marklin/cs/net/CSConnectionFactoryTest.java index fb7c9190..93191c41 100644 --- a/src/test/java/jcs/commandStation/marklin/cs/net/CSConnectionFactoryTest.java +++ b/src/test/java/jcs/commandStation/marklin/cs/net/CSConnectionFactoryTest.java @@ -60,7 +60,7 @@ public void testGetConnectionImpl() { System.out.println("getConnectionImpl"); CSConnectionFactory instance = null; CSConnection expResult = null; - CSConnection result = instance.getConnectionImpl(); + CSConnection result = instance.getConnectionImpl(true); assertEquals(expResult, result); // TODO review the generated test code and remove the default call to fail. fail("The test case is a prototype."); @@ -73,7 +73,7 @@ public void testGetConnectionImpl() { public void testGetConnection() { System.out.println("getConnection"); CSConnection expResult = null; - CSConnection result = CSConnectionFactory.getConnection(); + CSConnection result = CSConnectionFactory.getConnection(true); assertEquals(expResult, result); // TODO review the generated test code and remove the default call to fail. fail("The test case is a prototype."); @@ -98,7 +98,7 @@ public void testGetHTTPConnectionImpl() { System.out.println("getHTTPConnectionImpl"); CSConnectionFactory instance = null; CSHTTPConnection expResult = null; - CSHTTPConnection result = instance.getHTTPConnectionImpl(); + CSHTTPConnection result = instance.getHTTPConnectionImpl(true); assertEquals(expResult, result); // TODO review the generated test code and remove the default call to fail. fail("The test case is a prototype."); @@ -111,7 +111,7 @@ public void testGetHTTPConnectionImpl() { public void testGetHTTPConnection() { System.out.println("getHTTPConnection"); CSHTTPConnection expResult = null; - CSHTTPConnection result = CSConnectionFactory.getHTTPConnection(); + CSHTTPConnection result = CSConnectionFactory.getHTTPConnection(true); assertEquals(expResult, result); // TODO review the generated test code and remove the default call to fail. fail("The test case is a prototype."); From 16df4f885fbe92f5fdfb6c26929e3c3f44a7cad7 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Mon, 3 Mar 2025 21:00:08 +0100 Subject: [PATCH 28/70] Adding Tests for Marklin Feedback some minor refactoring --- .../jcs/commandStation/entities/InfoBean.java | 52 +++++++- .../marklin/cs/MarklinCentralStationImpl.java | 22 ++-- .../marklin/cs/can/CanMessageFactory.java | 31 ++++- ...ssageParser.java => AccessoryMessage.java} | 4 +- .../can/parser/FeedbackEventMessage.java} | 10 +- .../marklin/cs/net/CSVirtualConnection.java | 27 ++++ src/main/java/jcs/entities/SensorBean.java | 9 +- .../ecos/EsuEcosCommandStationImplTest.java | 2 - .../marklin/cs/MarklinCSTest.java | 8 +- .../marklin/cs/SensorEventTest.java | 108 ---------------- .../can/parser/FeedbackEventMessageTest.java | 120 ++++++++++++++++++ 11 files changed, 261 insertions(+), 132 deletions(-) rename src/main/java/jcs/commandStation/marklin/cs/can/parser/{AccessoryMessageParser.java => AccessoryMessage.java} (96%) rename src/main/java/jcs/commandStation/marklin/{cs2/SensorMessageParser.java => cs/can/parser/FeedbackEventMessage.java} (86%) delete mode 100755 src/test/java/jcs/commandStation/marklin/cs/SensorEventTest.java create mode 100755 src/test/java/jcs/commandStation/marklin/cs/can/parser/FeedbackEventMessageTest.java diff --git a/src/main/java/jcs/commandStation/entities/InfoBean.java b/src/main/java/jcs/commandStation/entities/InfoBean.java index 20b87228..79674298 100644 --- a/src/main/java/jcs/commandStation/entities/InfoBean.java +++ b/src/main/java/jcs/commandStation/entities/InfoBean.java @@ -16,6 +16,7 @@ package jcs.commandStation.entities; import jakarta.persistence.Transient; +import java.util.Objects; import jcs.entities.CommandStationBean; /** @@ -29,7 +30,6 @@ public class InfoBean extends CommandStationBean { private String productName; private String articleNumber; private String hostname; - private String ipAddress; private String gfpUid; private String guiUid; @@ -145,4 +145,54 @@ public String toString() { return "InfoBean{" + "softwareVersion=" + softwareVersion + ", hardwareVersion=" + hardwareVersion + ", serialNumber=" + serialNumber + ", productName=" + productName + ", articleNumber=" + articleNumber + ", hostname=" + hostname + ", gfpUid=" + gfpUid + ", guiUid=" + guiUid + "}"; } + @Override + public int hashCode() { + int hash = 3; + hash = 97 * hash + Objects.hashCode(this.softwareVersion); + hash = 97 * hash + Objects.hashCode(this.hardwareVersion); + hash = 97 * hash + Objects.hashCode(this.serialNumber); + hash = 97 * hash + Objects.hashCode(this.productName); + hash = 97 * hash + Objects.hashCode(this.articleNumber); + hash = 97 * hash + Objects.hashCode(this.hostname); + hash = 97 * hash + Objects.hashCode(this.gfpUid); + hash = 97 * hash + Objects.hashCode(this.guiUid); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final InfoBean other = (InfoBean) obj; + if (!Objects.equals(this.softwareVersion, other.softwareVersion)) { + return false; + } + if (!Objects.equals(this.hardwareVersion, other.hardwareVersion)) { + return false; + } + if (!Objects.equals(this.serialNumber, other.serialNumber)) { + return false; + } + if (!Objects.equals(this.productName, other.productName)) { + return false; + } + if (!Objects.equals(this.articleNumber, other.articleNumber)) { + return false; + } + if (!Objects.equals(this.hostname, other.hostname)) { + return false; + } + if (!Objects.equals(this.gfpUid, other.gfpUid)) { + return false; + } + return Objects.equals(this.guiUid, other.guiUid); + } + } diff --git a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java index 04775bb8..06e1c21c 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java +++ b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java @@ -15,6 +15,7 @@ */ package jcs.commandStation.marklin.cs; +import jcs.commandStation.marklin.cs.can.parser.FeedbackEventMessage; import java.awt.Image; import java.util.Date; import java.util.HashMap; @@ -59,14 +60,13 @@ import jcs.entities.CommandStationBean; import jcs.commandStation.entities.DeviceBean; import jcs.commandStation.entities.InfoBean; -import jcs.commandStation.marklin.cs.can.parser.AccessoryMessageParser; +import jcs.commandStation.marklin.cs.can.parser.AccessoryMessage; import jcs.entities.FeedbackModuleBean; import jcs.commandStation.marklin.cs2.InfoBeanParser; import jcs.commandStation.marklin.cs2.LocomotiveDirectionEventParser; import jcs.commandStation.marklin.cs2.LocomotiveFunctionEventParser; import jcs.commandStation.marklin.cs2.LocomotiveSpeedEventParser; import jcs.commandStation.marklin.cs2.PowerEventParser; -import jcs.commandStation.marklin.cs2.SensorMessageParser; import jcs.commandStation.VirtualConnection; import jcs.commandStation.events.DisconnectionEvent; import jcs.commandStation.events.DisconnectionEventListener; @@ -614,7 +614,7 @@ public void switchAccessory(Integer address, AccessoryValue value, Integer switc st = st / 10; CanMessage message = sendMessage(CanMessageFactory.switchAccessory(address, value, true, st, this.csUid)); //Notify listeners - AccessoryEvent ae = AccessoryMessageParser.parse(message); + AccessoryEvent ae = AccessoryMessage.parse(message); notifyAccessoryEventListeners(ae); } else { @@ -834,14 +834,14 @@ public void run() { //Lets do this the when we know all of the CS... if (mainDevice != null) { if (CanMessage.DLC_0 == dlc) { - Logger.trace("Answering Ping RQ: " + eventMessage); + //Logger.trace("Answering Ping RQ: " + eventMessage); sendJCSUIDMessage(); } } } case CanMessage.PING_RESP -> { if (CanMessage.DLC_8 == dlc) { - Logger.trace("Ping Response RX: " + eventMessage); + //Logger.trace("Ping Response RX: " + eventMessage); updateDevice(eventMessage); } @@ -857,7 +857,9 @@ public void run() { } case CanMessage.S88_EVENT_RESPONSE -> { if (CanMessage.DLC_8 == dlc) { - SensorBean sb = SensorMessageParser.parseMessage(eventMessage, new Date()); + Logger.trace("FeedbackSensorEvent RX: " + eventMessage); + + SensorBean sb = FeedbackEventMessage.parse(eventMessage, new Date()); SensorEvent sme = new SensorEvent(sb); if (sme.getSensorBean() != null) { fireSensorEventListeners(sme); @@ -866,7 +868,7 @@ public void run() { } case CanMessage.SX1_EVENT -> { if (CanMessage.DLC_8 == dlc) { - SensorBean sb = SensorMessageParser.parseMessage(eventMessage, new Date()); + SensorBean sb = FeedbackEventMessage.parse(eventMessage, new Date()); SensorEvent sme = new SensorEvent(sb); if (sme.getSensorBean() != null) { fireSensorEventListeners(sme); @@ -875,6 +877,10 @@ public void run() { } case CanMessage.SYSTEM_COMMAND -> { Logger.trace("SystemConfigCommand RX: " + eventMessage); + +//;/p + + } case CanMessage.SYSTEM_COMMAND_RESP -> { switch (subcmd) { @@ -904,7 +910,7 @@ public void run() { Logger.trace("AccessorySwitching RX: " + eventMessage); } case CanMessage.ACCESSORY_SWITCHING_RESP -> { - AccessoryEvent ae = AccessoryMessageParser.parse(eventMessage); + AccessoryEvent ae = AccessoryMessage.parse(eventMessage); if (ae.isValid()) { notifyAccessoryEventListeners(ae); } diff --git a/src/main/java/jcs/commandStation/marklin/cs/can/CanMessageFactory.java b/src/main/java/jcs/commandStation/marklin/cs/can/CanMessageFactory.java index 73008318..3fcd1827 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/can/CanMessageFactory.java +++ b/src/main/java/jcs/commandStation/marklin/cs/can/CanMessageFactory.java @@ -402,6 +402,32 @@ public static CanMessage requestConfigData(int gfpUid, String dataName) { return cm; } + /** + * Create a CanMessage for an (virtual) event. Used for the Virtual drive simulator + * + * @param sensorbean + * @return + */ + public static CanMessage sensorEventMessage(int nodeId, int contactId, int value, int previousValue, int millis, int uid) { + byte[] data = new byte[CanMessage.DATA_SIZE]; + + byte[] nId = CanMessage.to2Bytes(nodeId); + byte[] cId = CanMessage.to2Bytes(contactId); + byte val = (byte) value; + byte prev = (byte) previousValue; + byte[] time = CanMessage.to2Bytes(millis / 10); + byte[] hash = CanMessage.generateHash(uid); + + System.arraycopy(nId, 0, data, 0, nId.length); + System.arraycopy(cId, 0, data, 2, cId.length); + data[4] = prev; + data[5] = val; + System.arraycopy(time, 0, data, 6, time.length); + + CanMessage sensorMessage = new CanMessage(PRIO_1, S88_EVENT_RESPONSE, hash, DLC_8, data); + return sensorMessage; + } + //Mainly for testing.... public static void main(String[] a) { System.out.println("getMobAppPingReq: " + getMobileAppPingRequest()); @@ -420,10 +446,9 @@ public static void main(String[] a) { System.out.println("switchAccessory 1g: " + switchAccessory(1, AccessoryValue.RED, true, 1668498828)); - System.out.println("switchAccessory 2g: " + switchAccessory(2, AccessoryValue.GREEN, true,50, 1668498828)); - System.out.println("switchAccessory 2r: " + switchAccessory(2, AccessoryValue.RED, true,50, 1668498828)); + System.out.println("switchAccessory 2g: " + switchAccessory(2, AccessoryValue.GREEN, true, 50, 1668498828)); + System.out.println("switchAccessory 2r: " + switchAccessory(2, AccessoryValue.RED, true, 50, 1668498828)); - System.out.println("requestConfigData: " + requestConfigData(1668498828, "loks")); System.out.println(""); diff --git a/src/main/java/jcs/commandStation/marklin/cs/can/parser/AccessoryMessageParser.java b/src/main/java/jcs/commandStation/marklin/cs/can/parser/AccessoryMessage.java similarity index 96% rename from src/main/java/jcs/commandStation/marklin/cs/can/parser/AccessoryMessageParser.java rename to src/main/java/jcs/commandStation/marklin/cs/can/parser/AccessoryMessage.java index 42255419..e88d4c1d 100644 --- a/src/main/java/jcs/commandStation/marklin/cs/can/parser/AccessoryMessageParser.java +++ b/src/main/java/jcs/commandStation/marklin/cs/can/parser/AccessoryMessage.java @@ -20,9 +20,9 @@ import jcs.entities.AccessoryBean; import org.tinylog.Logger; -public class AccessoryMessageParser { +public class AccessoryMessage { - private AccessoryMessageParser() { + private AccessoryMessage() { } diff --git a/src/main/java/jcs/commandStation/marklin/cs2/SensorMessageParser.java b/src/main/java/jcs/commandStation/marklin/cs/can/parser/FeedbackEventMessage.java similarity index 86% rename from src/main/java/jcs/commandStation/marklin/cs2/SensorMessageParser.java rename to src/main/java/jcs/commandStation/marklin/cs/can/parser/FeedbackEventMessage.java index e3b29c82..93d65443 100644 --- a/src/main/java/jcs/commandStation/marklin/cs2/SensorMessageParser.java +++ b/src/main/java/jcs/commandStation/marklin/cs/can/parser/FeedbackEventMessage.java @@ -13,21 +13,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package jcs.commandStation.marklin.cs2; +package jcs.commandStation.marklin.cs.can.parser; import java.util.Date; import jcs.commandStation.marklin.cs.can.CanMessage; +import jcs.commandStation.marklin.cs.can.CanMessage; import jcs.entities.SensorBean; import jcs.util.ByteUtil; import org.tinylog.Logger; /** * - * @author Frans Jacobs + * Parse Sensor messages */ -public class SensorMessageParser { +public class FeedbackEventMessage { - public static SensorBean parseMessage(CanMessage message, Date eventDate) { + public static SensorBean parse(CanMessage message, Date eventDate) { CanMessage resp; if (!message.isResponseMessage()) { resp = message.getResponse(); @@ -52,4 +53,5 @@ public static SensorBean parseMessage(CanMessage message, Date eventDate) { return null; } } + } diff --git a/src/main/java/jcs/commandStation/marklin/cs/net/CSVirtualConnection.java b/src/main/java/jcs/commandStation/marklin/cs/net/CSVirtualConnection.java index 4e33e1ff..6b364787 100644 --- a/src/main/java/jcs/commandStation/marklin/cs/net/CSVirtualConnection.java +++ b/src/main/java/jcs/commandStation/marklin/cs/net/CSVirtualConnection.java @@ -158,6 +158,33 @@ public synchronized CanMessage sendCanMessage(CanMessage message) { // fireSensorEventListeners(sme); // } // } + +//0x00 0x23 0x7b 0x79 0x08 0x00 0x41 0x00 0x01 0x00 0x01 0xe5 0x10 +//0x00 0x23 0x7b 0x79 0x08 0x00 0x41 0x00 0x01 0x01 0x00 0x00 0x32 +//0x00 0x23 0x7b 0x79 0x08 0x00 0x41 0x00 0x02 0x00 0x01 0xab 0x68 +// +//0x00 0x23 0x7b 0x79 0x08 0x00 0x41 0x00 0x02 0x00 0x01 0xab 0x68 0x00 0x23 0x7b 0x79 0x08 0x00 0x41 0x00 0x0f 0x00 0x01 0xff 0xff +//0x00 0x23 0x7b 0x79 0x08 0x00 0x41 0x00 0x0f 0x01 0x00 0x01 0x90 +//0x00 0x23 0x7b 0x79 0x08 0x00 0x41 0x00 0x10 0x00 0x01 0xe3 0x3a +//0x00 0x23 0x7b 0x79 0x08 0x00 0x41 0x00 0x10 0x01 0x00 0x00 0x8c +// +//0x00 0x23 0x7b 0x79 0x08 0x00 0x41 0x07 0xd1 0x01 0x00 0x00 0xb4 +//0x00 0x23 0x7b 0x79 0x08 0x00 0x41 0x07 0xe0 0x00 0x01 0xdc 0xf0 +//0x00 0x23 0x7b 0x79 0x08 0x00 0x41 0x07 0xe0 0x01 0x00 0x00 0x50 + + +//0x00 0x23 0x7b 0x79 0x08 0x00 0x41 0x03 0xee 0x00 0x01 0x40 0xf6 +//0x00 0x23 0x7b 0x79 0x08 0x00 0x41 0x03 0xee 0x01 0x00 0x00 0x0a +//0x00 0x23 0x7b 0x79 0x08 0x00 0x41 0x03 0xf0 0x00 0x01 0x42 0x5d +//0x00 0x23 0x7b 0x79 0x08 0x00 0x41 0x03 0xf0 0x01 0x00 0x00 0x0a +//0x00 0x23 0x7b 0x79 0x08 0x00 0x41 0x03 0xf0 0x00 0x01 0x00 0x82 +//0x00 0x23 0x7b 0x79 0x08 0x00 0x41 0x03 0xf0 0x01 0x00 0x00 0x0a +//0x00 0x23 0x7b 0x79 0x08 0x00 0x41 0x03 0xf0 0x00 0x01 0x00 0x46 +//0x00 0x23 0x7b 0x79 0x08 0x00 0x41 0x03 0xf0 0x01 0x00 0x00 0x0a + + + + } case CanMessage.SYSTEM_COMMAND_RESP -> { } diff --git a/src/main/java/jcs/entities/SensorBean.java b/src/main/java/jcs/entities/SensorBean.java index 4f341f8f..7ec90c05 100755 --- a/src/main/java/jcs/entities/SensorBean.java +++ b/src/main/java/jcs/entities/SensorBean.java @@ -292,9 +292,16 @@ public String toString() { } public String toLogString() { + String ids; + if (id == null) { + ids = "(" + generateId() + ")"; + } else { + ids = id; + } + return "SensorBean{" + "id=" - + id + + ids + ", name=" + name + ", deviceId=" diff --git a/src/test/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImplTest.java b/src/test/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImplTest.java index b66b492a..cd326a9f 100644 --- a/src/test/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImplTest.java +++ b/src/test/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImplTest.java @@ -17,7 +17,6 @@ import java.util.ArrayList; import java.util.List; -import java.util.logging.Level; import jcs.commandStation.entities.DeviceBean; import jcs.commandStation.entities.InfoBean; import jcs.entities.AccessoryBean; @@ -28,7 +27,6 @@ import jcs.persistence.PersistenceFactory; import jcs.persistence.util.PersistenceTestHelper; import jcs.util.NetworkUtil; -import org.junit.Before; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/src/test/java/jcs/commandStation/marklin/cs/MarklinCSTest.java b/src/test/java/jcs/commandStation/marklin/cs/MarklinCSTest.java index b9a7f20c..6a659f55 100644 --- a/src/test/java/jcs/commandStation/marklin/cs/MarklinCSTest.java +++ b/src/test/java/jcs/commandStation/marklin/cs/MarklinCSTest.java @@ -21,6 +21,7 @@ import org.junit.After; import static org.junit.Assert.*; import org.junit.Before; +import org.junit.Test; import org.junit.jupiter.api.AfterAll; import org.tinylog.Logger; @@ -58,9 +59,10 @@ public MarklinCSTest() { csb.setProtocols("DCC,MFX,MM"); csb.setDefault(true); csb.setEnabled(true); + csb.setVirtual(true); instance = new MarklinCentralStationImpl(csb, false); - pause(500); + pause(200); csAvailable = instance.connect(); if (csAvailable) { @@ -77,7 +79,7 @@ public MarklinCSTest() { @Before public void setUp() { if (csAvailable) { - pause(500); + pause(200); } else { Logger.warn("Skipping tests CS not available"); } @@ -91,7 +93,7 @@ public void tearDown() { /** * Test of connect method, of class MarklinCentralStationImpl. */ - //@Test + @Test public void testConnect() { if (csAvailable) { System.out.println("connect"); diff --git a/src/test/java/jcs/commandStation/marklin/cs/SensorEventTest.java b/src/test/java/jcs/commandStation/marklin/cs/SensorEventTest.java deleted file mode 100755 index 45db9d75..00000000 --- a/src/test/java/jcs/commandStation/marklin/cs/SensorEventTest.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2023 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.commandStation.marklin.cs; - -import jcs.commandStation.marklin.cs.can.CanMessage; -import org.junit.After; -import org.junit.Before; - -/** - * - * @author fransjacobs - */ -public class SensorEventTest { - - private CanMessage message; - - public SensorEventTest() { - } - - @Before - public void setUp() { - message = new CanMessage(new byte[]{0x00, 0x23, (byte)0xcb, 0x12, 0x08, 0x00, 0x00, 0x00, 0x30, 0x00, 0x01, 0x0f, 0x59}); - } - - @After - public void tearDown() { - } - - /** - * Test of isNewValue method, of class FeedbackEventStatus. - */ -// @Test -// public void testIsNewValue() { -// System.out.println("isNewValue"); -// SensorMessageEvent instance = new SensorMessageEvent(message); -// boolean expResult = true; -// boolean result = instance.isNewValue(); -// assertEquals(expResult, result); -// } - /** - * Test of isOldValue method, of class FeedbackEventStatus. - */ -// @Test -// public void testIsOldValue() { -// System.out.println("isOldValue"); -// SensorMessageEvent instance = new SensorMessageEvent(message); -// boolean expResult = false; -// boolean result = instance.isOldValue(); -// assertEquals(expResult, result); -// } - /** - * Test of getContactId method, of class FeedbackEventStatus. - */ -// @Test -// public void testGetContactId() { -// System.out.println("getContactId"); -// SensorMessageEvent instance = new SensorMessageEvent(message); -// int expResult = 48; -// int result = instance.getContactId(); -// assertEquals(expResult, result); -// } - /** - * Test of getDeviceId method, of class FeedbackEventStatus. - */ -// @Test -// public void testGetDeviceId() { -// System.out.println("getDeviceId"); -// SensorMessageEvent instance = new SensorMessageEvent(message); -// int expResult = 0; -// int result = instance.getDeviceId(); -// assertEquals(expResult, result); -// } - /** - * Test of getMillis method, of class FeedbackEventStatus. - */ -// @Test -// public void testGetMillis() { -// System.out.println("getMillis"); -// SensorMessageEvent instance = new SensorMessageEvent(message); -// int expResult = 39290; -// int result = instance.getMillis(); -// assertEquals(expResult, result); -// } - /** - * Test of toString method, of class FeedbackEventStatus. - */ -// @Test -// public void testToString() { -// System.out.println("toString"); -// SensorMessageEvent instance = new SensorMessageEvent(message); -// String expResult = "SensorEvent{contactId: 48 deviceId: 0 value: true prevValue: false millis: 39290}"; -// String result = instance.toString(); -// assertEquals(expResult, result); -// } -} diff --git a/src/test/java/jcs/commandStation/marklin/cs/can/parser/FeedbackEventMessageTest.java b/src/test/java/jcs/commandStation/marklin/cs/can/parser/FeedbackEventMessageTest.java new file mode 100755 index 00000000..3286c3b1 --- /dev/null +++ b/src/test/java/jcs/commandStation/marklin/cs/can/parser/FeedbackEventMessageTest.java @@ -0,0 +1,120 @@ +/* + * Copyright 2023 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.commandStation.marklin.cs.can.parser; + +import java.util.Date; +import jcs.commandStation.marklin.cs.can.CanMessage; +import jcs.commandStation.marklin.cs.can.CanMessageFactory; +import jcs.entities.SensorBean; +import static org.junit.Assert.assertEquals; +import org.junit.Test; + +/** + * + */ +public class FeedbackEventMessageTest { + + public FeedbackEventMessageTest() { + } + + @Test + public void test65_bus0() { + System.out.println("65-bus0"); + Date now = new Date(); + + CanMessage msg1on = CanMessage.parse("0x00 0x23 0x7b 0x79 0x08 0x00 0x41 0x00 0x01 0x00 0x01 0xe5 0x10"); + CanMessage msg1off = CanMessage.parse("0x00 0x23 0x7b 0x79 0x08 0x00 0x41 0x00 0x01 0x01 0x00 0x00 0x32"); + + CanMessage msg2on = CanMessage.parse("0x00 0x23 0x7b 0x79 0x08 0x00 0x41 0x00 0x02 0x00 0x01 0xab 0x68"); + CanMessage msg2off = CanMessage.parse("0x00 0x23 0x7b 0x79 0x08 0x00 0x41 0x00 0x02 0x01 0x00 0x00 0x46"); + + SensorBean result1on = FeedbackEventMessage.parse(msg1on, now); + SensorBean result1off = FeedbackEventMessage.parse(msg1off, now); + + SensorBean result2on = FeedbackEventMessage.parse(msg2on, now); + SensorBean result2off = FeedbackEventMessage.parse(msg2off, now); + + SensorBean expResult1on = new SensorBean(65, 1, 1, 0, 586400, now); + SensorBean expResult1off = new SensorBean(65, 1, 0, 1, 500, now); + + SensorBean expResult2on = new SensorBean(65, 2, 1, 0, 438800, now); + SensorBean expResult2off = new SensorBean(65, 2, 0, 1, 700, now); + + assertEquals(expResult1on, result1on); + assertEquals(expResult1off, result1off); + assertEquals(expResult2on, result2on); + assertEquals(expResult2off, result2off); + } + + @Test + public void test65_bus1() { + System.out.println("65-bus1"); + Date now = new Date(); + + CanMessage msg1001on = CanMessage.parse("0x00 0x23 0x7b 0x79 0x08 0x00 0x41 0x03 0xe9 0x00 0x01 0x00 0x0a"); + CanMessage msg1001off = CanMessage.parse("0x00 0x23 0x7b 0x79 0x08 0x00 0x41 0x03 0xe9 0x01 0x00 0x00 0x0a"); + + SensorBean result1001on = FeedbackEventMessage.parse(msg1001on, now); + SensorBean result1001off = FeedbackEventMessage.parse(msg1001off, now); + + SensorBean expResult1001on = new SensorBean(65, 1001, 1, 0, 100, now); + SensorBean expResult1001off = new SensorBean(65, 1001, 0, 1, 100, now); + + //System.out.println(result1001off.toLogString()); + assertEquals(expResult1001on, result1001on); + assertEquals(expResult1001off, result1001off); + } + + @Test + public void test65_bus2() { + System.out.println("65-bus2"); + Date now = new Date(); + + CanMessage msg2001on = CanMessage.parse("0x00 0x23 0x7b 0x79 0x08 0x00 0x41 0x07 0xd1 0x00 0x01 0xdc 0xf0"); + CanMessage msg2001off = CanMessage.parse("0x00 0x23 0x7b 0x79 0x08 0x00 0x41 0x07 0xd1 0x01 0x00 0x00 0xb4"); + + SensorBean result2001on = FeedbackEventMessage.parse(msg2001on, now); + SensorBean result2001off = FeedbackEventMessage.parse(msg2001off, now); + + SensorBean expResult2001on = new SensorBean(65, 2001, 1, 0, 565600, now); + SensorBean expResult2001off = new SensorBean(65, 2001, 0, 1, 1800, now); + + //System.out.println(result2001on.toLogString()); + assertEquals(expResult2001on, result2001on); + assertEquals(expResult2001off, result2001off); + } + + @Test + public void test65_bus3() { + System.out.println("65-bus3"); + Date now = new Date(); + + //53385c41 -> 1396202561 uid link S88 + CanMessage msg3001on = CanMessageFactory.sensorEventMessage(65, 3001, 1, 0, 10000, 1396202561); + CanMessage msg3001off = CanMessageFactory.sensorEventMessage(65, 3001, 0, 1, 400, 1396202561); + + SensorBean result3001on = FeedbackEventMessage.parse(msg3001on, now); + SensorBean result3001off = FeedbackEventMessage.parse(msg3001off, now); + + SensorBean expResult3001on = new SensorBean(65, 3001, 1, 0, 10000, now); + SensorBean expResult3001off = new SensorBean(65, 3001, 0, 1, 400, now); + + //System.out.println(result3001on.toLogString()); + assertEquals(expResult3001on, result3001on); + assertEquals(expResult3001off, result3001off); + } + +} From 3c4cede2459bc9525893b45edaa7054d49717b90 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Thu, 6 Mar 2025 20:09:09 +0100 Subject: [PATCH 29/70] Marklin CS Virtual mode implemented --- src/main/java/jcs/JCS.java | 3 +- .../commandStation/JCSCommandStationImpl.java | 37 ++++++++-------- .../esu/ecos/EsuEcosCommandStationImpl.java | 7 +--- .../marklin/cs/MarklinCentralStationImpl.java | 42 +++++++++++++------ .../marklin/cs/can/parser/SystemStatus.java | 3 +- .../marklin/cs/net/CSVirtualConnection.java | 33 +++++++++++---- src/main/java/jcs/ui/JCSFrame.form | 7 +++- src/main/java/jcs/ui/JCSFrame.java | 10 ++--- src/main/java/jcs/ui/VNCPanel.java | 8 ++-- .../java/jcs/ui/widgets/FeedbackPanel.java | 2 +- 10 files changed, 94 insertions(+), 58 deletions(-) diff --git a/src/main/java/jcs/JCS.java b/src/main/java/jcs/JCS.java index b14d1b48..4919beb3 100755 --- a/src/main/java/jcs/JCS.java +++ b/src/main/java/jcs/JCS.java @@ -262,8 +262,7 @@ public static void main(String[] args) { persistentStore = getPersistenceService(); jcsCommandStation = getJcsCommandStation(); - if (persistentStore - != null) { + if (persistentStore != null) { if ("true".equalsIgnoreCase(System.getProperty("commandStation.autoconnect", "true"))) { if (jcsCommandStation != null) { boolean connected = jcsCommandStation.connect(); diff --git a/src/main/java/jcs/commandStation/JCSCommandStationImpl.java b/src/main/java/jcs/commandStation/JCSCommandStationImpl.java index 73048cef..0e1a0231 100755 --- a/src/main/java/jcs/commandStation/JCSCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/JCSCommandStationImpl.java @@ -116,7 +116,6 @@ private JCSCommandStationImpl(boolean autoConnectController) { @Override public final boolean connect() { - //TODO revice the connect, to nices code and preventing duplicat instantiations... boolean decoderControllerConnected = false; boolean allreadyConnected = false; @@ -213,7 +212,7 @@ public final boolean connect() { Logger.trace("Connected Controllers: Decoder: " + (decoderControllerConnected ? "Yes" : "No") + " Accessory: " + accessoryCntrConnected + " Feedback: " + feedbackCntrConnected); - if (decoderControllerConnected && !allreadyConnected) { + if (decoderControllerConnected && !allreadyConnected && decoderController != null) { decoderController.addDisconnectionEventListener(new DisconnectionListener(this)); decoderController.addLocomotiveFunctionEventListener(new LocomotiveFunctionChangeEventListener(this)); @@ -222,7 +221,7 @@ public final boolean connect() { supportedProtocols.addAll(decoderController.getCommandStationBean().getSupportedProtocols()); - if (this.decoderController.isSupportTrackMeasurements()) { + if (decoderController.isSupportTrackMeasurements()) { //Start the measurements background task long measureInterval = Long.parseLong(System.getProperty("track.measurements.interval", "5")); measureInterval = measureInterval * 1000; @@ -309,7 +308,10 @@ public void disconnect() { @Override public void setVirtual(boolean flag) { Logger.info("Switch Virtual Mode " + (flag ? "On" : "Off")); - this.decoderController.setVirtual(flag); + commandStation.setVirtual(flag); + PersistenceFactory.getService().persist(commandStation); + + decoderController.setVirtual(flag); } @Override @@ -576,17 +578,17 @@ public void removeLocomotiveSpeedEventListener(LocomotiveSpeedEventListener list @Override public void addDisconnectionEventListener(DisconnectionEventListener listener) { - if (this.decoderController != null) { - this.decoderController.addDisconnectionEventListener(listener); + if (decoderController != null) { + decoderController.addDisconnectionEventListener(listener); } - for (AccessoryController ac : this.accessoryControllers.values()) { - if (ac != this.decoderController) { + for (AccessoryController ac : accessoryControllers.values()) { + if (ac != decoderController) { ac.addDisconnectionEventListener(listener); } } - for (FeedbackController fc : this.feedbackControllers.values()) { - if (fc != this.decoderController) { + for (FeedbackController fc : feedbackControllers.values()) { + if (fc != decoderController) { fc.addDisconnectionEventListener(listener); } } @@ -594,26 +596,26 @@ public void addDisconnectionEventListener(DisconnectionEventListener listener) { @Override public void addPowerEventListener(PowerEventListener listener) { - if (this.decoderController != null) { - this.decoderController.addPowerEventListener(listener); + if (decoderController != null) { + decoderController.addPowerEventListener(listener); } } @Override public void removePowerEventListener(PowerEventListener listener) { - if (this.decoderController != null) { - this.decoderController.removePowerEventListener(listener); + if (decoderController != null) { + decoderController.removePowerEventListener(listener); } } @Override public void addMeasurementEventListener(MeasurementEventListener listener) { - this.measurementEventListeners.add(listener); + measurementEventListeners.add(listener); } @Override public void removeMeasurementListener(MeasurementEventListener listener) { - this.measurementEventListeners.remove(listener); + measurementEventListeners.remove(listener); } @Override @@ -646,7 +648,8 @@ public void run() { if (this.Controller != null && this.Controller.decoderController != null) { Map measurements = this.Controller.decoderController.getTrackMeasurements(); for (ChannelBean ch : measurements.values()) { - if (ch.isChanged()) { + + if (ch != null && ch.isChanged()) { MeasurementEvent me = new MeasurementEvent(ch); if (debuglog) { Logger.trace("Changed Channel " + ch.getNumber() + ", " + ch.getName() + ": " + ch.getHumanValue() + " " + ch.getUnit()); diff --git a/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java b/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java index 95d5d8ff..74318a6a 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java @@ -410,8 +410,7 @@ public void changeVelocity(int locUid, int speed, LocomotiveBean.Direction direc //When a locomotive has a speed change (>0) check if Auto mode is on. //When in Auto mode try to simulate the first sensor the locomotive is suppose to hit. if (AutoPilot.isAutoModeActive() && speed > 0) { - //simulateDriving(locUid, speed, direction); - this.simulator.simulateDriving(locUid, speed, direction); + simulator.simulateDriving(locUid, speed, direction); } } } @@ -581,16 +580,14 @@ public void fireSensorEventListeners(SensorEvent sensorEvent) { Logger.trace("SensorEvent: " + sensorEvent); if (sensorEventListeners != null && !sensorEventListeners.isEmpty()) { for (SensorEventListener listener : sensorEventListeners) { - //if (listener != null) { listener.onSensorChange(sensorEvent); - //} } } } @Override public void simulateSensor(SensorEvent sensorEvent) { - if (this.connection instanceof VirtualConnection virtualConnection) { + if (connection instanceof VirtualConnection virtualConnection) { virtualConnection.sendEvent(sensorEvent); } } diff --git a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java index 06e1c21c..1f1754d6 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java +++ b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java @@ -68,6 +68,8 @@ import jcs.commandStation.marklin.cs2.LocomotiveSpeedEventParser; import jcs.commandStation.marklin.cs2.PowerEventParser; import jcs.commandStation.VirtualConnection; +import jcs.commandStation.autopilot.AutoPilot; +import jcs.commandStation.autopilot.DriveSimulator; import jcs.commandStation.events.DisconnectionEvent; import jcs.commandStation.events.DisconnectionEventListener; import jcs.entities.LocomotiveBean; @@ -94,6 +96,8 @@ public class MarklinCentralStationImpl extends AbstractController implements Dec Map analogChannels; + private DriveSimulator simulator; + public MarklinCentralStationImpl(CommandStationBean commandStationBean) { this(commandStationBean, false); } @@ -153,7 +157,9 @@ public final synchronized boolean connect() { } CSConnection csConnection = CSConnectionFactory.getConnection(virtual); - csConnection.addDisconnectionEventListener(this); + if (csConnection != null) { + csConnection.addDisconnectionEventListener(this); + } connection = csConnection; @@ -163,7 +169,7 @@ public final synchronized boolean connect() { long timeout = now + 1000L; while (!connected && now < timeout) { - connected = csConnection.isConnected(); + connected = connection.isConnected(); now = System.currentTimeMillis(); } if (!connected && now > timeout) { @@ -204,8 +210,9 @@ public final synchronized boolean connect() { power = isPower(); JCS.logProgress("Power is " + (power ? "On" : "Off")); + } - Logger.trace("Connected: " + connected + " Default Accessory SwitchTime: " + this.defaultSwitchTime); + Logger.trace("Connected: " + connected + " Default Accessory SwitchTime: " + defaultSwitchTime); } else { Logger.warn("Can't connect with Central Station!"); JCS.logProgress("Can't connect with Central Station!"); @@ -215,6 +222,10 @@ public final synchronized boolean connect() { if (isCS3()) { getMembers(); } + if (isVirtual()) { + simulator = new DriveSimulator(); + Logger.info("Marklin Central Station Virtual Mode Enabled!"); + } return connected; } @@ -584,6 +595,16 @@ public void changeVelocity(int locUid, int speed, Direction direction) { CanMessage message = sendMessage(CanMessageFactory.setLocSpeed(locUid, speed, this.csUid)); LocomotiveSpeedEvent vme = LocomotiveSpeedEventParser.parseMessage(message); notifyLocomotiveSpeedEventListeners(vme); + + if (isVirtual()) { + //When a locomotive has a speed change (>0) check if Auto mode is on. + //When in Auto mode try to simulate the first sensor the locomotive is suppose to hit. + if (AutoPilot.isAutoModeActive() && speed > 0) { + //simulateDriving(locUid, speed, direction); + this.simulator.simulateDriving(locUid, speed, direction); + } + } + } } @@ -858,7 +879,7 @@ public void run() { case CanMessage.S88_EVENT_RESPONSE -> { if (CanMessage.DLC_8 == dlc) { Logger.trace("FeedbackSensorEvent RX: " + eventMessage); - + SensorBean sb = FeedbackEventMessage.parse(eventMessage, new Date()); SensorEvent sme = new SensorEvent(sb); if (sme.getSensorBean() != null) { @@ -877,10 +898,8 @@ public void run() { } case CanMessage.SYSTEM_COMMAND -> { Logger.trace("SystemConfigCommand RX: " + eventMessage); - + //;/p - - } case CanMessage.SYSTEM_COMMAND_RESP -> { switch (subcmd) { @@ -985,12 +1004,12 @@ public static void main(String[] a) { cs.power(false); Logger.debug("Power is " + (cs.isPower() ? "ON" : "Off")); cs.power(true); - + Logger.debug("Switch Accessory 2 to Red"); - cs.switchAccessory(2,AccessoryValue.RED,250); - + cs.switchAccessory(2, AccessoryValue.RED, 250); + Logger.debug("Switch Accessory 2 to Green"); - cs.switchAccessory(2,AccessoryValue.GREEN,250); + cs.switchAccessory(2, AccessoryValue.GREEN, 250); //cs.getLocomotivesViaCAN(); //cs.getAccessoriesViaCan(); @@ -1019,7 +1038,6 @@ public static void main(String[] a) { // Logger.trace("Channel " + ch.getNumber() + ": " + ch.getHumanValue() + " " + ch.getUnit()); // } // } - // Logger.debug("Channel 1: " + cs.channelData1.getChannel().getHumanValue() + " " + cs.channelData1.getChannel().getUnit()); // Logger.debug("Channel 2: " + cs.channelData2.getChannel().getHumanValue() + " " + cs.channelData2.getChannel().getUnit()); // Logger.debug("Channel 3: " + cs.channelData3.getChannel().getHumanValue() + " " + cs.channelData3.getChannel().getUnit()); diff --git a/src/main/java/jcs/commandStation/marklin/cs/can/parser/SystemStatus.java b/src/main/java/jcs/commandStation/marklin/cs/can/parser/SystemStatus.java index 33c9e90f..5bbd29b3 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/can/parser/SystemStatus.java +++ b/src/main/java/jcs/commandStation/marklin/cs/can/parser/SystemStatus.java @@ -33,7 +33,8 @@ public static boolean parseSystemPowerMessage(CanMessage message) { } else { for (CanMessage cm : respList) { if (CanMessage.SYSTEM_COMMAND_RESP == cm.getCommand() && cm.getDlc() == CanMessage.DLC_5) { - return message.getData()[4] == 1; + int powerVal = cm.getData()[4]; + return powerVal == 1; } } } diff --git a/src/main/java/jcs/commandStation/marklin/cs/net/CSVirtualConnection.java b/src/main/java/jcs/commandStation/marklin/cs/net/CSVirtualConnection.java index 6b364787..bd4da261 100644 --- a/src/main/java/jcs/commandStation/marklin/cs/net/CSVirtualConnection.java +++ b/src/main/java/jcs/commandStation/marklin/cs/net/CSVirtualConnection.java @@ -26,6 +26,7 @@ import jcs.commandStation.events.DisconnectionEventListener; import jcs.commandStation.events.SensorEvent; import jcs.commandStation.marklin.cs.can.CanMessage; +import jcs.commandStation.marklin.cs.can.CanMessageFactory; import jcs.commandStation.marklin.cs.can.parser.SystemStatus; import org.tinylog.Logger; @@ -34,6 +35,8 @@ */ class CSVirtualConnection implements CSConnection, VirtualConnection { + final static int LINK_S88_UID = 1396202561; + private boolean connected; private final InetAddress centralStationAddress; @@ -55,7 +58,26 @@ class CSVirtualConnection implements CSConnection, VirtualConnection { @Override public void sendEvent(SensorEvent sensorEvent) { - //Virtual + int deviceId = sensorEvent.getDeviceId(); + int contactId = sensorEvent.getContactId(); + int value = sensorEvent.isActive() ? 1 : 0; + int prevVal; + if (sensorEvent.isChanged() && sensorEvent.isActive()) { + prevVal = 1; + } else { + prevVal = 0; + } + + Logger.trace("Device: " + deviceId + " contact: " + contactId + " -> " + value); + + CanMessage eventMessage = CanMessageFactory.sensorEventMessage(deviceId, contactId, value, prevVal, 100, LINK_S88_UID); + + try { + eventQueue.put(eventMessage); + } catch (InterruptedException ex) { + Logger.error(ex); + } + } private void initMessageSender() { @@ -171,8 +193,6 @@ public synchronized CanMessage sendCanMessage(CanMessage message) { //0x00 0x23 0x7b 0x79 0x08 0x00 0x41 0x07 0xd1 0x01 0x00 0x00 0xb4 //0x00 0x23 0x7b 0x79 0x08 0x00 0x41 0x07 0xe0 0x00 0x01 0xdc 0xf0 //0x00 0x23 0x7b 0x79 0x08 0x00 0x41 0x07 0xe0 0x01 0x00 0x00 0x50 - - //0x00 0x23 0x7b 0x79 0x08 0x00 0x41 0x03 0xee 0x00 0x01 0x40 0xf6 //0x00 0x23 0x7b 0x79 0x08 0x00 0x41 0x03 0xee 0x01 0x00 0x00 0x0a //0x00 0x23 0x7b 0x79 0x08 0x00 0x41 0x03 0xf0 0x00 0x01 0x42 0x5d @@ -181,10 +201,6 @@ public synchronized CanMessage sendCanMessage(CanMessage message) { //0x00 0x23 0x7b 0x79 0x08 0x00 0x41 0x03 0xf0 0x01 0x00 0x00 0x0a //0x00 0x23 0x7b 0x79 0x08 0x00 0x41 0x03 0xf0 0x00 0x01 0x00 0x46 //0x00 0x23 0x7b 0x79 0x08 0x00 0x41 0x03 0xf0 0x01 0x00 0x00 0x0a - - - - } case CanMessage.SYSTEM_COMMAND_RESP -> { } @@ -226,7 +242,7 @@ public InetAddress getControllerAddress() { @Override public boolean isConnected() { - return this.connected; + return this.connected; } private class PeriodicCSMessageSender extends Thread { @@ -276,4 +292,3 @@ public void run() { } } } - diff --git a/src/main/java/jcs/ui/JCSFrame.form b/src/main/java/jcs/ui/JCSFrame.form index 0b57c4d5..c7203e32 100755 --- a/src/main/java/jcs/ui/JCSFrame.form +++ b/src/main/java/jcs/ui/JCSFrame.form @@ -139,11 +139,14 @@ - + + + + - + diff --git a/src/main/java/jcs/ui/JCSFrame.java b/src/main/java/jcs/ui/JCSFrame.java index 528d57fa..7fdaba69 100755 --- a/src/main/java/jcs/ui/JCSFrame.java +++ b/src/main/java/jcs/ui/JCSFrame.java @@ -327,9 +327,9 @@ private void initComponents() { setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); setTitle("Java Central Station"); setBounds(new Rectangle(0, 0, 1400, 900)); - setMinimumSize(new Dimension(1250, 900)); + setMinimumSize(new Dimension(1350, 850)); setName("JCSFrame"); // NOI18N - setSize(new Dimension(1250, 950)); + setSize(new Dimension(1350, 870)); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent evt) { formWindowClosing(evt); @@ -613,9 +613,7 @@ public void actionPerformed(ActionEvent evt) { centerPanel.add(layoutPanel, "designPanel"); layoutPanel.getAccessibleContext().setAccessibleName("designPanel"); - overviewPanel.setMinimumSize(new Dimension(1002, 772)); overviewPanel.setName("overviewPanel"); // NOI18N - overviewPanel.setPreferredSize(new Dimension(1002, 772)); centerPanel.add(overviewPanel, "overviewPanel"); overviewPanel.getAccessibleContext().setAccessibleName("overviewPanel"); @@ -1022,9 +1020,9 @@ private void resetAutoPilotBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:even }//GEN-LAST:event_resetAutoPilotBtnActionPerformed private void virtualCBActionPerformed(ActionEvent evt) {//GEN-FIRST:event_virtualCBActionPerformed - Logger.trace(evt.getActionCommand() + " Switch Virtual Mode " + (this.virtualCB.isSelected() ? "On" : "Off")); + Logger.trace(evt.getActionCommand() + " Switch Virtual Mode " + (virtualCB.isSelected() ? "On" : "Off")); if (JCS.getJcsCommandStation() != null) { - JCS.getJcsCommandStation().setVirtual(this.virtualCB.isSelected()); + JCS.getJcsCommandStation().setVirtual(virtualCB.isSelected()); } }//GEN-LAST:event_virtualCBActionPerformed diff --git a/src/main/java/jcs/ui/VNCPanel.java b/src/main/java/jcs/ui/VNCPanel.java index 51ca4516..7f2ed948 100644 --- a/src/main/java/jcs/ui/VNCPanel.java +++ b/src/main/java/jcs/ui/VNCPanel.java @@ -70,9 +70,11 @@ private void initVnc() { addDrawingSurface(); //clipboardMonitor.start(); initialiseVernacularClient(); - String ip = JCS.getJcsCommandStation().getCommandStationInfo().getIpAddress(); - int port = DEFAULT_VNC_PORT; - connect(ip, port); + if (JCS.getJcsCommandStation().isConnected()) { + String ip = JCS.getJcsCommandStation().getCommandStationInfo().getIpAddress(); + int port = DEFAULT_VNC_PORT; + connect(ip, port); + } } } } diff --git a/src/main/java/jcs/ui/widgets/FeedbackPanel.java b/src/main/java/jcs/ui/widgets/FeedbackPanel.java index 5dd6a948..f241f933 100755 --- a/src/main/java/jcs/ui/widgets/FeedbackPanel.java +++ b/src/main/java/jcs/ui/widgets/FeedbackPanel.java @@ -99,7 +99,7 @@ private void initSensorListeners() { int port = 1; p1 = new FeedbackPort(this.lbl1, deviceId, calculateContactId(moduleNumber, contactIdOffset, port++)); - Logger.trace("Port " + (port - 1) + ", device: " + deviceId + " module: " + moduleNumber + " offset: " + contactIdOffset + " Contact Addres: " + p1.contactId); + //Logger.trace("Port " + (port - 1) + ", device: " + deviceId + " module: " + moduleNumber + " offset: " + contactIdOffset + " Contact Addres: " + p1.contactId); p2 = new FeedbackPort(this.lbl2, deviceId, calculateContactId(moduleNumber, contactIdOffset, port++)); p3 = new FeedbackPort(this.lbl3, deviceId, calculateContactId(moduleNumber, contactIdOffset, port++)); p4 = new FeedbackPort(this.lbl4, deviceId, calculateContactId(moduleNumber, contactIdOffset, port++)); From 7eb01fce7e76943a9f62f8f98e7ac472b3ecc6fa Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Sun, 9 Mar 2025 14:28:15 +0100 Subject: [PATCH 30/70] Autodriving tested with Marklin CS --- .../commandStation/AccessoryController.java | 8 +- .../commandStation/JCSCommandStationImpl.java | 11 +- .../dccex/DccExCommandStationImpl.java | 30 +++-- .../esu/ecos/AccessoryManager.java | 13 ++ .../esu/ecos/EsuEcosCommandStationImpl.java | 28 +++-- .../marklin/cs/MarklinCentralStationImpl.java | 71 +++++------ .../marklin/cs/can/CanMessage.java | 6 +- .../marklin/cs/can/CanMessageFactory.java | 71 +++++++---- .../marklin/cs/can/MarklinCan.java | 2 + .../cs/can/parser/AccessoryMessage.java | 28 ++++- .../marklin/cs/can/parser/DirectionInfo.java | 52 -------- .../LocomotiveEmergencyStopMessage.java | 55 ++++++++ .../marklin/cs/net/CSVirtualConnection.java | 12 ++ .../marklin/cs2/LocomotiveBeanParser.java | 14 --- .../virtual/VirtualCommandStationImpl.java | 119 +++++++++--------- .../ecos/EsuEcosCommandStationImplTest.java | 9 +- .../marklin/cs/DirectionInfoTest.java | 72 ----------- .../cs/can/parser/AccessoryMessageTest.java | 56 +++++++++ 18 files changed, 358 insertions(+), 299 deletions(-) delete mode 100755 src/main/java/jcs/commandStation/marklin/cs/can/parser/DirectionInfo.java create mode 100644 src/main/java/jcs/commandStation/marklin/cs/can/parser/LocomotiveEmergencyStopMessage.java delete mode 100755 src/test/java/jcs/commandStation/marklin/cs/DirectionInfoTest.java create mode 100644 src/test/java/jcs/commandStation/marklin/cs/can/parser/AccessoryMessageTest.java diff --git a/src/main/java/jcs/commandStation/AccessoryController.java b/src/main/java/jcs/commandStation/AccessoryController.java index d943c3ff..2e387d6b 100644 --- a/src/main/java/jcs/commandStation/AccessoryController.java +++ b/src/main/java/jcs/commandStation/AccessoryController.java @@ -22,11 +22,13 @@ public interface AccessoryController extends GenericController { - void switchAccessory(Integer address, AccessoryValue value); + //void switchAccessory(Integer address, AccessoryValue value); - void switchAccessory(Integer address, AccessoryValue value, Integer switchTime); + //void switchAccessory(Integer address, AccessoryValue value, Integer switchTime); - void switchAccessory(String id, AccessoryBean.AccessoryValue value); + //void switchAccessory(String id, AccessoryBean.AccessoryValue value); + + void switchAccessory(Integer address, String protocol, AccessoryValue value, Integer switchTime); void addAccessoryEventListener(AccessoryEventListener listener); diff --git a/src/main/java/jcs/commandStation/JCSCommandStationImpl.java b/src/main/java/jcs/commandStation/JCSCommandStationImpl.java index 0e1a0231..9420125b 100755 --- a/src/main/java/jcs/commandStation/JCSCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/JCSCommandStationImpl.java @@ -498,8 +498,13 @@ public void changeLocomotiveFunction(Boolean newValue, Integer functionNumber, L @Override public void switchAccessory(AccessoryBean accessory, AccessoryValue value) { + String id = accessory.getId(); Integer address = accessory.getAddress(); Integer switchTime = accessory.getSwitchTime(); + AccessoryBean.Protocol protocol = accessory.getProtocol(); + if (protocol == null) { + protocol = AccessoryBean.Protocol.DCC; + } AccessoryValue val = value; Integer states = accessory.getStates(); Integer state = accessory.getState(); @@ -514,15 +519,13 @@ public void switchAccessory(AccessoryBean accessory, AccessoryValue value) { if (states > 2) { if (accessory.getState() > 1) { address = address + 1; - //val = AccessoryValue.cs3Get(state - 2); val = AccessoryValue.get(state - 2); } } Logger.trace("Change accessory with address: " + address + ", " + accessory.getName() + " to " + val.getValue()); - for (AccessoryController ac : accessoryControllers.values()) { - ac.switchAccessory(address, val, switchTime); + ac.switchAccessory(address, protocol.getValue(), val, switchTime); } } @@ -648,7 +651,7 @@ public void run() { if (this.Controller != null && this.Controller.decoderController != null) { Map measurements = this.Controller.decoderController.getTrackMeasurements(); for (ChannelBean ch : measurements.values()) { - + if (ch != null && ch.isChanged()) { MeasurementEvent me = new MeasurementEvent(ch); if (debuglog) { diff --git a/src/main/java/jcs/commandStation/dccex/DccExCommandStationImpl.java b/src/main/java/jcs/commandStation/dccex/DccExCommandStationImpl.java index acc797ca..2b68c61c 100644 --- a/src/main/java/jcs/commandStation/dccex/DccExCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/dccex/DccExCommandStationImpl.java @@ -336,13 +336,18 @@ public void changeFunctionValue(int address, int functionNumber, boolean flag) { //Direct approach no feed back... //maybe register the accessories and then via id? - @Override - public void switchAccessory(Integer address, AccessoryValue value) { - switchAccessory(address, value, null); - } +// @Override +// public void switchAccessory(Integer address, AccessoryValue value) { +// switchAccessory(address, value, null); +// } + +// @Override +// public void switchAccessory(Integer address, AccessoryValue value, Integer switchTime) { +// switchAccessory(address, "dcc", value, switchTime); +// } @Override - public void switchAccessory(Integer address, AccessoryValue value, Integer switchTime) { + public void switchAccessory(Integer address, String protocol, AccessoryValue value, Integer switchTime) { if (this.power && this.connected) { String activate = AccessoryValue.GREEN == value ? "0" : "1"; String message = DccExMessageFactory.activateAccessory(address, activate); @@ -365,10 +370,10 @@ public void switchAccessory(Integer address, AccessoryValue value, Integer switc } } - @Override - public void switchAccessory(String id, AccessoryValue value) { - throw new UnsupportedOperationException("Not supported yet."); - } +// @Override +// public void switchAccessory(String id, AccessoryValue value) { +// throw new UnsupportedOperationException("Not supported yet."); +// } @Override public List getLocomotives() { @@ -683,7 +688,7 @@ public void onDisconnect(DisconnectionEvent event) { } -////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////// // For testing only public static void main(String[] a) { @@ -732,7 +737,10 @@ public static void main(String[] a) { // ((DccExCommandStationImpl) cs).pause(500L); // cs.power(true); // Logger.trace("Power is: " + (cs.isPower() ? "On" : "Off")); - ///// + + + +///// //((DccExCommandStationImpl) cs).pause(500L); // cs.changeFunctionValue(8, 0, true); // diff --git a/src/main/java/jcs/commandStation/esu/ecos/AccessoryManager.java b/src/main/java/jcs/commandStation/esu/ecos/AccessoryManager.java index f3220b39..4da6ecf7 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/AccessoryManager.java +++ b/src/main/java/jcs/commandStation/esu/ecos/AccessoryManager.java @@ -216,6 +216,18 @@ Map getAccessories() { return accessories; } + AccessoryBean getAccessory(Integer address) { + AccessoryBean result = null; + for (AccessoryBean accessory : this.accessories.values()) { + if (address.equals(accessory.getAddress())) { + result = accessory; + break; + } + } + + return result; + } + String findId(Integer address) { String id = null; for (AccessoryBean accessory : this.accessories.values()) { @@ -398,6 +410,7 @@ static String deriveType(String symbol) { //20005 name1["Sein mini"]20005 name2["artikel"]20005 name3[">0001<"]20005 addr[16]20005 protocol[MM]20005 mode[SWITCH]20005 symbol[13]20005 //state[0]20005 type[ACCESSORY]20005 addrext[16g,16r]20005 duration[500]20005 gates[2]20005 variant[0]20005 position[ok]20005 switching[0] // + //// //20000 switching[1] //20000 state[0] diff --git a/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java b/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java index 74318a6a..d6351d7c 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java @@ -481,17 +481,23 @@ public Map getTrackMeasurements() { throw new UnsupportedOperationException("Not supported yet."); } +// @Override +// public void switchAccessory(Integer address, AccessoryBean.AccessoryValue value) { +// switchAccessory(address, value, defaultSwitchTime); +// } +// @Override +// public void switchAccessory(Integer address, AccessoryBean.AccessoryValue value, Integer switchTime) { +// AccessoryBean ab = accessoryManager.getAccessory(address); +// if (ab != null) { +// switchAccessory(ab.getId(), value); +// } else { +// Logger.warn("Accessory with address " + address + " does not exist for the Ecos"); +// } +// } @Override - public void switchAccessory(Integer address, AccessoryBean.AccessoryValue value) { - switchAccessory(address, value, this.defaultSwitchTime); - } - - @Override - public void switchAccessory(Integer address, AccessoryBean.AccessoryValue value, Integer switchTime) { - //for now try to find the object id based on the address. - //The protocol is not known so "accidents" can happen... + public void switchAccessory(Integer address, String protocol, AccessoryBean.AccessoryValue value, Integer switchTime) { Logger.trace("Using Address " + address + " to find the AccessoryId..."); - String id = this.accessoryManager.findId(address); + String id = accessoryManager.findId(address); if (id != null) { switchAccessory(id, value); } else { @@ -499,8 +505,8 @@ public void switchAccessory(Integer address, AccessoryBean.AccessoryValue value, } } - @Override - public void switchAccessory(String id, AccessoryBean.AccessoryValue value) { + //@Override + void switchAccessory(String id, AccessoryBean.AccessoryValue value) { //if (this.power && this.connected) { Logger.trace("Changing Accessory " + id + " to " + value); int state; diff --git a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java index 1f1754d6..7e38d30c 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java +++ b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java @@ -72,6 +72,7 @@ import jcs.commandStation.autopilot.DriveSimulator; import jcs.commandStation.events.DisconnectionEvent; import jcs.commandStation.events.DisconnectionEventListener; +import jcs.commandStation.marklin.cs.can.parser.LocomotiveEmergencyStopMessage; import jcs.entities.LocomotiveBean; import jcs.entities.LocomotiveBean.Direction; import jcs.entities.SensorBean; @@ -563,26 +564,10 @@ private CanMessage sendMessage(CanMessage canMessage) { return canMessage; } -// private int getLocoAddres(int address, DecoderType decoderType) { -// int locoAddress; -// locoAddress = switch (decoderType) { -// case MFX -> -// 0x4000 + address; -// case MFXP -> -// 0x4000 + address; -// case DCC -> -// 0xC000 + address; -// case SX1 -> -// 0x0800 + address; -// default -> -// address; -// }; -// -// return locoAddress; -// } @Override public void changeDirection(int locUid, Direction direction) { if (power && connected) { + Logger.trace("Change direction to " + direction + " CS val " + direction.getMarklinValue()); CanMessage message = sendMessage(CanMessageFactory.setDirection(locUid, direction.getMarklinValue(), this.csUid)); LocomotiveDirectionEvent dme = LocomotiveDirectionEventParser.parseMessage(message); notifyLocomotiveDirectionEventListeners(dme); @@ -617,12 +602,7 @@ public void changeFunctionValue(int locUid, int functionNumber, boolean flag) { } @Override - public void switchAccessory(Integer address, AccessoryValue value) { - switchAccessory(address, value, defaultSwitchTime); - } - - @Override - public void switchAccessory(Integer address, AccessoryValue value, Integer switchTime) { + public void switchAccessory(Integer address, String protocol, AccessoryValue value, Integer switchTime) { if (power && connected) { //make sure a time is set! int st; @@ -631,23 +611,39 @@ public void switchAccessory(Integer address, AccessoryValue value, Integer switc } else { st = switchTime / 10; } - //CS Switchtime is in 10 ms increments + + int adr; // zero based! + if ("dcc".equals(protocol)) { + adr = address - 1; + adr = adr + CanMessage.DCC_ACCESSORY_OFFSET; + } else { + adr = address - 1; + } + //CS 2/3 Switchtime is in 10 ms increments! st = st / 10; - CanMessage message = sendMessage(CanMessageFactory.switchAccessory(address, value, true, st, this.csUid)); + CanMessage message = sendMessage(CanMessageFactory.switchAccessory(adr, value, true, st, this.csUid)); //Notify listeners AccessoryEvent ae = AccessoryMessage.parse(message); - notifyAccessoryEventListeners(ae); } else { Logger.trace("Trackpower is OFF! Can't switch Accessory: " + address + " to: " + value + "!"); } } - @Override - public void switchAccessory(String id, AccessoryValue value) { - throw new UnsupportedOperationException("Not supported yet."); - } - +// @Override +// public void switchAccessory(String id, AccessoryValue value) { +// throw new UnsupportedOperationException("Not supported yet."); +// +//DCC Accessories +//RX: 0x00 0x16 0x37 0x7e 0x06 0x00 0x00 0x38 0x00 0x00 0x01 0x00 0x00 +//RX: 0x00 0x16 0x37 0x7e 0x06 0x00 0x00 0x38 0x00 0x00 0x00 0x00 0x00 +//RX: 0x00 0x16 0x37 0x7e 0x06 0x00 0x00 0x38 0x00 0x01 0x01 0x00 0x00 +//RX: 0x00 0x16 0x37 0x7e 0x06 0x00 0x00 0x38 0x00 0x01 0x00 0x00 0x00 +//RX: 0x00 0x16 0x37 0x7e 0x06 0x00 0x00 0x38 0x01 0x00 0x01 0x00 0x00 +//RX: 0x00 0x16 0x37 0x7e 0x06 0x00 0x00 0x38 0x01 0x00 0x00 0x00 0x00 +//RX: 0x00 0x16 0x37 0x7e 0x06 0x00 0x00 0x38 0x01 0x01 0x01 0x00 0x00 +//RX: 0x00 0x16 0x37 0x7e 0x06 0x00 0x00 0x38 0x01 0x01 0x00 0x00 0x00 +// } private void sendJCSUIDMessage() { sendMessage(CanMessageFactory.getMemberPingResponse(CanMessage.JCS_UID, 1, CanMessage.JCS_DEVICE_ID)); } @@ -898,8 +894,6 @@ public void run() { } case CanMessage.SYSTEM_COMMAND -> { Logger.trace("SystemConfigCommand RX: " + eventMessage); - -//;/p } case CanMessage.SYSTEM_COMMAND_RESP -> { switch (subcmd) { @@ -916,8 +910,9 @@ public void run() { notifyPowerEventListeners(gpe); } case CanMessage.LOC_STOP_SUB_CMD -> { - PowerEvent gpe = PowerEventParser.parseMessage(eventMessage); - notifyPowerEventListeners(gpe); + //stop specific loc + LocomotiveSpeedEvent lse = LocomotiveEmergencyStopMessage.parse(eventMessage); + notifyLocomotiveSpeedEventListeners(lse); } case CanMessage.OVERLOAD_SUB_CMD -> { PowerEvent gpe = PowerEventParser.parseMessage(eventMessage); @@ -941,9 +936,11 @@ public void run() { notifyLocomotiveSpeedEventListeners(LocomotiveSpeedEventParser.parseMessage(eventMessage)); } case CanMessage.LOC_DIRECTION -> { + Logger.trace("DirectionChange# " + eventMessage); } case CanMessage.LOC_DIRECTION_RESP -> { + Logger.trace("DirectionChange " + eventMessage); notifyLocomotiveDirectionEventListeners(LocomotiveDirectionEventParser.parseMessage(eventMessage)); } case CanMessage.LOC_FUNCTION -> { @@ -1006,10 +1003,10 @@ public static void main(String[] a) { cs.power(true); Logger.debug("Switch Accessory 2 to Red"); - cs.switchAccessory(2, AccessoryValue.RED, 250); + //cs.switchAccessory(2, AccessoryValue.RED, 250); Logger.debug("Switch Accessory 2 to Green"); - cs.switchAccessory(2, AccessoryValue.GREEN, 250); + //cs.switchAccessory(2, AccessoryValue.GREEN, 250); //cs.getLocomotivesViaCAN(); //cs.getAccessoriesViaCan(); diff --git a/src/main/java/jcs/commandStation/marklin/cs/can/CanMessage.java b/src/main/java/jcs/commandStation/marklin/cs/can/CanMessage.java index bc63274c..533c9ead 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/can/CanMessage.java +++ b/src/main/java/jcs/commandStation/marklin/cs/can/CanMessage.java @@ -358,9 +358,9 @@ public boolean isResponseComplete() { return this.responses.size() >= 2; } default -> { - if (this.expectsResponse()) { - CanMessage r0 = this.responses.get(0); - return this.command == r0.getCommand() - 1; + if (expectsResponse() && !responses.isEmpty()) { + CanMessage r0 = responses.get(0); + return command == r0.getCommand() - 1; } else { return true; } diff --git a/src/main/java/jcs/commandStation/marklin/cs/can/CanMessageFactory.java b/src/main/java/jcs/commandStation/marklin/cs/can/CanMessageFactory.java index 3fcd1827..19ac023c 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/can/CanMessageFactory.java +++ b/src/main/java/jcs/commandStation/marklin/cs/can/CanMessageFactory.java @@ -214,27 +214,26 @@ public static CanMessage systemStatus(int channel, int gfpUid) { return cm; } - public static CanMessage switchAccessory(int address, AccessoryValue value, boolean on, int gfpUid) { - byte[] data = new byte[CanMessage.DATA_SIZE]; - //TODO support for DCC - //localID = address - 1; // GUI-address is 1-based, protocol-address is 0-based - //if (protocol == ProtocolDCC) { localID |= 0x3800; } else { localID |= 0x3000;} - byte[] hash; - if (gfpUid > 0) { - hash = CanMessage.generateHash(gfpUid); - } else { - hash = MAGIC_HASH; - } - - data[ACCESSORY_CAN_ADDRESS_IDX] = ACCESSORY_CAN_ADDRESS; - data[ACCESSORY_ADDRESS_IDX] = (byte) (address - 1); - data[ACCESSORY_VALUE_IDX] = (byte) (AccessoryValue.GREEN.equals(value) ? 1 : 0); - data[ACCESSORY_ACTIVE_IDX] = (byte) (on ? 1 : 0); - - CanMessage cm = new CanMessage(PRIO_1, ACCESSORY_SWITCHING, hash, DLC_6, data); - return cm; - } - +// public static CanMessage switchAccessory(int address, AccessoryValue value, boolean on, int gfpUid) { +// byte[] data = new byte[CanMessage.DATA_SIZE]; +// //TODO support for DCC +// //localID = address - 1; // GUI-address is 1-based, protocol-address is 0-based +// //if (protocol == ProtocolDCC) { localID |= 0x3800; } else { localID |= 0x3000;} +// byte[] hash; +// if (gfpUid > 0) { +// hash = CanMessage.generateHash(gfpUid); +// } else { +// hash = MAGIC_HASH; +// } +// +// data[ACCESSORY_CAN_ADDRESS_IDX] = ACCESSORY_CAN_ADDRESS; +// data[ACCESSORY_ADDRESS_IDX] = (byte) (address - 1); +// data[ACCESSORY_VALUE_IDX] = (byte) (AccessoryValue.GREEN.equals(value) ? 1 : 0); +// data[ACCESSORY_ACTIVE_IDX] = (byte) (on ? 1 : 0); +// +// CanMessage cm = new CanMessage(PRIO_1, ACCESSORY_SWITCHING, hash, DLC_6, data); +// return cm; +// } public static CanMessage switchAccessory(int address, AccessoryValue value, boolean on, int switchTime, int gfpUid) { byte[] data = new byte[CanMessage.DATA_SIZE]; byte[] hash; @@ -244,8 +243,9 @@ public static CanMessage switchAccessory(int address, AccessoryValue value, bool hash = MAGIC_HASH; } - data[ACCESSORY_CAN_ADDRESS_IDX] = ACCESSORY_CAN_ADDRESS; - data[ACCESSORY_ADDRESS_IDX] = (byte) (address - 1); + byte[] addressBytes = CanMessage.to2Bytes(address); + System.arraycopy(addressBytes, 0, data, 2, addressBytes.length); + //TODO for signal other values are also supported data[ACCESSORY_VALUE_IDX] = (byte) (AccessoryValue.GREEN.equals(value) ? 1 : 0); data[ACCESSORY_ACTIVE_IDX] = (byte) (on ? 1 : 0); @@ -328,6 +328,25 @@ public static CanMessage queryDirection(int address, int gfpUid) { return cm; } + + // private int getLocoAddres(int address, DecoderType decoderType) { +// int locoAddress; +// locoAddress = switch (decoderType) { +// case MFX -> +// 0x4000 + address; +// case MFXP -> +// 0x4000 + address; +// case DCC -> +// 0xC000 + address; +// case SX1 -> +// 0x0800 + address; +// default -> +// address; +// }; +// +// return locoAddress; +// } + public static CanMessage setDirection(int address, int csdirection, int gfpUid) { byte[] data = new byte[CanMessage.DATA_SIZE]; byte[] hash; @@ -441,10 +460,10 @@ public static void main(String[] a) { System.out.println("systemStatus ch 1: " + systemStatus(1, 1668498828)); System.out.println("systemStatus ch 4: " + systemStatus(4, 1668498828)); - System.out.println("switchAccessory 1g: " + switchAccessory(1, AccessoryValue.GREEN, true, 1668498828)); - System.out.println("switchAccessory 1g: " + switchAccessory(1, AccessoryValue.GREEN, false, 1668498828)); + System.out.println("switchAccessory 1g: " + switchAccessory(1, AccessoryValue.GREEN, true, 20, 1668498828)); + System.out.println("switchAccessory 1g: " + switchAccessory(1, AccessoryValue.GREEN, false, 30, 1668498828)); - System.out.println("switchAccessory 1g: " + switchAccessory(1, AccessoryValue.RED, true, 1668498828)); + System.out.println("switchAccessory dcc 1: " + switchAccessory(14336, AccessoryValue.RED, true, 200, 1668498828)); System.out.println("switchAccessory 2g: " + switchAccessory(2, AccessoryValue.GREEN, true, 50, 1668498828)); System.out.println("switchAccessory 2r: " + switchAccessory(2, AccessoryValue.RED, true, 50, 1668498828)); diff --git a/src/main/java/jcs/commandStation/marklin/cs/can/MarklinCan.java b/src/main/java/jcs/commandStation/marklin/cs/can/MarklinCan.java index a5a7b04a..7ceaec50 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/can/MarklinCan.java +++ b/src/main/java/jcs/commandStation/marklin/cs/can/MarklinCan.java @@ -180,4 +180,6 @@ interface MarklinCan { //Magic hash which will result is getting device ids public static final byte[] MAGIC_HASH = new byte[]{0x07, 0x69}; + public static final int DCC_ACCESSORY_OFFSET = 14336; + } diff --git a/src/main/java/jcs/commandStation/marklin/cs/can/parser/AccessoryMessage.java b/src/main/java/jcs/commandStation/marklin/cs/can/parser/AccessoryMessage.java index e88d4c1d..40a0e0b3 100644 --- a/src/main/java/jcs/commandStation/marklin/cs/can/parser/AccessoryMessage.java +++ b/src/main/java/jcs/commandStation/marklin/cs/can/parser/AccessoryMessage.java @@ -21,9 +21,9 @@ import org.tinylog.Logger; public class AccessoryMessage { - + private AccessoryMessage() { - + } public static AccessoryEvent parse(CanMessage message) { @@ -39,16 +39,32 @@ public static AccessoryEvent parse(CanMessage message) { byte[] data = msg.getData(); if (CanMessage.ACCESSORY_SWITCHING_RESP == cmd || CanMessage.ACCESSORY_SWITCHING == cmd) { - int address = data[3]; - int position = data[4]; + byte[] addressData = new byte[]{data[2], data[3]}; + int address = CanMessage.toInt(addressData); + String protocol; //CS is zero based - address = address + 1; + if (address >= CanMessage.DCC_ACCESSORY_OFFSET) { + protocol = "dcc"; + address = address - CanMessage.DCC_ACCESSORY_OFFSET + 1; + } else { + protocol = "mm"; + address = address + 1; + } + + //int address = data[3]; + int position = data[4]; + String id = Integer.toString(address); - AccessoryBean accessoryBean = new AccessoryBean(id, address, null, null, position, null, null, null, CanMessage.MARKLIN_COMMANDSTATION_ID); + AccessoryBean accessoryBean = new AccessoryBean(id, address, null, null, position, null, protocol, null, CanMessage.MARKLIN_COMMANDSTATION_ID); //TODO DCC support + ///RX: 0x00 0x16 0x37 0x7e 0x06 0x00 0x00 0x38 0x00 0x01 0x00 0x00 0x00 + //RX: 0x00 0x16 0x37 0x7e 0x06 0x00 0x00 0x38 0x01 0x00 0x01 0x00 0x00 + + if (CanMessage.DLC_8 == dlc) { int switchTime = CanMessage.toInt(new byte[]{data[6], data[7]}); + switchTime = switchTime * 10; accessoryBean.setSwitchTime(switchTime); } return new AccessoryEvent(accessoryBean); diff --git a/src/main/java/jcs/commandStation/marklin/cs/can/parser/DirectionInfo.java b/src/main/java/jcs/commandStation/marklin/cs/can/parser/DirectionInfo.java deleted file mode 100755 index 676eaafa..00000000 --- a/src/main/java/jcs/commandStation/marklin/cs/can/parser/DirectionInfo.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2023 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.commandStation.marklin.cs.can.parser; - -import java.io.Serializable; -import jcs.commandStation.marklin.cs.can.CanMessage; -import jcs.entities.LocomotiveBean.Direction; -import org.tinylog.Logger; - -public class DirectionInfo implements Serializable { - - private Direction direction; - - public DirectionInfo(Direction direction) { - this.direction = direction; - } - - public DirectionInfo(CanMessage locDirection) { - parseMessage(locDirection); - } - - private void parseMessage(CanMessage locDirection) { - Logger.debug(locDirection); - byte[] data = locDirection.getResponse(0).getData(); - int dir = data[4]; - - this.direction = Direction.getDirectionMarkin(dir); - } - - @Override - public String toString() { - return "DirectionInfo{" + "direction=" + direction + '}'; - } - - public Direction getDirection() { - return direction; - } - -} diff --git a/src/main/java/jcs/commandStation/marklin/cs/can/parser/LocomotiveEmergencyStopMessage.java b/src/main/java/jcs/commandStation/marklin/cs/can/parser/LocomotiveEmergencyStopMessage.java new file mode 100644 index 00000000..6ef33c73 --- /dev/null +++ b/src/main/java/jcs/commandStation/marklin/cs/can/parser/LocomotiveEmergencyStopMessage.java @@ -0,0 +1,55 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.commandStation.marklin.cs.can.parser; + +import jcs.commandStation.events.LocomotiveSpeedEvent; +import jcs.commandStation.marklin.cs.can.CanMessage; +import jcs.entities.LocomotiveBean; +import org.tinylog.Logger; + +/** + * Emergency Stop for a specific locomotive + */ +public class LocomotiveEmergencyStopMessage { + + public static LocomotiveSpeedEvent parse(CanMessage message) { + CanMessage resp; + if (!message.isResponseMessage()) { + resp = message.getResponse(); + } else { + resp = message; + } + int cmd = resp.getCommand(); + int subCmd = resp.getSubCommand(); + int dlc = resp.getDlc(); + byte[] data = resp.getData(); + + if ((cmd == CanMessage.SYSTEM_COMMAND_RESP || cmd == CanMessage.SYSTEM_COMMAND) && subCmd == CanMessage.LOC_STOP_SUB_CMD && dlc == CanMessage.DLC_5) { + long id = CanMessage.toInt(new byte[]{data[0], data[1], data[2], data[3]}); + + LocomotiveBean locomotiveBean = new LocomotiveBean(); + locomotiveBean.setCommandStationId(CanMessage.MARKLIN_COMMANDSTATION_ID); + locomotiveBean.setId(id); + locomotiveBean.setVelocity(0); + return new LocomotiveSpeedEvent(locomotiveBean); + } else { + Logger.warn("Can't parse message, not a Locomotive Emergency Stop Message! " + resp); + return null; + } + + } + +} diff --git a/src/main/java/jcs/commandStation/marklin/cs/net/CSVirtualConnection.java b/src/main/java/jcs/commandStation/marklin/cs/net/CSVirtualConnection.java index bd4da261..8cf10b5f 100644 --- a/src/main/java/jcs/commandStation/marklin/cs/net/CSVirtualConnection.java +++ b/src/main/java/jcs/commandStation/marklin/cs/net/CSVirtualConnection.java @@ -208,6 +208,18 @@ public synchronized CanMessage sendCanMessage(CanMessage message) { message.addResponse(CanMessage.parse(message.toString(), true)); } case CanMessage.ACCESSORY_SWITCHING_RESP -> { +//DCC Accessories +//RX: 0x00 0x16 0x37 0x7e 0x06 0x00 0x00 0x38 0x00 0x00 0x01 0x00 0x00 +//RX: 0x00 0x16 0x37 0x7e 0x06 0x00 0x00 0x38 0x00 0x00 0x00 0x00 0x00 +//RX: 0x00 0x16 0x37 0x7e 0x06 0x00 0x00 0x38 0x00 0x01 0x01 0x00 0x00 +//RX: 0x00 0x16 0x37 0x7e 0x06 0x00 0x00 0x38 0x00 0x01 0x00 0x00 0x00 +//RX: 0x00 0x16 0x37 0x7e 0x06 0x00 0x00 0x38 0x01 0x00 0x01 0x00 0x00 +//RX: 0x00 0x16 0x37 0x7e 0x06 0x00 0x00 0x38 0x01 0x00 0x00 0x00 0x00 +//RX: 0x00 0x16 0x37 0x7e 0x06 0x00 0x00 0x38 0x01 0x01 0x01 0x00 0x00 +//RX: 0x00 0x16 0x37 0x7e 0x06 0x00 0x00 0x38 0x01 0x01 0x00 0x00 0x00 + + + } case CanMessage.LOC_VELOCITY -> { message.addResponse(CanMessage.parse(message.toString(), true)); diff --git a/src/main/java/jcs/commandStation/marklin/cs2/LocomotiveBeanParser.java b/src/main/java/jcs/commandStation/marklin/cs2/LocomotiveBeanParser.java index 89f5d049..777e7aa4 100755 --- a/src/main/java/jcs/commandStation/marklin/cs2/LocomotiveBeanParser.java +++ b/src/main/java/jcs/commandStation/marklin/cs2/LocomotiveBeanParser.java @@ -269,18 +269,4 @@ private LocomotiveBean createLoco(Map locoProps, Map locs = lp.parseLocomotivesFile(loksFile); - - for (LocomotiveBean loc : locs) { - Logger.trace(loc); - } - - } - } diff --git a/src/main/java/jcs/commandStation/virtual/VirtualCommandStationImpl.java b/src/main/java/jcs/commandStation/virtual/VirtualCommandStationImpl.java index b15ab642..52c0eaed 100644 --- a/src/main/java/jcs/commandStation/virtual/VirtualCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/virtual/VirtualCommandStationImpl.java @@ -54,16 +54,16 @@ * @author frans */ public class VirtualCommandStationImpl extends AbstractController implements DecoderController, AccessoryController, FeedbackController { - + private DeviceBean mainDevice; private InfoBean infoBean; - + private DriveSimulator simulator; - + public VirtualCommandStationImpl(CommandStationBean commandStationBean) { this(commandStationBean, false); } - + public VirtualCommandStationImpl(CommandStationBean commandStationBean, boolean autoConnect) { super(autoConnect, commandStationBean); //scheduledExecutor = new ScheduledThreadPoolExecutor(30); @@ -73,55 +73,55 @@ public VirtualCommandStationImpl(CommandStationBean commandStationBean, boolean autoConnect(); } } - + private void autoConnect() { connect(); } - + @Override public synchronized boolean connect() { this.connected = true; - + mainDevice = new DeviceBean(); mainDevice.setArticleNumber("JCS Virtual CS"); mainDevice.setVersion(VersionInfo.getVersion()); - + mainDevice.setSerial("1"); mainDevice.setIdentifier(this.commandStationBean.getId()); mainDevice.setName(this.commandStationBean.getDescription()); - + infoBean = new InfoBean(); infoBean.setProductName(commandStationBean.getDescription()); infoBean.setArticleNumber(commandStationBean.getShortName()); infoBean.setHostname(this.getIp()); - + power(true); - + return connected; } - + @Override public void disconnect() { this.connected = false; this.infoBean = null; this.mainDevice = null; } - + @Override public boolean isVirtual() { return true; } - + @Override public InfoBean getCommandStationInfo() { return this.infoBean; } - + @Override public DeviceBean getDevice() { return this.mainDevice; } - + @Override public List getDevices() { List devices = new ArrayList<>(); @@ -130,12 +130,12 @@ public List getDevices() { } return devices; } - + @Override public String getIp() { return NetworkUtil.getIPv4HostAddress().getHostAddress(); } - + @Override public boolean power(boolean on) { Logger.trace("Switching Power " + (on ? "On" : "Off")); @@ -143,7 +143,7 @@ public boolean power(boolean on) { this.power = on; Logger.trace("Power is " + (power ? "On" : "Off")); PowerEvent pe = new PowerEvent(this.power); - + executor.execute(() -> fireAllPowerEventListeners(pe)); synchronized (this) { notifyAll(); @@ -152,22 +152,22 @@ public boolean power(boolean on) { } else { return false; } - + } - + private void fireAllPowerEventListeners(final PowerEvent powerEvent) { for (PowerEventListener listener : powerEventListeners) { listener.onPowerChange(powerEvent); } } - + @Override public void changeDirection(int locUid, LocomotiveBean.Direction direction) { if (this.power && this.connected) { Logger.debug("locUid " + locUid + " direction " + direction); - + LocomotiveDirectionEvent lde = new LocomotiveDirectionEvent(locUid, direction, commandStationBean.getId()); - + notifyLocomotiveDirectionEventListeners(lde); } else { if (!this.power) { @@ -175,11 +175,11 @@ public void changeDirection(int locUid, LocomotiveBean.Direction direction) { } } } - + private void notifyLocomotiveDirectionEventListeners(final LocomotiveDirectionEvent directionEvent) { executor.execute(() -> fireAllDirectionEventListeners(directionEvent)); } - + private void fireAllDirectionEventListeners(final LocomotiveDirectionEvent directionEvent) { if (directionEvent.isValid()) { for (LocomotiveDirectionEventListener listener : this.locomotiveDirectionEventListeners) { @@ -187,12 +187,12 @@ private void fireAllDirectionEventListeners(final LocomotiveDirectionEvent direc } } } - + @Override public void changeVelocity(int locUid, int speed, LocomotiveBean.Direction direction) { if (this.power && connected) { Logger.debug("locUid " + locUid + " speed " + speed); - + LocomotiveSpeedEvent lse = new LocomotiveSpeedEvent(locUid, speed, commandStationBean.getId()); executor.execute(() -> { fireAllLocomotiveSpeedEventListeners(lse); @@ -210,7 +210,7 @@ public void changeVelocity(int locUid, int speed, LocomotiveBean.Direction direc } } } - + private void fireAllLocomotiveSpeedEventListeners(final LocomotiveSpeedEvent speedEvent) { if (speedEvent.isValid()) { for (LocomotiveSpeedEventListener listener : this.locomotiveSpeedEventListeners) { @@ -218,7 +218,7 @@ private void fireAllLocomotiveSpeedEventListeners(final LocomotiveSpeedEvent spe } } } - + @Override public void changeFunctionValue(int locUid, int functionNumber, boolean flag) { if (this.power && connected) { @@ -231,7 +231,7 @@ public void changeFunctionValue(int locUid, int functionNumber, boolean flag) { } } } - + private void fireAllFunctionEventListeners(final LocomotiveFunctionEvent functionEvent) { if (functionEvent.isValid()) { for (LocomotiveFunctionEventListener listener : this.locomotiveFunctionEventListeners) { @@ -239,47 +239,52 @@ private void fireAllFunctionEventListeners(final LocomotiveFunctionEvent functio } } } - + @Override public List getLocomotives() { throw new UnsupportedOperationException("Not supported yet."); } - + @Override public Image getLocomotiveImage(String icon) { throw new UnsupportedOperationException("Not supported yet."); } - + @Override public Image getLocomotiveFunctionImage(String icon) { throw new UnsupportedOperationException("Not supported yet."); } - + @Override public boolean isSupportTrackMeasurements() { return false; } - + @Override public Map getTrackMeasurements() { throw new UnsupportedOperationException("Not supported yet."); } - - @Override - public void switchAccessory(Integer address, AccessoryBean.AccessoryValue value) { - switchAccessory(address, value, 200); - } - - @Override - public void switchAccessory(String id, AccessoryBean.AccessoryValue value) { - throw new UnsupportedOperationException("Not supported yet."); - } - + +// @Override +// public void switchAccessory(Integer address, AccessoryBean.AccessoryValue value) { +// switchAccessory(address, value, 200); +// } + +// @Override +// public void switchAccessory(String id, AccessoryBean.AccessoryValue value) { +// throw new UnsupportedOperationException("Not supported yet."); +// } +// @Override +// public void switchAccessory(Integer address, AccessoryBean.AccessoryValue value, Integer switchTime) { +// switchAccessory(address, "dcc", value, switchTime); +// } + @Override - public void switchAccessory(Integer address, AccessoryBean.AccessoryValue value, Integer switchTime) { + public void switchAccessory(Integer address, String protocol, AccessoryBean.AccessoryValue value, Integer switchTime) { if (this.power && connected) { AccessoryBean ab = new AccessoryBean(); ab.setAddress(address); + ab.setProtocol(AccessoryBean.Protocol.get(protocol)); ab.setAccessoryValue(value); String id = address + ""; if (id.length() == 1) { @@ -289,7 +294,7 @@ public void switchAccessory(Integer address, AccessoryBean.AccessoryValue value, } ab.setId(id); ab.setCommandStationId(commandStationBean.getId()); - + AccessoryEvent ae = new AccessoryEvent(ab); //executor.execute(() -> fireAllAccessoryEventListeners(ae)); Logger.trace("Switched accessory " + id + " to " + value.getValue()); @@ -300,29 +305,29 @@ public void switchAccessory(Integer address, AccessoryBean.AccessoryValue value, } } } - + private void fireAllAccessoryEventListeners(final AccessoryEvent accessoryEvent) { for (AccessoryEventListener listener : this.accessoryEventListeners) { listener.onAccessoryChange(accessoryEvent); Logger.trace("Fired accessory listener " + accessoryEvent.getId()); } } - + @Override public List getAccessories() { throw new UnsupportedOperationException("Not supported yet."); } - + @Override public DeviceBean getFeedbackDevice() { throw new UnsupportedOperationException("Not supported yet."); } - + @Override public List getFeedbackModules() { throw new UnsupportedOperationException("Not supported yet."); } - + @Override public synchronized void fireSensorEventListeners(final SensorEvent sensorEvent) { for (SensorEventListener listener : sensorEventListeners) { @@ -331,14 +336,14 @@ public synchronized void fireSensorEventListeners(final SensorEvent sensorEvent) } } } - + @Override public void simulateSensor(SensorEvent sensorEvent) { List acl = JCS.getJcsCommandStation().getFeedbackControllers(); - + for (FeedbackController fbc : acl) { fbc.fireSensorEventListeners(sensorEvent); } } - + } diff --git a/src/test/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImplTest.java b/src/test/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImplTest.java index cd326a9f..5060aa8c 100644 --- a/src/test/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImplTest.java +++ b/src/test/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImplTest.java @@ -323,12 +323,14 @@ public void testIsSupportTrackMeasurements() { //@Test public void testSwitchAccessory_Integer_AccessoryBeanAccessoryValue() { System.out.println("switchAccessory"); + int switchTime = 200; + String protocol = "mm"; EsuEcosCommandStationImpl instance = new EsuEcosCommandStationImpl(commandStationBean); instance.connect(); Integer address = null; AccessoryBean.AccessoryValue value = null; - instance.switchAccessory(address, value); + instance.switchAccessory(address, protocol, value, switchTime); // TODO review the generated test code and remove the default call to fail. fail("The test case is a prototype."); } @@ -339,13 +341,14 @@ public void testSwitchAccessory_Integer_AccessoryBeanAccessoryValue() { //@Test public void testSwitchAccessory_3args() { System.out.println("switchAccessory"); + int switchTime = 200; + String protocol = "dcc"; EsuEcosCommandStationImpl instance = new EsuEcosCommandStationImpl(commandStationBean); instance.connect(); Integer address = null; AccessoryBean.AccessoryValue value = null; - Integer switchTime = null; - instance.switchAccessory(address, value, switchTime); + instance.switchAccessory(address, protocol, value, switchTime); // TODO review the generated test code and remove the default call to fail. fail("The test case is a prototype."); } diff --git a/src/test/java/jcs/commandStation/marklin/cs/DirectionInfoTest.java b/src/test/java/jcs/commandStation/marklin/cs/DirectionInfoTest.java deleted file mode 100755 index 52f230eb..00000000 --- a/src/test/java/jcs/commandStation/marklin/cs/DirectionInfoTest.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2023 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.commandStation.marklin.cs; - -import jcs.commandStation.marklin.cs.can.parser.DirectionInfo; -import jcs.commandStation.marklin.cs.can.CanMessage; -import jcs.entities.LocomotiveBean.Direction; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import static org.junit.Assert.*; - -/** - * - * @author fransjacobs - */ -public class DirectionInfoTest { - - private CanMessage message; - - public DirectionInfoTest() { - } - - @Before - public void setUp() { - message = new CanMessage(new byte[]{0x00, 0x0a, (byte) 0xcb, 0x13, 0x04, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00}); - CanMessage response = new CanMessage(new byte[]{0x00, 0x0b, (byte) 0xcb, 0x13, 0x08, 0x00, 0x00, 0x00, 0x0c, 0x02, 0x00, 0x00, 0x00}); - message.addResponse(response); - } - - @After - public void tearDown() { - } - - /** - * Test of toString method, of class DirectionInfo. - */ - @Test - public void testToString() { - System.out.println("toString"); - DirectionInfo instance = new DirectionInfo(message); - String expResult = "DirectionInfo{direction=BACKWARDS}"; - String result = instance.toString(); - assertEquals(expResult, result); - } - - /** - * Test of getDirection method, of class DirectionInfo. - */ - @Test - public void testGetDirection() { - System.out.println("getDirection"); - DirectionInfo instance = new DirectionInfo(message); - Direction expResult = Direction.BACKWARDS; - Direction result = instance.getDirection(); - assertEquals(expResult, result); - } - -} diff --git a/src/test/java/jcs/commandStation/marklin/cs/can/parser/AccessoryMessageTest.java b/src/test/java/jcs/commandStation/marklin/cs/can/parser/AccessoryMessageTest.java new file mode 100644 index 00000000..d67283bd --- /dev/null +++ b/src/test/java/jcs/commandStation/marklin/cs/can/parser/AccessoryMessageTest.java @@ -0,0 +1,56 @@ +/* + * Copyright 2025 fransjacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.commandStation.marklin.cs.can.parser; + +import jcs.commandStation.events.AccessoryEvent; +import jcs.commandStation.marklin.cs.can.CanMessage; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +/** + * + * @author fransjacobs + */ +public class AccessoryMessageTest { + + public AccessoryMessageTest() { + } + + @BeforeEach + public void setUp() { + } + + @AfterEach + public void tearDown() { + } + + /** + * Test of parse method, of class AccessoryMessage. + */ + @Test + public void testParse() { + System.out.println("parse"); + CanMessage message = null; + AccessoryEvent expResult = null; + AccessoryEvent result = AccessoryMessage.parse(message); + assertEquals(expResult, result); + // TODO review the generated test code and remove the default call to fail. + fail("The test case is a prototype."); + } + +} From 37ed653adad8857821a6f8ddee8b0879ea5c478a Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Sun, 9 Mar 2025 14:33:20 +0100 Subject: [PATCH 31/70] fix failing testcase --- .../commandStation/marklin/cs/can/parser/AccessoryMessage.java | 3 +++ .../marklin/cs/can/parser/AccessoryMessageTest.java | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/jcs/commandStation/marklin/cs/can/parser/AccessoryMessage.java b/src/main/java/jcs/commandStation/marklin/cs/can/parser/AccessoryMessage.java index 40a0e0b3..210b664e 100644 --- a/src/main/java/jcs/commandStation/marklin/cs/can/parser/AccessoryMessage.java +++ b/src/main/java/jcs/commandStation/marklin/cs/can/parser/AccessoryMessage.java @@ -27,6 +27,9 @@ private AccessoryMessage() { } public static AccessoryEvent parse(CanMessage message) { + if(message == null) { + return null; + } CanMessage msg; if (!message.isResponseMessage()) { msg = message.getResponse(); diff --git a/src/test/java/jcs/commandStation/marklin/cs/can/parser/AccessoryMessageTest.java b/src/test/java/jcs/commandStation/marklin/cs/can/parser/AccessoryMessageTest.java index d67283bd..609c0d53 100644 --- a/src/test/java/jcs/commandStation/marklin/cs/can/parser/AccessoryMessageTest.java +++ b/src/test/java/jcs/commandStation/marklin/cs/can/parser/AccessoryMessageTest.java @@ -19,7 +19,6 @@ import jcs.commandStation.marklin.cs.can.CanMessage; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; /** @@ -42,7 +41,7 @@ public void tearDown() { /** * Test of parse method, of class AccessoryMessage. */ - @Test + //@Test public void testParse() { System.out.println("parse"); CanMessage message = null; From ccb68f6cda395520fcedff7b6b0f2ee178e1b516 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Sun, 9 Mar 2025 19:55:31 +0100 Subject: [PATCH 32/70] Refactoring fix minor issue --- .../marklin/cs/MarklinCentralStationImpl.java | 33 +++++++++---------- .../parser/LocomotiveVelocityMessage.java} | 19 ++++------- .../marklin/cs2/LocomotiveBeanParser.java | 4 --- src/main/java/jcs/ui/DriverCabPanel.java | 10 +++--- .../options/LocomotivePreferencesPanel.java | 2 ++ 5 files changed, 28 insertions(+), 40 deletions(-) rename src/main/java/jcs/commandStation/marklin/{cs2/LocomotiveSpeedEventParser.java => cs/can/parser/LocomotiveVelocityMessage.java} (66%) diff --git a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java index 7e38d30c..4a8af81c 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java +++ b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java @@ -65,7 +65,7 @@ import jcs.commandStation.marklin.cs2.InfoBeanParser; import jcs.commandStation.marklin.cs2.LocomotiveDirectionEventParser; import jcs.commandStation.marklin.cs2.LocomotiveFunctionEventParser; -import jcs.commandStation.marklin.cs2.LocomotiveSpeedEventParser; +import jcs.commandStation.marklin.cs.can.parser.LocomotiveVelocityMessage; import jcs.commandStation.marklin.cs2.PowerEventParser; import jcs.commandStation.VirtualConnection; import jcs.commandStation.autopilot.AutoPilot; @@ -569,6 +569,10 @@ public void changeDirection(int locUid, Direction direction) { if (power && connected) { Logger.trace("Change direction to " + direction + " CS val " + direction.getMarklinValue()); CanMessage message = sendMessage(CanMessageFactory.setDirection(locUid, direction.getMarklinValue(), this.csUid)); + + //DirectionChange# 0x00 0x0a 0x37 0x7e 0x05 0x00 0x00 0x40 0x0c 0x01 0x00 0x00 0x00 + //BR 216 059-6 Speed changed from 218 to 0 + //DirectionChange 0x00 0x0b 0x03 0x26 0x05 0x00 0x00 0x40 0x0c 0x01 0x00 0x00 0x00 LocomotiveDirectionEvent dme = LocomotiveDirectionEventParser.parseMessage(message); notifyLocomotiveDirectionEventListeners(dme); } @@ -577,8 +581,12 @@ public void changeDirection(int locUid, Direction direction) { @Override public void changeVelocity(int locUid, int speed, Direction direction) { if (power && connected) { - CanMessage message = sendMessage(CanMessageFactory.setLocSpeed(locUid, speed, this.csUid)); - LocomotiveSpeedEvent vme = LocomotiveSpeedEventParser.parseMessage(message); + //VelocityChange 0x00 0x09 0x03 0x26 0x06 0x00 0x00 0x40 0x0c 0x00 0x30 0x00 0x00 + //16396 + CanMessage message = CanMessageFactory.setLocSpeed(locUid, speed, this.csUid); + Logger.trace("Ch Velocity: "+message); + message = sendMessage(message); + LocomotiveSpeedEvent vme = LocomotiveVelocityMessage.parse(message); notifyLocomotiveSpeedEventListeners(vme); if (isVirtual()) { @@ -630,20 +638,6 @@ public void switchAccessory(Integer address, String protocol, AccessoryValue val } } -// @Override -// public void switchAccessory(String id, AccessoryValue value) { -// throw new UnsupportedOperationException("Not supported yet."); -// -//DCC Accessories -//RX: 0x00 0x16 0x37 0x7e 0x06 0x00 0x00 0x38 0x00 0x00 0x01 0x00 0x00 -//RX: 0x00 0x16 0x37 0x7e 0x06 0x00 0x00 0x38 0x00 0x00 0x00 0x00 0x00 -//RX: 0x00 0x16 0x37 0x7e 0x06 0x00 0x00 0x38 0x00 0x01 0x01 0x00 0x00 -//RX: 0x00 0x16 0x37 0x7e 0x06 0x00 0x00 0x38 0x00 0x01 0x00 0x00 0x00 -//RX: 0x00 0x16 0x37 0x7e 0x06 0x00 0x00 0x38 0x01 0x00 0x01 0x00 0x00 -//RX: 0x00 0x16 0x37 0x7e 0x06 0x00 0x00 0x38 0x01 0x00 0x00 0x00 0x00 -//RX: 0x00 0x16 0x37 0x7e 0x06 0x00 0x00 0x38 0x01 0x01 0x01 0x00 0x00 -//RX: 0x00 0x16 0x37 0x7e 0x06 0x00 0x00 0x38 0x01 0x01 0x00 0x00 0x00 -// } private void sendJCSUIDMessage() { sendMessage(CanMessageFactory.getMemberPingResponse(CanMessage.JCS_UID, 1, CanMessage.JCS_DEVICE_ID)); } @@ -930,10 +924,13 @@ public void run() { } } case CanMessage.LOC_VELOCITY -> { + Logger.trace("VelocityChange# " + eventMessage); } case CanMessage.LOC_VELOCITY_RESP -> { - notifyLocomotiveSpeedEventListeners(LocomotiveSpeedEventParser.parseMessage(eventMessage)); + Logger.trace("VelocityChange " + eventMessage); + + notifyLocomotiveSpeedEventListeners(LocomotiveVelocityMessage.parse(eventMessage)); } case CanMessage.LOC_DIRECTION -> { Logger.trace("DirectionChange# " + eventMessage); diff --git a/src/main/java/jcs/commandStation/marklin/cs2/LocomotiveSpeedEventParser.java b/src/main/java/jcs/commandStation/marklin/cs/can/parser/LocomotiveVelocityMessage.java similarity index 66% rename from src/main/java/jcs/commandStation/marklin/cs2/LocomotiveSpeedEventParser.java rename to src/main/java/jcs/commandStation/marklin/cs/can/parser/LocomotiveVelocityMessage.java index f636a4c7..c572fe9f 100644 --- a/src/main/java/jcs/commandStation/marklin/cs2/LocomotiveSpeedEventParser.java +++ b/src/main/java/jcs/commandStation/marklin/cs/can/parser/LocomotiveVelocityMessage.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package jcs.commandStation.marklin.cs2; +package jcs.commandStation.marklin.cs.can.parser; import jcs.commandStation.events.*; import jcs.commandStation.marklin.cs.can.CanMessage; @@ -23,9 +23,9 @@ /** * */ -public class LocomotiveSpeedEventParser { - - public static LocomotiveSpeedEvent parseMessage(CanMessage message) { +public class LocomotiveVelocityMessage { + + public static LocomotiveSpeedEvent parse(CanMessage message) { LocomotiveBean locomotiveBean = new LocomotiveBean(); locomotiveBean.setCommandStationId(CanMessage.MARKLIN_COMMANDSTATION_ID); @@ -36,14 +36,7 @@ public static LocomotiveSpeedEvent parseMessage(CanMessage message) { resp = message; } - if (resp.isResponseMessage() && CanMessage.SYSTEM_COMMAND == resp.getCommand() && CanMessage.LOC_STOP_SUB_CMD == resp.getSubCommand() && CanMessage.DLC_5 == resp.getDlc()) { - //Loco halt command could be issued due to a direction change. - byte[] data = resp.getData(); - long id = CanMessage.toInt(new byte[]{data[0], data[1], data[2], data[3]}); - - locomotiveBean.setId(id); - locomotiveBean.setVelocity(0); - } else if (resp.isResponseMessage() && CanMessage.LOC_VELOCITY_RESP == resp.getCommand()) { + if (resp.isResponseMessage() && CanMessage.LOC_VELOCITY_RESP == resp.getCommand()) { byte[] data = resp.getData(); long id = CanMessage.toInt(new byte[]{data[0], data[1], data[2], data[3]}); @@ -53,7 +46,7 @@ public static LocomotiveSpeedEvent parseMessage(CanMessage message) { locomotiveBean.setVelocity(velocity); } else { - Logger.warn("Can't parse message, not a Locomotive Velocity or a Locomotive Emergency Stop Message! " + resp); + Logger.warn("Can't parse message, not a Locomotive Velocity Message! " + resp); return null; } return new LocomotiveSpeedEvent(locomotiveBean); diff --git a/src/main/java/jcs/commandStation/marklin/cs2/LocomotiveBeanParser.java b/src/main/java/jcs/commandStation/marklin/cs2/LocomotiveBeanParser.java index 777e7aa4..ee365a6e 100755 --- a/src/main/java/jcs/commandStation/marklin/cs2/LocomotiveBeanParser.java +++ b/src/main/java/jcs/commandStation/marklin/cs2/LocomotiveBeanParser.java @@ -15,10 +15,6 @@ */ package jcs.commandStation.marklin.cs2; -import java.io.File; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Arrays; import java.util.HashMap; import java.util.LinkedList; diff --git a/src/main/java/jcs/ui/DriverCabPanel.java b/src/main/java/jcs/ui/DriverCabPanel.java index 5fe0e085..e1226259 100644 --- a/src/main/java/jcs/ui/DriverCabPanel.java +++ b/src/main/java/jcs/ui/DriverCabPanel.java @@ -339,7 +339,6 @@ private void changeVelocity(int newVelocity, LocomotiveBean locomotiveBean) { } private void changeDirection(LocomotiveBean.Direction direction) { - //executor.execute(() -> changeDirection(direction, this.locomotiveBean)); changeDirection(direction, this.locomotiveBean); } @@ -453,10 +452,6 @@ public void onSpeedChange(LocomotiveSpeedEvent event) { this.speedSlider.setValue(sliderValue); - for (ChangeListener changeListener : changeListeners) { - this.speedSlider.addChangeListener(changeListener); - } - max = this.speedGauge.getMaxValue(); double gaugeValue = Math.round(max / 1000 * velocity); //this.speedGauge.setValue(gaugeValue); @@ -464,6 +459,11 @@ public void onSpeedChange(LocomotiveSpeedEvent event) { this.speedGauge.setUserLedOn(this.power); this.speedGauge.setLedBlinking(!this.power); + + for (ChangeListener changeListener : changeListeners) { + this.speedSlider.addChangeListener(changeListener); + } + } } diff --git a/src/main/java/jcs/ui/options/LocomotivePreferencesPanel.java b/src/main/java/jcs/ui/options/LocomotivePreferencesPanel.java index 512f11bf..f32b9790 100755 --- a/src/main/java/jcs/ui/options/LocomotivePreferencesPanel.java +++ b/src/main/java/jcs/ui/options/LocomotivePreferencesPanel.java @@ -940,6 +940,8 @@ public int compare(LocomotiveBean a, LocomotiveBean b) { class LocomotiveBeanListModel extends AbstractListModel { + private static final long serialVersionUID = -2632478289320377224L; + private final List model; public LocomotiveBeanListModel() { From 01ef3666548bb3de79f211c4f646ac997e7d728c Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Mon, 10 Mar 2025 21:46:14 +0100 Subject: [PATCH 33/70] Minor refactoring added property for disabling screen location storage --- src/main/java/jcs/JCS.java | 3 +- .../marklin/cs/MarklinCentralStationImpl.java | 2 +- .../can/parser/LocomotiveVelocityMessage.java | 2 +- src/main/java/jcs/ui/DriverCabPanel.java | 2 ++ src/main/java/jcs/ui/JCSFrame.form | 15 ++++----- src/main/java/jcs/ui/JCSFrame.java | 31 ++++++++++++++----- src/main/java/jcs/ui/layout/LayoutCanvas.java | 4 ++- src/main/java/jcs/ui/layout/LayoutPanel.java | 4 +-- .../options/LocomotivePreferencesPanel.java | 2 ++ src/main/java/jcs/ui/util/FrameMonitor.java | 10 +++++- 10 files changed, 52 insertions(+), 23 deletions(-) diff --git a/src/main/java/jcs/JCS.java b/src/main/java/jcs/JCS.java index 4919beb3..a5af8b9e 100755 --- a/src/main/java/jcs/JCS.java +++ b/src/main/java/jcs/JCS.java @@ -159,10 +159,11 @@ public void run() { Logger.info("JCS " + VersionInfo.getVersion() + " session finished"); } + @Deprecated public static void addRefreshListener(RefreshEventListener refreshListener) { instance.refreshEventListeners.add(refreshListener); } - + @Deprecated public static void removeRefreshListener(RefreshEventListener refreshListener) { instance.refreshEventListeners.remove(refreshListener); } diff --git a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java index 4a8af81c..177963c6 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java +++ b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java @@ -569,7 +569,7 @@ public void changeDirection(int locUid, Direction direction) { if (power && connected) { Logger.trace("Change direction to " + direction + " CS val " + direction.getMarklinValue()); CanMessage message = sendMessage(CanMessageFactory.setDirection(locUid, direction.getMarklinValue(), this.csUid)); - + //query velocity of give a not halt //DirectionChange# 0x00 0x0a 0x37 0x7e 0x05 0x00 0x00 0x40 0x0c 0x01 0x00 0x00 0x00 //BR 216 059-6 Speed changed from 218 to 0 //DirectionChange 0x00 0x0b 0x03 0x26 0x05 0x00 0x00 0x40 0x0c 0x01 0x00 0x00 0x00 diff --git a/src/main/java/jcs/commandStation/marklin/cs/can/parser/LocomotiveVelocityMessage.java b/src/main/java/jcs/commandStation/marklin/cs/can/parser/LocomotiveVelocityMessage.java index c572fe9f..9f727a42 100644 --- a/src/main/java/jcs/commandStation/marklin/cs/can/parser/LocomotiveVelocityMessage.java +++ b/src/main/java/jcs/commandStation/marklin/cs/can/parser/LocomotiveVelocityMessage.java @@ -15,7 +15,7 @@ */ package jcs.commandStation.marklin.cs.can.parser; -import jcs.commandStation.events.*; +import jcs.commandStation.events.LocomotiveSpeedEvent; import jcs.commandStation.marklin.cs.can.CanMessage; import jcs.entities.LocomotiveBean; import org.tinylog.Logger; diff --git a/src/main/java/jcs/ui/DriverCabPanel.java b/src/main/java/jcs/ui/DriverCabPanel.java index e1226259..145ec0cd 100644 --- a/src/main/java/jcs/ui/DriverCabPanel.java +++ b/src/main/java/jcs/ui/DriverCabPanel.java @@ -36,6 +36,8 @@ */ public class DriverCabPanel extends javax.swing.JPanel implements LocomotiveDirectionEventListener, LocomotiveSpeedEventListener, PowerEventListener { + private static final long serialVersionUID = 8833627645563021982L; + private LocomotiveBean locomotiveBean; private final ExecutorService executor; diff --git a/src/main/java/jcs/ui/JCSFrame.form b/src/main/java/jcs/ui/JCSFrame.form index c7203e32..2d6f5808 100755 --- a/src/main/java/jcs/ui/JCSFrame.form +++ b/src/main/java/jcs/ui/JCSFrame.form @@ -141,9 +141,6 @@ - - - @@ -152,7 +149,7 @@ - + @@ -730,8 +727,8 @@ - - + + @@ -746,14 +743,14 @@ - + - + @@ -778,7 +775,7 @@ - + diff --git a/src/main/java/jcs/ui/JCSFrame.java b/src/main/java/jcs/ui/JCSFrame.java index 7fdaba69..2831a558 100755 --- a/src/main/java/jcs/ui/JCSFrame.java +++ b/src/main/java/jcs/ui/JCSFrame.java @@ -81,6 +81,8 @@ */ public class JCSFrame extends JFrame implements UICallback, DisconnectionEventListener { + private static final long serialVersionUID = -5800900684173242844L; + private final Map actionMap; private FeedbackMonitor feedbackMonitor; @@ -99,8 +101,10 @@ public JCSFrame() { if (SystemInfo.isMacFullWindowContentSupported) { this.getRootPane().putClientProperty("apple.awt.transparentTitleBar", true); this.getRootPane().putClientProperty("apple.awt.fullWindowContent", true); - this.getRootPane().putClientProperty("apple.awt.transparentTitleBar", true); //this.getRootPane().putClientProperty( "apple.awt.windowTitleVisible", false ); + + this.getRootPane().putClientProperty("apple.awt.brushMetalLook", true); + } initJCS(); @@ -108,6 +112,7 @@ public JCSFrame() { if (SystemInfo.isMacFullWindowContentSupported) { //avoid overlap of the red/orange/green buttons and the window title this.jcsToolBar.add(Box.createHorizontalStrut(70), 0); + //this.jcsToolBar.setb } initKeyStrokes(); @@ -135,18 +140,29 @@ private void initJCS() { } private void initKeyStrokes() { + KeyStroke keySpace = KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0); KeyStroke key0 = KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_DOWN_MASK); - actionMap.put(key0, new AbstractAction("stopAction") { + actionMap.put(keySpace, new AbstractAction("stopAction") { + private static final long serialVersionUID = -6536021676834946105L; + @Override public void actionPerformed(ActionEvent e) { - stop(); + powerButton.doClick(100); +// if(powerButton.isSelected()) { +// stop(); +// } else { +// +// } } }); KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager(); kfm.addKeyEventDispatcher((KeyEvent e) -> { KeyStroke keyStroke = KeyStroke.getKeyStrokeForEvent(e); + + Logger.trace("KeyCode: " + e.getKeyCode() + " ExtendedKeyCode: " + e.getExtendedKeyCode() + " Ctrl: " + e.isControlDown() + " Shift: " + e.isShiftDown()); + if (actionMap.containsKey(keyStroke)) { final Action a = actionMap.get(keyStroke); final ActionEvent ae = new ActionEvent(e.getSource(), e.getID(), null); @@ -338,9 +354,9 @@ public void windowClosing(WindowEvent evt) { toolbarPanel.setName("toolbarPanel"); // NOI18N toolbarPanel.setPreferredSize(new Dimension(1350, 52)); - FlowLayout flowLayout8 = new FlowLayout(FlowLayout.LEFT); - flowLayout8.setAlignOnBaseline(true); - toolbarPanel.setLayout(flowLayout8); + FlowLayout flowLayout2 = new FlowLayout(FlowLayout.LEFT); + flowLayout2.setAlignOnBaseline(true); + toolbarPanel.setLayout(flowLayout2); jcsToolBar.setMaximumSize(new Dimension(1050, 42)); jcsToolBar.setMinimumSize(new Dimension(1000, 42)); @@ -854,6 +870,7 @@ public void actionPerformed(ActionEvent evt) { setJMenuBar(jcsMenuBar); pack(); + setLocationRelativeTo(null); }// //GEN-END:initComponents private void showLocosMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_showLocosMIActionPerformed @@ -900,7 +917,7 @@ private void showOverviewBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_ private void powerButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_powerButtonActionPerformed boolean on = ((JToggleButton) evt.getSource()).isSelected(); - Logger.trace("Switch Power "+(on?"On":"Off")); + Logger.trace("Switch Power " + (on ? "On" : "Off")); if (JCS.getJcsCommandStation() != null) { JCS.getJcsCommandStation().switchPower(on); } diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.java b/src/main/java/jcs/ui/layout/LayoutCanvas.java index a1914b97..a062670c 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.java +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.java @@ -75,7 +75,9 @@ * This canvas / Panel is used to draw the layout * */ -public class LayoutCanvas extends JPanel { //implements PropertyChangeListener { +public class LayoutCanvas extends JPanel { + + private static final long serialVersionUID = 9075914241802892566L; public enum Mode { SELECT, diff --git a/src/main/java/jcs/ui/layout/LayoutPanel.java b/src/main/java/jcs/ui/layout/LayoutPanel.java index 932cbcfd..3ffacdd6 100755 --- a/src/main/java/jcs/ui/layout/LayoutPanel.java +++ b/src/main/java/jcs/ui/layout/LayoutPanel.java @@ -932,8 +932,8 @@ private void setTileType(TileBean.TileType tileType) { private void setDirection(Direction direction) { this.canvas.setDirection(direction); } - - private void setMode(LayoutCanvas.Mode mode) { + + public void setMode(LayoutCanvas.Mode mode) { switch (mode) { case SELECT -> { selectBtn.setIcon(new ImageIcon(getClass().getResource("/media/cursor-24-y.png"))); diff --git a/src/main/java/jcs/ui/options/LocomotivePreferencesPanel.java b/src/main/java/jcs/ui/options/LocomotivePreferencesPanel.java index f32b9790..4d55800d 100755 --- a/src/main/java/jcs/ui/options/LocomotivePreferencesPanel.java +++ b/src/main/java/jcs/ui/options/LocomotivePreferencesPanel.java @@ -90,6 +90,8 @@ */ public class LocomotivePreferencesPanel extends JPanel implements PropertyChangeListener { + private static final long serialVersionUID = -2076222213624366106L; + private final LocomotiveBeanListModel locoListModel; private CommandStationBean commandStationBean; private LocomotiveBean selectedLocomotive; diff --git a/src/main/java/jcs/ui/util/FrameMonitor.java b/src/main/java/jcs/ui/util/FrameMonitor.java index 9d147899..cfe31396 100644 --- a/src/main/java/jcs/ui/util/FrameMonitor.java +++ b/src/main/java/jcs/ui/util/FrameMonitor.java @@ -49,6 +49,10 @@ public static void registerFrame(JFrame frame, String frameUniqueId) { } public static void registerFrame(JFrame frame, String frameUniqueId, int defaultX, int defaultY, int defaultW, int defaultH) { + if (System.getProperty("disable.ui.pref.storage", "false").equalsIgnoreCase("true")) { + return; + } + Preferences prefs = Preferences.userRoot().node(FrameMonitor.class.getSimpleName() + "-" + frameUniqueId); frame.setLocation(getFrameLocation(prefs, defaultX, defaultY)); @@ -70,13 +74,17 @@ public void componentMoved(ComponentEvent e) { } private static void updatePref(JFrame frame, Preferences prefs) { + if (System.getProperty("disable.ui.pref.storage", "false").equalsIgnoreCase("true")) { + return; + } + Point location = frame.getLocation(); prefs.putInt("x", location.x); prefs.putInt("y", location.y); Dimension size = frame.getSize(); prefs.putInt("w", size.width); prefs.putInt("h", size.height); - Logger.trace("Updated prefs for " + frame.getClass().getSimpleName()+" Pos: ("+location.x+","+location.y+") Size W: "+size.width+" H: "+size.height); + Logger.trace("Updated prefs for " + frame.getClass().getSimpleName() + " Pos: (" + location.x + "," + location.y + ") Size W: " + size.width + " H: " + size.height); } private static Dimension getFrameSize(Preferences pref, int defaultW, int defaultH) { From e6a75d549d5157d5687fe0f14240582ba8936d77 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Thu, 13 Mar 2025 20:47:25 +0100 Subject: [PATCH 34/70] Start with catching Key events WIP --- src/main/java/jcs/ui/JCSFrame.java | 225 +++++++++++++----- src/main/java/jcs/ui/layout/LayoutCanvas.java | 163 ++++++------- src/main/resources/tinylog.properties | 2 +- 3 files changed, 249 insertions(+), 141 deletions(-) diff --git a/src/main/java/jcs/ui/JCSFrame.java b/src/main/java/jcs/ui/JCSFrame.java index 2831a558..10ec7927 100755 --- a/src/main/java/jcs/ui/JCSFrame.java +++ b/src/main/java/jcs/ui/JCSFrame.java @@ -93,10 +93,11 @@ public JCSFrame() { actionMap = new HashMap<>(); initComponents(); + //TODO: see https://www.formdev.com/flatlaf/macos/ if (RunUtil.isMacOSX()) { - this.quitMI.setVisible(false); - this.optionsMI.setVisible(false); - this.toolsMenu.setVisible(false); + quitMI.setVisible(false); + optionsMI.setVisible(false); + toolsMenu.setVisible(false); if (SystemInfo.isMacFullWindowContentSupported) { this.getRootPane().putClientProperty("apple.awt.transparentTitleBar", true); @@ -114,9 +115,8 @@ public JCSFrame() { this.jcsToolBar.add(Box.createHorizontalStrut(70), 0); //this.jcsToolBar.setb } - - initKeyStrokes(); } + initKeyStrokes(); } private void initJCS() { @@ -139,32 +139,141 @@ private void initJCS() { } } + private class PowerAction extends AbstractAction { + + private static final long serialVersionUID = 4263882874269440066L; + + @Override + public void actionPerformed(ActionEvent e) { + powerButton.doClick(50); + } + } + + private class QuitAction extends AbstractAction { + + private static final long serialVersionUID = 106411709893099942L; + + @Override + public void actionPerformed(ActionEvent e) { + QuitApp(); + } + } + + private class ShowMonitorAction extends AbstractAction { + + private static final long serialVersionUID = -3352181383049583600L; + + @Override + public void actionPerformed(ActionEvent e) { + showSensorMonitor(); + } + } + + private class HomeAction extends AbstractAction { + + private static final long serialVersionUID = 6369350924548859534L; + + @Override + public void actionPerformed(ActionEvent e) { + showOverviewPanel(); + } + } + + private class SelectModeKeyAction extends AbstractAction { + + private static final long serialVersionUID = -5543240676519086334L; + + @Override + public void actionPerformed(ActionEvent e) { + Logger.info("Select"); + } + } + + private class AddModeKeyAction extends AbstractAction { + + private static final long serialVersionUID = -429465825958791906L; + + @Override + public void actionPerformed(ActionEvent e) { + Logger.info("Add"); + } + } + + private class DeleteModeKeyAction extends AbstractAction { + + private static final long serialVersionUID = 569113006687591145L; + + @Override + public void actionPerformed(ActionEvent e) { + Logger.info("Delete"); + } + } + + private class RotateKeyAction extends AbstractAction { + + private static final long serialVersionUID = -292237743142583719L; + + @Override + public void actionPerformed(ActionEvent e) { + Logger.info("Rotate"); + } + } + + private class FlipHorizontalKeyAction extends AbstractAction { + + private static final long serialVersionUID = 7657976620206362097L; + + @Override + public void actionPerformed(ActionEvent e) { + Logger.info("Flip Horizontal"); + } + } + + private class FlipVerticalKeyAction extends AbstractAction { + + private static final long serialVersionUID = -4269202419142803636L; + + @Override + public void actionPerformed(ActionEvent e) { + Logger.info("Flip Vertical"); + } + } + private void initKeyStrokes() { KeyStroke keySpace = KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0); - KeyStroke key0 = KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_DOWN_MASK); - - actionMap.put(keySpace, new AbstractAction("stopAction") { - private static final long serialVersionUID = -6536021676834946105L; - - @Override - public void actionPerformed(ActionEvent e) { - powerButton.doClick(100); -// if(powerButton.isSelected()) { -// stop(); -// } else { -// -// } - } - }); + KeyStroke keyQuit = KeyStroke.getKeyStroke(KeyEvent.VK_Q, KeyEvent.CTRL_DOWN_MASK); + KeyStroke keySensorMonitor = KeyStroke.getKeyStroke(KeyEvent.VK_M, KeyEvent.CTRL_DOWN_MASK); + KeyStroke keyHome = KeyStroke.getKeyStroke(KeyEvent.VK_H, KeyEvent.CTRL_DOWN_MASK); + + //Edit screen + KeyStroke keyModeSelect = KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.ALT_DOWN_MASK); + KeyStroke keyModeAdd = KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.ALT_DOWN_MASK); + KeyStroke keyModeDelete = KeyStroke.getKeyStroke(KeyEvent.VK_D, KeyEvent.ALT_DOWN_MASK); + + KeyStroke keyRotate = KeyStroke.getKeyStroke(KeyEvent.VK_R, KeyEvent.ALT_DOWN_MASK); + KeyStroke keyFlipHorizontal = KeyStroke.getKeyStroke(KeyEvent.VK_H, KeyEvent.ALT_DOWN_MASK); + KeyStroke keyFlipVertical = KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.ALT_DOWN_MASK); + + actionMap.put(keySpace, new PowerAction()); + actionMap.put(keyQuit, new QuitAction()); + actionMap.put(keySensorMonitor, new ShowMonitorAction()); + actionMap.put(keyHome, new HomeAction()); + + actionMap.put(keyModeSelect, new SelectModeKeyAction()); + actionMap.put(keyModeAdd, new AddModeKeyAction()); + actionMap.put(keyModeDelete, new DeleteModeKeyAction()); + + actionMap.put(keyRotate, new RotateKeyAction()); + actionMap.put(keyFlipHorizontal, new FlipHorizontalKeyAction()); + actionMap.put(keyFlipVertical, new FlipVerticalKeyAction()); KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager(); kfm.addKeyEventDispatcher((KeyEvent e) -> { KeyStroke keyStroke = KeyStroke.getKeyStrokeForEvent(e); - Logger.trace("KeyCode: " + e.getKeyCode() + " ExtendedKeyCode: " + e.getExtendedKeyCode() + " Ctrl: " + e.isControlDown() + " Shift: " + e.isShiftDown()); - if (actionMap.containsKey(keyStroke)) { final Action a = actionMap.get(keyStroke); + final ActionEvent ae = new ActionEvent(e.getSource(), e.getID(), null); SwingUtilities.invokeLater(() -> { a.actionPerformed(ae); @@ -176,22 +285,21 @@ public void actionPerformed(ActionEvent e) { } public void showExtraToolbar(JToolBar toolbar) { - this.jcsToolBar.add(toolbar); + jcsToolBar.add(toolbar); jcsToolBar.doLayout(); - this.toolbarPanel.repaint(); + toolbarPanel.repaint(); } public void hideExtraToolbar(JToolBar toolbar) { - this.jcsToolBar.remove(toolbar); + jcsToolBar.remove(toolbar); jcsToolBar.doLayout(); - this.toolbarPanel.repaint(); - //this.repaint(); + toolbarPanel.repaint(); } public void showOverviewPanel() { - CardLayout card = (CardLayout) this.centerPanel.getLayout(); - card.show(this.centerPanel, "overviewPanel"); - this.overviewPanel.loadLayout(); + CardLayout card = (CardLayout) centerPanel.getLayout(); + card.show(centerPanel, "overviewPanel"); + overviewPanel.loadLayout(); } public void showLocomotives() { @@ -228,13 +336,7 @@ public void showDesignLayoutPanel() { if (!AutoPilot.isAutoModeActive()) { CardLayout card = (CardLayout) this.centerPanel.getLayout(); card.show(this.centerPanel, "designPanel"); - this.layoutPanel.loadLayout(); - } - } - - public void stop() { - if (JCS.getJcsCommandStation() != null) { - JCS.getJcsCommandStation().switchPower(false); + layoutPanel.loadLayout(); } } @@ -255,7 +357,7 @@ private void setControllerProperties() { this.powerButton.setSelected(connected); } boolean virt = JCS.getJcsCommandStation().isVirtual(); - this.virtualCB.setSelected(virt); + virtualCB.setSelected(virt); } } @@ -265,7 +367,7 @@ private void showSensorMonitor() { feedbackMonitor = new FeedbackMonitor(); FrameMonitor.registerFrame(feedbackMonitor, FeedbackMonitor.class.getName()); } - this.feedbackMonitor.showMonitor(); + feedbackMonitor.showMonitor(); } /** @@ -886,20 +988,7 @@ private void quitMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_quitMIAct }//GEN-LAST:event_quitMIActionPerformed private void formWindowClosing(WindowEvent evt) {//GEN-FIRST:event_formWindowClosing - boolean closed = this.handleQuitRequest(); - if (closed) { - setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - setVisible(false); - dispose(); - - //Disconnect Command stations - JCS.getJcsCommandStation().switchPower(false); - JCS.getJcsCommandStation().disconnect(); - - //Force close ports - SerialPortUtil.closeAllPorts(); - Logger.debug("Shutting down"); - } + QuitApp(); }//GEN-LAST:event_formWindowClosing private void optionsMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_optionsMIActionPerformed @@ -912,7 +1001,6 @@ private void showEditDesignBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:even private void showOverviewBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_showOverviewBtnActionPerformed showOverviewPanel(); - overviewPanel.loadLayout(); }//GEN-LAST:event_showOverviewBtnActionPerformed private void powerButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_powerButtonActionPerformed @@ -927,6 +1015,26 @@ private void showFeedbackMonitorBtnActionPerformed(ActionEvent evt) {//GEN-FIRST showSensorMonitor(); }//GEN-LAST:event_showFeedbackMonitorBtnActionPerformed + private boolean QuitApp() { + int result = JOptionPane.showConfirmDialog(this, "Are you sure you want to exit JCS?", "Exit JCS", JOptionPane.YES_NO_OPTION); + if (result == JOptionPane.YES_OPTION) { + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setVisible(false); + dispose(); + + //Disconnect Command stations + JCS.getJcsCommandStation().switchPower(false); + JCS.getJcsCommandStation().disconnect(); + + //Force close ports + SerialPortUtil.closeAllPorts(); + Logger.debug("Shutting down"); + //Force! + System.exit(0); + } + return false; + } + public void connect(boolean connect) { boolean connected = false; if (JCS.getJcsCommandStation() != null) { @@ -977,7 +1085,6 @@ private void connectButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_co private void showHomeActionPerformed(ActionEvent evt) {//GEN-FIRST:event_showHomeActionPerformed showOverviewPanel(); - this.overviewPanel.loadLayout(); }//GEN-LAST:event_showHomeActionPerformed private void editLayoutActionPerformed(ActionEvent evt) {//GEN-FIRST:event_editLayoutActionPerformed @@ -995,7 +1102,7 @@ private void showSensorMonitorActionPerformed(ActionEvent evt) {//GEN-FIRST:even private void connectMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_connectMIActionPerformed boolean connect = "Connect".equals(((JMenuItem) evt.getSource()).getText()); connect(connect); - this.connectButton.setSelected(connect); + connectButton.setSelected(connect); }//GEN-LAST:event_connectMIActionPerformed private void commandStationsMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_commandStationsMIActionPerformed @@ -1078,8 +1185,7 @@ public void onDisconnect(DisconnectionEvent event) { @Override public boolean handleQuitRequest() { - int result = JOptionPane.showConfirmDialog(this, "Are you sure you want to exit JCS?", "Exit JCS", JOptionPane.YES_NO_OPTION); - return result == JOptionPane.YES_OPTION; + return QuitApp(); } @Override @@ -1107,10 +1213,9 @@ public void handlePreferences() { } public void powerChanged(PowerEvent event) { - this.powerButton.setSelected(event.isPower()); + powerButton.setSelected(event.isPower()); } - // Variables declaration - do not modify//GEN-BEGIN:variables private JMenuItem aboutMI; private JToggleButton autoPilotBtn; diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.java b/src/main/java/jcs/ui/layout/LayoutCanvas.java index a062670c..d5da470c 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.java +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.java @@ -26,16 +26,19 @@ import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import javax.swing.AbstractAction; import javax.swing.JFrame; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; +import javax.swing.KeyStroke; import javax.swing.SwingUtilities; import jcs.commandStation.autopilot.AutoPilot; import jcs.entities.BlockBean; @@ -75,7 +78,7 @@ * This canvas / Panel is used to draw the layout * */ -public class LayoutCanvas extends JPanel { +public class LayoutCanvas extends JPanel { private static final long serialVersionUID = 9075914241802892566L; @@ -87,38 +90,38 @@ public enum Mode { DELETE, CONTROL } - + static final int LINE_GRID = 0; static final int DOT_GRID = 1; - + private int gridType = LINE_GRID; - + private boolean readonly; private Mode mode; private boolean drawGrid = true; - + private Orientation orientation; private Direction direction; private TileType tileType; - + private Point mouseLocation = new Point(); - + private final ExecutorService executor; - + private Tile selectedTile; - + private RoutesDialog routesDialog; - + public LayoutCanvas() { this(false); } - + public LayoutCanvas(boolean readonly) { super(); setLayout(null); setOpaque(true); setDoubleBuffered(true); - + this.readonly = readonly; this.executor = Executors.newSingleThreadExecutor(); //this.executor = Executors.newCachedThreadPool(); @@ -126,24 +129,24 @@ public LayoutCanvas(boolean readonly) { this.mode = Mode.SELECT; this.orientation = Orientation.EAST; this.direction = Direction.CENTER; - + initComponents(); postInit(); } - + private void postInit() { routesDialog = new RoutesDialog(getParentFrame(), false, this, this.readonly); } - + public boolean isReadonly() { return readonly; } - + @Override public void paint(Graphics g) { //long started = System.currentTimeMillis(); super.paint(g); - + if (drawGrid) { if (this.gridType == LINE_GRID) { paintLineGrid(g); @@ -155,7 +158,7 @@ public void paint(Graphics g) { //long now = System.currentTimeMillis(); //Logger.trace("Duration: " + (now - started) + " ms."); } - + @Override public Component add(Component component) { super.add(component); @@ -164,7 +167,7 @@ public Component add(Component component) { } return component; } - + @Override public Component add(String name, Component component) { if (component instanceof Tile tile) { @@ -175,14 +178,14 @@ public Component add(String name, Component component) { } return component; } - + private void paintDotGrid(Graphics g) { int width = getWidth(); int height = getHeight(); Graphics2D gc = (Graphics2D) g; Paint p = gc.getPaint(); gc.setPaint(Color.black); - + int xOffset = 0; int yOffset = 0; for (int r = 0; r < width; r++) { @@ -192,7 +195,7 @@ private void paintDotGrid(Graphics g) { } gc.setPaint(p); } - + private void paintLineGrid(Graphics g) { int width = getWidth(); int height = getHeight(); @@ -200,7 +203,7 @@ private void paintLineGrid(Graphics g) { Paint p = gc.getPaint(); gc.setPaint(Color.black); gc.setPaint(Color.lightGray); - + gc.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); for (int x = 0; x < width; x += 40) { gc.drawLine(x, 0, x, height); @@ -210,12 +213,12 @@ private void paintLineGrid(Graphics g) { } gc.setPaint(p); } - + void setMode(LayoutCanvas.Mode mode) { this.mode = mode; Logger.trace("Mode: " + mode); } - + void setDrawGrid(boolean flag) { if (flag) { switch (gridType) { @@ -230,16 +233,16 @@ void setDrawGrid(boolean flag) { drawGrid = flag; repaint(); } - + void setTileType(TileBean.TileType tileType) { this.tileType = tileType; Logger.trace("TileType: " + tileType + " Current mode: " + mode); } - + void setDirection(Direction direction) { this.direction = direction; } - + void loadLayoutInBackground() { this.executor.execute(() -> loadTiles()); @@ -254,13 +257,13 @@ void loadLayoutInBackground() { // } // }).start(); } - + private void loadTiles() { List tiles = TileCache.loadTiles(readonly); - + removeAll(); selectedTile = null; - + Dimension minSize = TileCache.getMinCanvasSize(); setMinimumSize(minSize); @@ -276,13 +279,13 @@ private void loadTiles() { h = minSize.height; changeSize = true; } - + if (changeSize) { setPreferredSize(new Dimension(w, h)); setSize(new Dimension(w, h)); Logger.trace("Changed size to w: " + w + " h: " + h); } - + for (Tile tile : tiles) { add(tile); boolean showCenter = "true".equalsIgnoreCase(System.getProperty("tile.show.center", "false")); @@ -291,7 +294,7 @@ private void loadTiles() { } } } - + private void mouseMoveAction(MouseEvent evt) { Point sp = LayoutUtil.snapToGrid(evt.getPoint()); if (selectedTile != null) { @@ -300,7 +303,7 @@ private void mouseMoveAction(MouseEvent evt) { setCursor(Cursor.getDefaultCursor()); } } - + private void mousePressedAction(MouseEvent evt) { Logger.trace("@ (" + evt.getX() + "," + evt.getY() + ")"); Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); @@ -311,13 +314,13 @@ private void mousePressedAction(MouseEvent evt) { if (selectedTile != null && CONTROL != mode) { selectedTile.setSelected(true); } - + if (previousSelected != null && selectedTile != null && previousSelected.getId().equals(selectedTile.getId())) { Logger.trace("Same tile " + selectedTile.getId() + " selected"); } else if (previousSelected != null) { previousSelected.setSelected(false); } - + switch (mode) { case CONTROL -> { if (selectedTile != null) { @@ -368,11 +371,11 @@ private void mousePressedAction(MouseEvent evt) { } } } - + private Tile addTile(Point p, TileType tileType, Orientation orientation, Direction direction, boolean selected, boolean showCenter) { Logger.trace("Adding: " + tileType + " @ " + p + " O: " + orientation + " D: " + direction); Tile tile = TileCache.createTile(tileType, orientation, direction, p); - + if (TileCache.canMoveTo(tile, p)) { tile.setSelected(selected); tile.setDrawCenterPoint(showCenter); @@ -386,7 +389,7 @@ private Tile addTile(Point p, TileType tileType, Orientation orientation, Direct return null; } } - + void removeTile(Tile tile) { Tile toBeDeleted = (Tile) getComponentAt(tile.getCenter()); if (toBeDeleted != null) { @@ -395,7 +398,7 @@ void removeTile(Tile tile) { TileCache.deleteTile(tile); } } - + private void mouseDragAction(MouseEvent evt) { //Logger.trace("@ (" + evt.getX() + "," + evt.getY() + ")"); Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); @@ -403,13 +406,13 @@ private void mouseDragAction(MouseEvent evt) { int z = getComponentZOrder(selectedTile); setComponentZOrder(selectedTile, 0); Logger.trace("Moving: " + selectedTile.getId() + " @ " + selectedTile.xyToString() + " P: " + snapPoint.x + "," + snapPoint.y + ")"); - + if (TileCache.canMoveTo(selectedTile, snapPoint)) { selectedTile.setSelectedColor(Tile.DEFAULT_SELECTED_COLOR); } else { selectedTile.setSelectedColor(Tile.DEFAULT_WARN_COLOR); } - + int curX, curY; switch (selectedTile.getTileType()) { case BLOCK -> { @@ -450,7 +453,7 @@ private void mouseDragAction(MouseEvent evt) { selectedTile.setBounds(curX, curY, selectedTile.getWidth(), selectedTile.getHeight()); } } - + private void mouseReleasedAction(MouseEvent evt) { Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); if (!Mode.CONTROL.equals(mode) && MouseEvent.BUTTON1 == evt.getButton() && selectedTile != null) { @@ -462,7 +465,7 @@ private void mouseReleasedAction(MouseEvent evt) { } } } - + private void executeControlActionForTile(Tile tile, Point p) { TileBean.TileType tt = tile.getTileType(); switch (tt) { @@ -479,7 +482,7 @@ private void executeControlActionForTile(Tile tile, Point p) { Block block = (Block) tile; BlockControlDialog bcd = new BlockControlDialog(getParentFrame(), block); bcd.setVisible(true); - + Logger.trace("Block properties closed"); this.repaint(block.getTileBounds()); } @@ -496,7 +499,7 @@ private void executeControlActionForTile(Tile tile, Point p) { } } } - + private void editSelectedTileProperties() { //the first tile should be the selected one boolean showProperties = false; @@ -504,11 +507,11 @@ private void editSelectedTileProperties() { boolean showRotate = false; boolean showMove = false; boolean showDelete = false; - + if (selectedTile != null) { TileBean.TileType tt = selectedTile.getTileType(); Logger.trace("Selected tile " + selectedTile.getId() + " TileType " + tt); - + switch (tt) { case END -> { showRotate = true; @@ -553,7 +556,7 @@ private void editSelectedTileProperties() { repaint(); } } - + private void showBlockPopupMenu(Tile tile, Point p) { if (tile == null || p == null) { return; @@ -569,18 +572,18 @@ private void showBlockPopupMenu(Tile tile, Point p) { this.toggleLocomotiveDirectionMI.setEnabled(hasLoco); this.reverseArrivalSideMI.setEnabled(hasLoco); this.resetGhostMI.setEnabled(isGhost); - + this.toggleOutOfOrderMI.setEnabled(!hasLoco); - + if (BlockBean.BlockState.OUT_OF_ORDER == ((Block) tile).getBlockState()) { this.toggleOutOfOrderMI.setText("Enable Block"); } else { this.toggleOutOfOrderMI.setText("Set Out of Order"); } - + this.blockPopupMenu.show(this, p.x, p.y); } - + private void showOperationsPopupMenu(Tile tile, Point p) { if (tile == null || p == null) { return; @@ -594,7 +597,7 @@ private void showOperationsPopupMenu(Tile tile, Point p) { boolean showMove = false; @SuppressWarnings("UnusedAssignment") boolean showDelete = false; - + TileType tt = tile.getTileType(); switch (tt) { case SENSOR -> { @@ -630,16 +633,16 @@ private void showOperationsPopupMenu(Tile tile, Point p) { } } this.xyMI.setVisible(true); - + String extra = ""; if (tile instanceof Sensor s) { if (s.getSensorBean() != null) { extra = " " + s.getSensorBean().getName(); } } - + this.xyMI.setText(tile.getId() + extra + " (" + p.x + "," + p.y + ") O: " + tile.getOrientation().getOrientation() + " D: " + tile.getDirection()); - + this.propertiesMI.setVisible(showProperties); this.flipHorizontalMI.setVisible(showFlip); this.flipVerticalMI.setVisible(showFlip); @@ -648,36 +651,36 @@ private void showOperationsPopupMenu(Tile tile, Point p) { this.deleteMI.setVisible(showDelete); this.operationsPM.show(this, p.x, p.y); } - + private JFrame getParentFrame() { JFrame frame = (JFrame) SwingUtilities.getRoot(this); return frame; } - + public void rotateSelectedTile() { Logger.trace("Selected Tile " + selectedTile.getId()); selectedTile = TileCache.rotateTile(selectedTile); selectedTile.setBounds(selectedTile.getTileBounds()); } - + public void flipSelectedTileHorizontal() { selectedTile = TileCache.flipHorizontal(selectedTile); selectedTile.setBounds(selectedTile.getTileBounds()); } - + public void flipSelectedTileVertical() { selectedTile = TileCache.flipVertical(selectedTile); selectedTile.setBounds(selectedTile.getTileBounds()); } - + void routeLayout() { this.executor.execute(() -> routeLayoutWithAStar()); } - + private void routeLayoutWithAStar() { //Make sure the layout is saved TileCache.persistAllTiles(); - + AStar astar = new AStar(); astar.buildGraph(TileCache.getTiles()); astar.routeAll(); @@ -686,7 +689,7 @@ private void routeLayoutWithAStar() { routesDialog.loadRoutes(); } } - + void showRoutesDialog() { routesDialog.setVisible(true); } @@ -912,7 +915,7 @@ private void formMouseReleased(MouseEvent evt) {//GEN-FIRST:event_formMouseRelea private void horizontalMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_horizontalMIActionPerformed Logger.trace(this.orientation + ", " + evt.getModifiers() + ", " + evt.paramString()); - + if (this.mouseLocation != null && evt.getModifiers() == ActionEvent.MOUSE_EVENT_MASK) { this.mouseLocation = null; } @@ -920,7 +923,7 @@ private void horizontalMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_hor private void verticalMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_verticalMIActionPerformed Logger.trace(this.orientation + ", " + evt.getModifiers() + ", " + evt.paramString()); - + if (this.mouseLocation != null && evt.getModifiers() == ActionEvent.MOUSE_EVENT_MASK) { this.mouseLocation = null; } @@ -928,7 +931,7 @@ private void verticalMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_verti private void rightMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_rightMIActionPerformed Logger.trace(this.orientation + ", " + evt.getModifiers() + ", " + evt.paramString()); - + if (this.mouseLocation != null && evt.getModifiers() == ActionEvent.MOUSE_EVENT_MASK) { this.mouseLocation = null; } @@ -936,7 +939,7 @@ private void rightMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_rightMIA private void leftMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_leftMIActionPerformed Logger.trace(this.orientation + ", " + evt.getModifiers() + ", " + evt.paramString()); - + if (this.mouseLocation != null && evt.getModifiers() == ActionEvent.MOUSE_EVENT_MASK) { this.mouseLocation = null; } @@ -998,7 +1001,7 @@ private void resetDispatcherMIActionPerformed(ActionEvent evt) {//GEN-FIRST:even if (this.selectedTile != null) { Block block = (Block) selectedTile; LocomotiveBean locomotive = block.getBlockBean().getLocomotive(); - + this.executor.execute(() -> { AutoPilot.resetDispatcher(locomotive); repaint(); @@ -1010,13 +1013,13 @@ private void removeLocMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_remo if (selectedTile != null && selectedTile.isBlock()) { LocomotiveBean locomotive = selectedTile.getLocomotive(); locomotive.setDispatcherDirection(null); - + selectedTile.setLocomotive(null); - + executor.execute(() -> { PersistenceFactory.getService().persist(selectedTile.getBlockBean()); PersistenceFactory.getService().persist(locomotive); - + AutoPilot.removeLocomotive(locomotive); }); } @@ -1027,7 +1030,7 @@ private void blockPropertiesMIActionPerformed(ActionEvent evt) {//GEN-FIRST:even //show the Block control dialog so tha a locomotive can be assigned to the block BlockControlDialog bcd = new BlockControlDialog(getParentFrame(), (Block) selectedTile); bcd.setVisible(true); - + repaint(selectedTile.getTileBounds()); } }//GEN-LAST:event_blockPropertiesMIActionPerformed @@ -1035,7 +1038,7 @@ private void blockPropertiesMIActionPerformed(ActionEvent evt) {//GEN-FIRST:even private void reverseArrivalSideMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_reverseArrivalSideMIActionPerformed if (this.selectedTile != null) { Block block = (Block) selectedTile; - + String suffix = block.getArrivalSuffix(); if ("+".equals(suffix)) { block.setArrivalSuffix("-"); @@ -1053,7 +1056,7 @@ private void toggleLocomotiveDirectionMIActionPerformed(ActionEvent evt) {//GEN- if (selectedTile != null) { Block block = (Block) selectedTile; LocomotiveBean locomotive = block.getLocomotive(); - + LocomotiveBean.Direction curDir; if (block.getLogicalDirection() != null) { curDir = block.getLogicalDirection(); @@ -1063,7 +1066,7 @@ private void toggleLocomotiveDirectionMIActionPerformed(ActionEvent evt) {//GEN- LocomotiveBean.Direction newDir = LocomotiveBean.toggle(curDir); block.setLogicalDirection(newDir); Logger.trace(block.getId() + " LogicalDir changed from " + curDir + " to " + newDir + " for " + locomotive.getName()); - + this.executor.execute(() -> { PersistenceFactory.getService().persist(block.getTileBean()); }); @@ -1079,7 +1082,7 @@ private void toggleOutOfOrderMIActionPerformed(ActionEvent evt) {//GEN-FIRST:eve } else if (BlockState.OUT_OF_ORDER == currentState) { block.setBlockState(BlockState.FREE); } - + if (currentState != block.getBlockState()) { this.executor.execute(() -> { PersistenceFactory.getService().persist(block.getBlockBean()); @@ -1092,7 +1095,7 @@ private void resetGhostMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_res if (this.selectedTile != null) { Block block = (Block) selectedTile; BlockBean.BlockState currentState = block.getBlockState(); - + if (BlockBean.BlockState.GHOST == currentState) { if (block.getLocomotive() != null) { block.setBlockState(BlockBean.BlockState.OCCUPIED); diff --git a/src/main/resources/tinylog.properties b/src/main/resources/tinylog.properties index 7e4f6c98..50d15434 100755 --- a/src/main/resources/tinylog.properties +++ b/src/main/resources/tinylog.properties @@ -35,5 +35,5 @@ exception = strip: jdk.internal level@jcs.util = info #level@jcs.commandStation = debug -level@jcs.ui.layout = info +#level@jcs.ui.layout = info level@jcs.commandStation.esu.ecos.EcosMessage = info \ No newline at end of file From 0b6f12abcb6f8a7d7511c524491a5a79c9898e49 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Sat, 15 Mar 2025 14:41:51 +0100 Subject: [PATCH 35/70] GUI refactoring replaced the feedback monitor by a Dialog WIP --- JCS_SETUP_NL.md | 8 +- README.md | 13 +- src/main/java/jcs/JCS.java | 123 +++++++-- src/main/java/jcs/ui/DriverCabFrame.java | 8 +- ...Monitor.form => FeedbackSensorDialog.form} | 100 +++---- ...Monitor.java => FeedbackSensorDialog.java} | 170 ++++++------ src/main/java/jcs/ui/JCSFrame.form | 132 +++++++-- src/main/java/jcs/ui/JCSFrame.java | 252 +++++++++++++----- src/main/java/jcs/ui/util/FrameMonitor.java | 67 ++++- src/main/java/jcs/ui/util/MacOsAdapter.java | 206 -------------- 10 files changed, 612 insertions(+), 467 deletions(-) rename src/main/java/jcs/ui/{monitor/FeedbackMonitor.form => FeedbackSensorDialog.form} (94%) rename src/main/java/jcs/ui/{monitor/FeedbackMonitor.java => FeedbackSensorDialog.java} (74%) delete mode 100755 src/main/java/jcs/ui/util/MacOsAdapter.java diff --git a/JCS_SETUP_NL.md b/JCS_SETUP_NL.md index 0e343ae5..2e7291ff 100644 --- a/JCS_SETUP_NL.md +++ b/JCS_SETUP_NL.md @@ -18,16 +18,16 @@ In JCS wordt een blok altijd gemarkeerd door twee sensoren. ## Het tekenen van de baan Wanneer JCS is gestart, selecteer je de Bewerken-knop om de bewerkingsmodus te activeren. -![Start Edit](assets/startedit.png) +![Start Edit](assets/startedit.png) Via toesenbord door Ctrl + E. JCS toont het scherm voor het bewerken van de baan. ![Start Edit](assets/layoutedittoolbar.png) De werkbalk bevat de meest voorkomende elementen om een baan te tekenen. Een plattegrond van een baan bestaat uit tegels. Een tegel stelt een component, zoals een recht stuk, sensor, blok, enz. voor. -Gebruik de __+__ knop om een tegel op het canvas toe te voegen. De prullenbakknop verwijdert een tegel. -Klik met de rechtermuisknop op een tegel om eigenschappen te bekijken of de tegel te draaien of om te keren indien van toepassing. -Wanneer een tegel is geselecteerd, kan deze naar de juiste positie worden gesleept. +Gebruik de __+__ knop, of via toetsenbord Alt + A om een tegel op het canvas toe te voegen. De prullenbakknop (Alt +D) verwijdert een tegel. +Klik met de rechtermuisknop op een tegel om eigenschappen te bekijken of de tegel te draaien (Alt + R) of om te keren (Alt + H of Alt + V), +indien van toepassing. Wanneer een tegel is geselecteerd, kan deze naar de juiste positie worden gesleept. Tegels worden automatisch opgeslagen. Het voorbeeld ziet er als volgt uit wanneer alle tegels op het canvas zijn geplaatst. diff --git a/README.md b/README.md index 4ff0d4cb..7d8018ff 100644 --- a/README.md +++ b/README.md @@ -15,14 +15,16 @@ JCS is a hobby project of me where I try to automate my Model Railway. Over the past years I have worked on and off on several aspects and modules of the software which are needed to drive automatically. A short summary of the topics which are needed and used to be able to drive trains automatically: -- Connectivity to the Command Station hardware. (DCC-EX,HSI-S88, Marklin CS2/3) +- Connectivity to the Command Station hardware. (DCC-EX,HSI-S88, Marklin CS2/3 ESU Ecos) - Edit and display graphically a layout - With the layout be able to route all the possible drive ways - Show the routes and driveways in the layout screen - Graphically feedback events on track to the layout screen +- Automatically run locomotives on the layout - Input dialogs to setup Accessories, Locomotives, Command stations, etc - Locomotive Drive Cap so tha you can manually run you locomotive - Virtual Command Station, to ease testing and simulate automatic driving +- Build in VNC viewer - Monitor Sensor events I created a [short video](https://youtu.be/xP6eUdScMY0) demonstrating automatic running of locomotives. Also a [video of pysical locomotives running on the Test Layout](https://www.youtube.com/watch?v=CyLmGk6gfHA) @@ -78,7 +80,7 @@ To debug or easly setup your feedback sensors ## Releases -- [First Release V 0.0.1](https://github.com/fransjacobs/model-railway/releases/tag/V0.0.1) +- [Latest Release V 0.0.2](https://github.com/fransjacobs/model-railway/releases/tag/V0.0.2) ## Supported Hardware @@ -94,10 +96,9 @@ To debug or easly setup your feedback sensors Currently the following feature are in development: - Documentation -- Internationalization enable multiple languages -- Add support for ESU ECOS -- Show Signal aspects in automatic driving - Enhance GUI +- Show Signal aspects in automatic driving +- Internationalization enable multiple languages - Add more Unit tests - ... @@ -125,7 +126,7 @@ Currently the following feature are in development: -## Copyright 2019 - 2024 Frans Jacobs +## Copyright 2019 - 2025 Frans Jacobs Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, diff --git a/src/main/java/jcs/JCS.java b/src/main/java/jcs/JCS.java index a5af8b9e..3189fe84 100755 --- a/src/main/java/jcs/JCS.java +++ b/src/main/java/jcs/JCS.java @@ -15,12 +15,25 @@ */ package jcs; +import java.awt.Desktop; import java.awt.GraphicsEnvironment; +import java.awt.Taskbar; +import java.awt.desktop.AboutEvent; +import java.awt.desktop.AboutHandler; +import java.awt.desktop.OpenFilesEvent; +import java.awt.desktop.OpenFilesHandler; +import java.awt.desktop.PreferencesEvent; +import java.awt.desktop.PreferencesHandler; +import java.awt.desktop.QuitEvent; +import java.awt.desktop.QuitHandler; +import java.awt.desktop.QuitResponse; +import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.List; +import javax.imageio.ImageIO; import javax.swing.ImageIcon; import javax.swing.JOptionPane; import javax.swing.UIManager; @@ -29,7 +42,6 @@ import jcs.commandStation.JCSCommandStationImpl; import jcs.commandStation.events.PowerEvent; import jcs.commandStation.events.PowerEventListener; -import jcs.commandStation.events.RefreshEvent; import jcs.commandStation.events.RefreshEventListener; import jcs.persistence.PersistenceFactory; import jcs.persistence.PersistenceService; @@ -37,8 +49,8 @@ import jcs.ui.JCSFrame; import jcs.ui.splash.JCSSplash; import jcs.ui.util.FrameMonitor; -import jcs.ui.util.MacOsAdapter; import jcs.ui.util.ProcessFactory; +import jcs.ui.util.UICallback; import jcs.util.RunUtil; import jcs.util.VersionInfo; import org.tinylog.Logger; @@ -55,10 +67,11 @@ public class JCS extends Thread { private static PersistenceService persistentStore; private static JCSCommandStation jcsCommandStation; - private static MacOsAdapter osAdapter; private static JCSFrame jcsFrame; private static String version; + private static UICallback uiCallback; + private final List refreshEventListeners; private JCS() { @@ -99,16 +112,34 @@ private void startGui() { JCS.logProgress("Check OS..."); if (RunUtil.isMacOSX()) { - MacOsAdapter.setMacOsProperties(); - osAdapter = new MacOsAdapter(); + + try { + Desktop desktop = Desktop.getDesktop(); + desktop.setAboutHandler(new JCSAboutHandler()); + desktop.setQuitHandler(new JCSQuitHandler()); + desktop.setPreferencesHandler(new JCSPreferencesHandler()); + + + Taskbar taskbar = Taskbar.getTaskbar(); + try { + //BufferedImage img = ImageIO.read(JCS.class.getResource("/media/jcs-train-64.png")); + BufferedImage img = ImageIO.read(JCS.class.getResource("/media/jcs-train-2-512.png")); + taskbar.setIconImage(img); + } catch (final UnsupportedOperationException e) { + Logger.warn("The os does not support: 'taskbar.setIconImage'"); + } catch (final SecurityException e) { + Logger.warn("There was a security exception for: 'taskbar.setIconImage'"); + } + + } catch (SecurityException | IllegalArgumentException | IOException ex) { + Logger.warn("Failed to register with MacOS: " + ex); + } + } java.awt.EventQueue.invokeLater(() -> { jcsFrame = new JCSFrame(); - - if (RunUtil.isMacOSX()) { - osAdapter.setUiCallback(jcsFrame); - } + JCS.uiCallback = jcsFrame; //URL iconUrl = JCS.class.getResource("/media/jcs-train-64.png"); URL iconUrl = JCS.class.getResource("/media/jcs-train-2-512.png"); @@ -159,20 +190,21 @@ public void run() { Logger.info("JCS " + VersionInfo.getVersion() + " session finished"); } - @Deprecated - public static void addRefreshListener(RefreshEventListener refreshListener) { - instance.refreshEventListeners.add(refreshListener); - } - @Deprecated - public static void removeRefreshListener(RefreshEventListener refreshListener) { - instance.refreshEventListeners.remove(refreshListener); - } +// @Deprecated +// public static void addRefreshListener(RefreshEventListener refreshListener) { +// instance.refreshEventListeners.add(refreshListener); +// } - public static void settingsChanged(RefreshEvent refreshEvent) { - for (RefreshEventListener rel : instance.refreshEventListeners) { - rel.onChange(refreshEvent); - } - } +// @Deprecated +// public static void removeRefreshListener(RefreshEventListener refreshListener) { +// instance.refreshEventListeners.remove(refreshListener); +// } + +// public static void settingsChanged(RefreshEvent refreshEvent) { +// for (RefreshEventListener rel : instance.refreshEventListeners) { +// rel.onChange(refreshEvent); +// } +// } public static JCS getInstance() { if (instance == null) { @@ -212,7 +244,6 @@ public static void main(String[] args) { //Load properties RunUtil.loadProperties(); - RunUtil.loadExternalProperties(); try { @@ -232,9 +263,20 @@ public static void main(String[] args) { System.exit(0); } + if (RunUtil.isMacOSX()) { + System.setProperty("apple.awt.application.name", "JCS"); + System.setProperty("apple.laf.useScreenMenuBar", "true"); + System.setProperty("apple.awt.application.appearance", "system"); + + } + splashScreen = new JCSSplash(); - splashScreen.showSplash(); + if ("true".equalsIgnoreCase(System.getProperty("disable.splash", "false"))) { + Logger.info("Splasscreen is disabled"); + } else { + splashScreen.showSplash(); + } splashScreen.setProgressMax(25); @@ -310,4 +352,37 @@ public void onPowerChange(PowerEvent event) { } } + private class JCSQuitHandler implements QuitHandler { + + @Override + public void handleQuitRequestWith(QuitEvent e, QuitResponse response) { + uiCallback.handleQuitRequest(); + } + } + + private class JCSAboutHandler implements AboutHandler { + + @Override + public void handleAbout(AboutEvent e) { + uiCallback.handleAbout(); + } + } + + private class JCSPreferencesHandler implements PreferencesHandler { + + @Override + public void handlePreferences(PreferencesEvent e) { + uiCallback.handlePreferences(); + } + } + + private class JCSOpenFilesHandler implements OpenFilesHandler { + + @Override + public void openFiles(OpenFilesEvent e) { + //STUB + uiCallback.openFiles(null); + } + } + } diff --git a/src/main/java/jcs/ui/DriverCabFrame.java b/src/main/java/jcs/ui/DriverCabFrame.java index 80ca25fe..b0601797 100644 --- a/src/main/java/jcs/ui/DriverCabFrame.java +++ b/src/main/java/jcs/ui/DriverCabFrame.java @@ -39,7 +39,6 @@ import jcs.entities.LocomotiveBean.Direction; import jcs.persistence.PersistenceFactory; import jcs.ui.util.ImageUtil; -import jcs.ui.util.MacOsAdapter; import jcs.util.RunUtil; import org.tinylog.Logger; @@ -49,6 +48,8 @@ */ public class DriverCabFrame extends javax.swing.JFrame implements LocomotiveDirectionEventListener { + private static final long serialVersionUID = 6139691226868043462L; + private List filteredLocos; List locoNames; @@ -320,7 +321,10 @@ public static void main(String args[]) { DriverCabFrame driverFrame = new DriverCabFrame(); if (RunUtil.isMacOSX()) { - MacOsAdapter.setMacOsProperties(); + System.setProperty("apple.awt.application.name", "JCS"); + System.setProperty("apple.laf.useScreenMenuBar", "true"); + System.setProperty("apple.awt.application.appearance", "system"); + Taskbar taskbar = Taskbar.getTaskbar(); try { BufferedImage img = ImageIO.read(DriverCabFrame.class.getResource(frameImageUrl)); diff --git a/src/main/java/jcs/ui/monitor/FeedbackMonitor.form b/src/main/java/jcs/ui/FeedbackSensorDialog.form similarity index 94% rename from src/main/java/jcs/ui/monitor/FeedbackMonitor.form rename to src/main/java/jcs/ui/FeedbackSensorDialog.form index 0a4b1a83..5e146310 100644 --- a/src/main/java/jcs/ui/monitor/FeedbackMonitor.form +++ b/src/main/java/jcs/ui/FeedbackSensorDialog.form @@ -1,9 +1,9 @@ -
+ - + @@ -23,56 +23,10 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -172,5 +126,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/jcs/ui/monitor/FeedbackMonitor.java b/src/main/java/jcs/ui/FeedbackSensorDialog.java similarity index 74% rename from src/main/java/jcs/ui/monitor/FeedbackMonitor.java rename to src/main/java/jcs/ui/FeedbackSensorDialog.java index 283fd315..52bc1e1f 100644 --- a/src/main/java/jcs/ui/monitor/FeedbackMonitor.java +++ b/src/main/java/jcs/ui/FeedbackSensorDialog.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Frans Jacobs. + * Copyright 2025 fransjacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,9 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package jcs.ui.monitor; +package jcs.ui; -import com.formdev.flatlaf.util.SystemInfo; import java.awt.Taskbar; import java.awt.image.BufferedImage; import java.io.IOException; @@ -28,46 +27,28 @@ import javax.swing.UnsupportedLookAndFeelException; import javax.swing.table.DefaultTableCellRenderer; import jcs.JCS; -import jcs.ui.DriverCabFrame; import jcs.ui.options.table.SensorTableModel; import jcs.ui.util.FrameMonitor; -import jcs.ui.util.MacOsAdapter; import jcs.util.RunUtil; import org.tinylog.Logger; /** * - * @author frans + * @author fransjacobs */ -public class FeedbackMonitor extends JFrame { +public class FeedbackSensorDialog extends javax.swing.JDialog { + + private static final long serialVersionUID = -1441572779636957892L; private final SensorTableModel sensorTableModel; /** - * Creates new form FeedbackMonitor + * Creates new form FeedbackSensorDialog */ - public FeedbackMonitor() { + public FeedbackSensorDialog(java.awt.Frame parent, boolean modal) { + super(parent, modal); sensorTableModel = new SensorTableModel(); - - if (RunUtil.isMacOSX()) { - System.setProperty("apple.awt.application.name", "JCS Sensor Monitor"); - System.setProperty("apple.laf.useScreenMenuBar", "true"); - System.setProperty("apple.awt.application.appearance", "system"); - } - -// if (SystemInfo.isMacFullWindowContentSupported) { -// this.getRootPane().putClientProperty("apple.awt.transparentTitleBar", true); -// this.getRootPane().putClientProperty("apple.awt.fullWindowContent", true); -// this.getRootPane().putClientProperty("apple.awt.transparentTitleBar", true); -// } initComponents(); - - URL iconUrl = JCS.class.getResource("/media/jcs-train-64.png"); - if (iconUrl != null) { - this.setIconImage(new ImageIcon(iconUrl).getImage()); - } - - alignSensorTable(); } private void alignSensorTable() { @@ -103,20 +84,21 @@ public void showMonitor() { } /** - * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. + * This method is called from within the constructor to initialize the form.
+ * WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { + topPanel = new javax.swing.JPanel(); + clearButton = new javax.swing.JButton(); mainPanel = new javax.swing.JPanel(); sensorTableSP = new javax.swing.JScrollPane(); sensorTable = new javax.swing.JTable(); - topPanel = new javax.swing.JPanel(); - clearButton = new javax.swing.JButton(); setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); - setTitle("JCS Sensor Monitor"); + setTitle("JCS Feedback Sensor Monitor"); addWindowListener(new java.awt.event.WindowAdapter() { public void windowActivated(java.awt.event.WindowEvent evt) { formWindowActivated(evt); @@ -126,24 +108,6 @@ public void windowClosed(java.awt.event.WindowEvent evt) { } }); - mainPanel.setPreferredSize(new java.awt.Dimension(750, 300)); - - sensorTableSP.setPreferredSize(new java.awt.Dimension(750, 345)); - - sensorTable.setModel(sensorTableModel); - sensorTable.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR)); - sensorTable.setDoubleBuffered(true); - sensorTable.setFillsViewportHeight(true); - sensorTable.setGridColor(new java.awt.Color(204, 204, 204)); - sensorTable.setName(""); // NOI18N - sensorTable.setRowHeight(18); - sensorTable.setShowGrid(true); - sensorTableSP.setViewportView(sensorTable); - - mainPanel.add(sensorTableSP); - - getContentPane().add(mainPanel, java.awt.BorderLayout.CENTER); - java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.RIGHT); flowLayout1.setAlignOnBaseline(true); topPanel.setLayout(flowLayout1); @@ -162,37 +126,59 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { getContentPane().add(topPanel, java.awt.BorderLayout.PAGE_START); + mainPanel.setPreferredSize(new java.awt.Dimension(750, 300)); + mainPanel.setLayout(new java.awt.BorderLayout()); + + sensorTableSP.setPreferredSize(new java.awt.Dimension(750, 345)); + + sensorTable.setModel(sensorTableModel); + sensorTable.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR)); + sensorTable.setDoubleBuffered(true); + sensorTable.setFillsViewportHeight(true); + sensorTable.setGridColor(new java.awt.Color(204, 204, 204)); + sensorTable.setName(""); // NOI18N + sensorTable.setRowHeight(18); + sensorTable.setShowGrid(true); + sensorTableSP.setViewportView(sensorTable); + + mainPanel.add(sensorTableSP, java.awt.BorderLayout.CENTER); + + getContentPane().add(mainPanel, java.awt.BorderLayout.CENTER); + pack(); }// //GEN-END:initComponents - private void clearButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_clearButtonActionPerformed - Logger.trace(evt.getActionCommand()); - sensorTableModel.clear(); - }//GEN-LAST:event_clearButtonActionPerformed + private void clearButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_clearButtonActionPerformed + Logger.trace(evt.getActionCommand()); + sensorTableModel.clear(); - private void formWindowClosed(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosed - if (JCS.getJcsCommandStation() != null) { - JCS.getJcsCommandStation().removeSensorEventListener(sensorTableModel); - Logger.trace(evt.getNewState() + " Removed sensor listener"); - } - this.sensorTableModel.clear(); - }//GEN-LAST:event_formWindowClosed + URL iconUrl = JCS.class.getResource("/media/jcs-train-64.png"); + if (iconUrl != null) { + this.setIconImage(new ImageIcon(iconUrl).getImage()); + } - private void formWindowActivated(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowActivated - if (JCS.getJcsCommandStation() != null) { - JCS.getJcsCommandStation().addSensorEventListener(sensorTableModel); - Logger.trace(evt.getNewState() + " Added sensor listener"); - } - }//GEN-LAST:event_formWindowActivated + alignSensorTable(); - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JButton clearButton; - private javax.swing.JPanel mainPanel; - private javax.swing.JTable sensorTable; - private javax.swing.JScrollPane sensorTableSP; - private javax.swing.JPanel topPanel; - // End of variables declaration//GEN-END:variables + }//GEN-LAST:event_clearButtonActionPerformed + + private void formWindowActivated(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowActivated + if (JCS.getJcsCommandStation() != null) { + JCS.getJcsCommandStation().addSensorEventListener(sensorTableModel); + Logger.trace(evt.getNewState() + " Added sensor listener"); + } + }//GEN-LAST:event_formWindowActivated + private void formWindowClosed(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosed + if (JCS.getJcsCommandStation() != null) { + JCS.getJcsCommandStation().removeSensorEventListener(sensorTableModel); + Logger.trace(evt.getNewState() + " Removed sensor listener"); + } + this.sensorTableModel.clear(); + }//GEN-LAST:event_formWindowClosed + + /** + * @param args the command line arguments + */ public static void main(String args[]) { try { String plaf = System.getProperty("jcs.plaf", "com.formdev.flatlaf.FlatLightLaf"); @@ -201,15 +187,21 @@ public static void main(String args[]) { Logger.error(ex); } - java.awt.EventQueue.invokeLater(() -> { - FeedbackMonitor monitorFrame = new FeedbackMonitor(); - FrameMonitor.registerFrame(monitorFrame, FeedbackMonitor.class.getName()); + if (RunUtil.isMacOSX()) { + System.setProperty("apple.awt.application.name", "JCS Feedback Sensor Monitor"); + System.setProperty("apple.laf.useScreenMenuBar", "true"); + System.setProperty("apple.awt.application.appearance", "system"); + } + /* Create and display the dialog */ + java.awt.EventQueue.invokeLater(() -> { + JFrame frame = new JFrame(); + FeedbackSensorDialog dialog = new FeedbackSensorDialog(frame, true); + FrameMonitor.registerFrame(dialog, FeedbackSensorDialog.class.getName()); //String frameImageUrl = "/media/jcs-train-64.png"; String frameImageUrl = "/media/jcs-train-2-512.png"; - + if (RunUtil.isMacOSX()) { - MacOsAdapter.setMacOsProperties(); Taskbar taskbar = Taskbar.getTaskbar(); try { BufferedImage img = ImageIO.read(DriverCabFrame.class.getResource(frameImageUrl)); @@ -218,19 +210,27 @@ public static void main(String args[]) { Logger.warn("Error: " + ex.getMessage()); } } - URL iconUrl = FeedbackMonitor.class.getResource(frameImageUrl); + URL iconUrl = FeedbackSensorDialog.class.getResource(frameImageUrl); if (iconUrl != null) { - monitorFrame.setIconImage(new ImageIcon(iconUrl).getImage()); + frame.setIconImage(new ImageIcon(iconUrl).getImage()); + dialog.setIconImage(new ImageIcon(iconUrl).getImage()); } - - monitorFrame.addWindowListener(new java.awt.event.WindowAdapter() { + + dialog.addWindowListener(new java.awt.event.WindowAdapter() { @Override public void windowClosing(java.awt.event.WindowEvent e) { System.exit(0); } }); - - monitorFrame.showMonitor(); + dialog.setVisible(true); }); } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton clearButton; + private javax.swing.JPanel mainPanel; + private javax.swing.JTable sensorTable; + private javax.swing.JScrollPane sensorTableSP; + private javax.swing.JPanel topPanel; + // End of variables declaration//GEN-END:variables } diff --git a/src/main/java/jcs/ui/JCSFrame.form b/src/main/java/jcs/ui/JCSFrame.form index 2d6f5808..fc4cef65 100755 --- a/src/main/java/jcs/ui/JCSFrame.form +++ b/src/main/java/jcs/ui/JCSFrame.form @@ -33,6 +33,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -41,73 +90,102 @@ + + - - - - - - - - - + + - + - - + + + - + - + - - + + + + - + - + - - + + - + - - + + + - + - + + + + + + + + + + + - + + + + + + + + + + + + - + + + + + + + + + + diff --git a/src/main/java/jcs/ui/JCSFrame.java b/src/main/java/jcs/ui/JCSFrame.java index 10ec7927..6f9fa29a 100755 --- a/src/main/java/jcs/ui/JCSFrame.java +++ b/src/main/java/jcs/ui/JCSFrame.java @@ -64,7 +64,6 @@ import jcs.commandStation.entities.InfoBean; import jcs.persistence.PersistenceFactory; import jcs.ui.layout.LayoutPanel; -import jcs.ui.monitor.FeedbackMonitor; import jcs.ui.options.CommandStationDialog; import jcs.ui.options.CommandStationPanel; import jcs.ui.options.OptionDialog; @@ -84,7 +83,7 @@ public class JCSFrame extends JFrame implements UICallback, DisconnectionEventLi private static final long serialVersionUID = -5800900684173242844L; private final Map actionMap; - private FeedbackMonitor feedbackMonitor; + private FeedbackSensorDialog feedbackMonitor; /** * Creates new form JCSFrame @@ -95,26 +94,30 @@ public JCSFrame() { //TODO: see https://www.formdev.com/flatlaf/macos/ if (RunUtil.isMacOSX()) { - quitMI.setVisible(false); - optionsMI.setVisible(false); - toolsMenu.setVisible(false); + //quitMI.setVisible(false); + //optionsMI.setVisible(false); + //settingsMenu.setVisible(false); if (SystemInfo.isMacFullWindowContentSupported) { - this.getRootPane().putClientProperty("apple.awt.transparentTitleBar", true); - this.getRootPane().putClientProperty("apple.awt.fullWindowContent", true); + getRootPane().putClientProperty("apple.awt.transparentTitleBar", true); + getRootPane().putClientProperty("apple.awt.fullWindowContent", true); //this.getRootPane().putClientProperty( "apple.awt.windowTitleVisible", false ); - this.getRootPane().putClientProperty("apple.awt.brushMetalLook", true); + getRootPane().putClientProperty("apple.awt.windowTitleVisible", false); + getRootPane().putClientProperty("apple.awt.brushMetalLook", true); + + //avoid overlap of the red/orange/green buttons and the window title + jcsToolBar.add(Box.createHorizontalStrut(70), 0); } initJCS(); - if (SystemInfo.isMacFullWindowContentSupported) { - //avoid overlap of the red/orange/green buttons and the window title - this.jcsToolBar.add(Box.createHorizontalStrut(70), 0); - //this.jcsToolBar.setb - } +// if (SystemInfo.isMacFullWindowContentSupported) { +// //avoid overlap of the red/orange/green buttons and the window title +// this.jcsToolBar.add(Box.createHorizontalStrut(70), 0); +// //this.jcsToolBar.setb +// } } initKeyStrokes(); } @@ -123,10 +126,9 @@ private void initJCS() { if (PersistenceFactory.getService() != null) { this.setTitle(this.getTitleString()); - if (RunUtil.isMacOSX()) { - this.setTitle(""); - } - +// if (RunUtil.isMacOSX()) { +// this.setTitle(""); +// } if (JCS.getJcsCommandStation().isConnected()) { setControllerProperties(); } @@ -134,8 +136,7 @@ private void initJCS() { //Show the default panel showOverviewPanel(); - JCS.addRefreshListener(dispatcherStatusPanel); - + //JCS.addRefreshListener(dispatcherStatusPanel); } } @@ -179,6 +180,16 @@ public void actionPerformed(ActionEvent e) { } } + private class EditAction extends AbstractAction { + + private static final long serialVersionUID = -4725560671766567186L; + + @Override + public void actionPerformed(ActionEvent e) { + showEditLayoutPanel(); + } + } + private class SelectModeKeyAction extends AbstractAction { private static final long serialVersionUID = -5543240676519086334L; @@ -242,8 +253,10 @@ public void actionPerformed(ActionEvent e) { private void initKeyStrokes() { KeyStroke keySpace = KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0); KeyStroke keyQuit = KeyStroke.getKeyStroke(KeyEvent.VK_Q, KeyEvent.CTRL_DOWN_MASK); - KeyStroke keySensorMonitor = KeyStroke.getKeyStroke(KeyEvent.VK_M, KeyEvent.CTRL_DOWN_MASK); + + KeyStroke keySensorMonitor = KeyStroke.getKeyStroke(KeyEvent.VK_M, KeyEvent.ALT_DOWN_MASK); KeyStroke keyHome = KeyStroke.getKeyStroke(KeyEvent.VK_H, KeyEvent.CTRL_DOWN_MASK); + KeyStroke keyEdit = KeyStroke.getKeyStroke(KeyEvent.VK_E, KeyEvent.CTRL_DOWN_MASK); //Edit screen KeyStroke keyModeSelect = KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.ALT_DOWN_MASK); @@ -257,6 +270,9 @@ private void initKeyStrokes() { actionMap.put(keySpace, new PowerAction()); actionMap.put(keyQuit, new QuitAction()); actionMap.put(keySensorMonitor, new ShowMonitorAction()); + actionMap.put(keyHome, new HomeAction()); + actionMap.put(keyEdit, new EditAction()); + actionMap.put(keyHome, new HomeAction()); actionMap.put(keyModeSelect, new SelectModeKeyAction()); @@ -332,7 +348,7 @@ public void showVNCConsole() { card.show(this.centerPanel, "vncPanel"); } - public void showDesignLayoutPanel() { + public void showEditLayoutPanel() { if (!AutoPilot.isAutoModeActive()) { CardLayout card = (CardLayout) this.centerPanel.getLayout(); card.show(this.centerPanel, "designPanel"); @@ -364,8 +380,8 @@ private void setControllerProperties() { private void showSensorMonitor() { if (feedbackMonitor == null) { Logger.trace("Creating a Monitor UI"); - feedbackMonitor = new FeedbackMonitor(); - FrameMonitor.registerFrame(feedbackMonitor, FeedbackMonitor.class.getName()); + feedbackMonitor = new FeedbackSensorDialog(this, false); + FrameMonitor.registerFrame(feedbackMonitor, FeedbackSensorDialog.class.getName()); } feedbackMonitor.showMonitor(); } @@ -430,15 +446,22 @@ private void initComponents() { fileMenu = new JMenu(); quitMI = new JMenuItem(); connectMI = new JMenuItem(); + editMenu = new JMenu(); + rotateTileMI = new JMenuItem(); + flipTileHorizontallyMI = new JMenuItem(); + flipTileVerticallyMI = new JMenuItem(); + deleteTileMI = new JMenuItem(); viewMenu = new JMenu(); showHome = new JMenuItem(); - showLocosMI = new JMenuItem(); editLayout = new JMenuItem(); - showKeyboard = new JMenuItem(); showSensorMonitor = new JMenuItem(); - toolsMenu = new JMenu(); + showKeyboard = new JMenuItem(); + settingsMenu = new JMenu(); + showLocosMI = new JMenuItem(); + showAccessoryMI = new JMenuItem(); + showCommandStationsMI = new JMenuItem(); + showPropertiesMI = new JMenuItem(); optionsMI = new JMenuItem(); - commandStationsMI = new JMenuItem(); helpMenu = new JMenu(); aboutMI = new JMenuItem(); @@ -882,10 +905,58 @@ public void actionPerformed(ActionEvent evt) { jcsMenuBar.add(fileMenu); + editMenu.setText("Edit"); + editMenu.setName("editMenu"); // NOI18N + + rotateTileMI.setMnemonic('R'); + rotateTileMI.setText("Rotate Tile"); + rotateTileMI.setToolTipText("Rotate the selected Tile"); + rotateTileMI.setName("rotateTileMI"); // NOI18N + rotateTileMI.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + rotateTileMIActionPerformed(evt); + } + }); + editMenu.add(rotateTileMI); + + flipTileHorizontallyMI.setText("Flip Horizontally"); + flipTileHorizontallyMI.setToolTipText("Flip selected Tile Horizontally"); + flipTileHorizontallyMI.setName("flipTileHorizontallyMI"); // NOI18N + flipTileHorizontallyMI.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + flipTileHorizontallyMIActionPerformed(evt); + } + }); + editMenu.add(flipTileHorizontallyMI); + + flipTileVerticallyMI.setText("Flip Tile Vertically"); + flipTileVerticallyMI.setToolTipText("Flip the selected Tile Vertically"); + flipTileVerticallyMI.setName("flipTileVerticallyMI"); // NOI18N + flipTileVerticallyMI.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + flipTileVerticallyMIActionPerformed(evt); + } + }); + editMenu.add(flipTileVerticallyMI); + + deleteTileMI.setText("Delete Tile"); + deleteTileMI.setToolTipText("Delete the selected Tile"); + deleteTileMI.setName("deleteTileMI"); // NOI18N + deleteTileMI.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + deleteTileMIActionPerformed(evt); + } + }); + editMenu.add(deleteTileMI); + + jcsMenuBar.add(editMenu); + viewMenu.setText("View"); viewMenu.setName("viewMenu"); // NOI18N + showHome.setMnemonic('H'); showHome.setText("Home"); + showHome.setToolTipText("Home screen"); showHome.setName("showHome"); // NOI18N showHome.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { @@ -894,16 +965,9 @@ public void actionPerformed(ActionEvent evt) { }); viewMenu.add(showHome); - showLocosMI.setLabel("Locomotives"); - showLocosMI.setName("showLocosMI"); // NOI18N - showLocosMI.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent evt) { - showLocosMIActionPerformed(evt); - } - }); - viewMenu.add(showLocosMI); - + editLayout.setMnemonic('E'); editLayout.setText("Edit Layout"); + editLayout.setToolTipText("Edit the track layout"); editLayout.setName("editLayout"); // NOI18N editLayout.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { @@ -912,7 +976,19 @@ public void actionPerformed(ActionEvent evt) { }); viewMenu.add(editLayout); + showSensorMonitor.setMnemonic('M'); + showSensorMonitor.setText("Sensor Monitor"); + showSensorMonitor.setName("showSensorMonitor"); // NOI18N + showSensorMonitor.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + showSensorMonitorActionPerformed(evt); + } + }); + viewMenu.add(showSensorMonitor); + + showKeyboard.setMnemonic('K'); showKeyboard.setText("Keyboard"); + showKeyboard.setToolTipText("Accessory keyboard"); showKeyboard.setName("showKeyboard"); // NOI18N showKeyboard.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { @@ -921,39 +997,61 @@ public void actionPerformed(ActionEvent evt) { }); viewMenu.add(showKeyboard); - showSensorMonitor.setText("Sensor Monitor"); - showSensorMonitor.setName("showSensorMonitor"); // NOI18N - showSensorMonitor.addActionListener(new ActionListener() { + jcsMenuBar.add(viewMenu); + + settingsMenu.setText("Settings"); + settingsMenu.setName("settingsMenu"); // NOI18N + + showLocosMI.setToolTipText("Locomotive settings"); + showLocosMI.setLabel("Locomotives"); + showLocosMI.setName("showLocosMI"); // NOI18N + showLocosMI.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { - showSensorMonitorActionPerformed(evt); + showLocosMIActionPerformed(evt); } }); - viewMenu.add(showSensorMonitor); + settingsMenu.add(showLocosMI); - jcsMenuBar.add(viewMenu); + showAccessoryMI.setText("Accessories"); + showAccessoryMI.setToolTipText("Accessory Settings"); + showAccessoryMI.setName("showAccessoryMI"); // NOI18N + showAccessoryMI.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + showAccessoryMIActionPerformed(evt); + } + }); + settingsMenu.add(showAccessoryMI); - toolsMenu.setText("Tools"); - toolsMenu.setName("toolsMenu"); // NOI18N + showCommandStationsMI.setText("Command Stations"); + showCommandStationsMI.setToolTipText("Commans Station Settings"); + showCommandStationsMI.setName("showCommandStationsMI"); // NOI18N + showCommandStationsMI.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + showCommandStationsMIActionPerformed(evt); + } + }); + settingsMenu.add(showCommandStationsMI); - optionsMI.setText("Options"); - optionsMI.setName("optionsMI"); // NOI18N - optionsMI.addActionListener(new ActionListener() { + showPropertiesMI.setText("Properties"); + showPropertiesMI.setToolTipText("Property Settings"); + showPropertiesMI.setName("showPropertiesMI"); // NOI18N + showPropertiesMI.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { - optionsMIActionPerformed(evt); + showPropertiesMIActionPerformed(evt); } }); - toolsMenu.add(optionsMI); + settingsMenu.add(showPropertiesMI); - commandStationsMI.setText("Command Stations"); - commandStationsMI.setName("commandStationsMI"); // NOI18N - commandStationsMI.addActionListener(new ActionListener() { + optionsMI.setText("Options"); + optionsMI.setName("optionsMI"); // NOI18N + optionsMI.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { - commandStationsMIActionPerformed(evt); + optionsMIActionPerformed(evt); } }); - toolsMenu.add(commandStationsMI); + settingsMenu.add(optionsMI); - jcsMenuBar.add(toolsMenu); + jcsMenuBar.add(settingsMenu); helpMenu.setText("Help"); helpMenu.setName("helpMenu"); // NOI18N @@ -996,7 +1094,7 @@ private void optionsMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_option }//GEN-LAST:event_optionsMIActionPerformed private void showEditDesignBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_showEditDesignBtnActionPerformed - showDesignLayoutPanel(); + showEditLayoutPanel(); }//GEN-LAST:event_showEditDesignBtnActionPerformed private void showOverviewBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_showOverviewBtnActionPerformed @@ -1088,7 +1186,7 @@ private void showHomeActionPerformed(ActionEvent evt) {//GEN-FIRST:event_showHom }//GEN-LAST:event_showHomeActionPerformed private void editLayoutActionPerformed(ActionEvent evt) {//GEN-FIRST:event_editLayoutActionPerformed - showDesignLayoutPanel(); + showEditLayoutPanel(); }//GEN-LAST:event_editLayoutActionPerformed private void showKeyboardActionPerformed(ActionEvent evt) {//GEN-FIRST:event_showKeyboardActionPerformed @@ -1105,11 +1203,11 @@ private void connectMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_connec connectButton.setSelected(connect); }//GEN-LAST:event_connectMIActionPerformed - private void commandStationsMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_commandStationsMIActionPerformed + private void showCommandStationsMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_showCommandStationsMIActionPerformed CommandStationDialog csd = new CommandStationDialog(this, true); csd.setLocationRelativeTo(null); csd.setVisible(true); - }//GEN-LAST:event_commandStationsMIActionPerformed + }//GEN-LAST:event_showCommandStationsMIActionPerformed private void aboutMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_aboutMIActionPerformed Logger.trace(evt.getActionCommand()); @@ -1157,6 +1255,31 @@ private void startAllLocsBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_ } }//GEN-LAST:event_startAllLocsBtnActionPerformed + private void showAccessoryMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_showAccessoryMIActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_showAccessoryMIActionPerformed + + private void showPropertiesMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_showPropertiesMIActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_showPropertiesMIActionPerformed + + private void rotateTileMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_rotateTileMIActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_rotateTileMIActionPerformed + + private void flipTileHorizontallyMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_flipTileHorizontallyMIActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_flipTileHorizontallyMIActionPerformed + + private void flipTileVerticallyMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_flipTileVerticallyMIActionPerformed + + // TODO add your handling code here: + }//GEN-LAST:event_flipTileVerticallyMIActionPerformed + + private void deleteTileMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_deleteTileMIActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_deleteTileMIActionPerformed + private String getTitleString() { String jcsVersion = VersionInfo.getVersion(); @@ -1222,7 +1345,6 @@ public void powerChanged(PowerEvent event) { private JPanel bottomLeftPanel; private JPanel centerPanel; private CommandStationPanel commandStationPanel; - private JMenuItem commandStationsMI; private JToggleButton connectButton; private JMenuItem connectMI; private JLabel controllerCatalogLbl; @@ -1233,8 +1355,10 @@ public void powerChanged(PowerEvent event) { private JLabel controllerLbl; private JLabel controllerSerialLbl; private JLabel controllerSerialNumberLbl; + private JMenuItem deleteTileMI; private DispatcherStatusPanel dispatcherStatusPanel; private JMenuItem editLayout; + private JMenu editMenu; private JMenu fileMenu; private Box.Filler filler1; private Box.Filler filler10; @@ -1246,6 +1370,8 @@ public void powerChanged(PowerEvent event) { private Box.Filler filler7; private Box.Filler filler8; private Box.Filler filler9; + private JMenuItem flipTileHorizontallyMI; + private JMenuItem flipTileVerticallyMI; private JMenu helpMenu; private JPanel jPanel1; private JPanel jPanel2; @@ -1263,7 +1389,11 @@ public void powerChanged(PowerEvent event) { private JToggleButton powerButton; private JMenuItem quitMI; private JButton resetAutoPilotBtn; + private JMenuItem rotateTileMI; + private JMenu settingsMenu; private JPanel settingsPanel; + private JMenuItem showAccessoryMI; + private JMenuItem showCommandStationsMI; private JButton showEditDesignBtn; private JButton showFeedbackMonitorBtn; private JMenuItem showHome; @@ -1271,12 +1401,12 @@ public void powerChanged(PowerEvent event) { private JButton showKeyboardBtn; private JMenuItem showLocosMI; private JButton showOverviewBtn; + private JMenuItem showPropertiesMI; private JMenuItem showSensorMonitor; private JButton showVNCBtn; private JButton startAllLocsBtn; private StatusPanel statusPanel; private JPanel toolbarPanel; - private JMenu toolsMenu; private JMenu viewMenu; private JCheckBox virtualCB; private VNCPanel vncPanel; diff --git a/src/main/java/jcs/ui/util/FrameMonitor.java b/src/main/java/jcs/ui/util/FrameMonitor.java index cfe31396..50276e50 100644 --- a/src/main/java/jcs/ui/util/FrameMonitor.java +++ b/src/main/java/jcs/ui/util/FrameMonitor.java @@ -20,6 +20,7 @@ import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.util.prefs.Preferences; +import javax.swing.JDialog; import javax.swing.JFrame; import org.tinylog.Logger; @@ -55,8 +56,8 @@ public static void registerFrame(JFrame frame, String frameUniqueId, int default Preferences prefs = Preferences.userRoot().node(FrameMonitor.class.getSimpleName() + "-" + frameUniqueId); - frame.setLocation(getFrameLocation(prefs, defaultX, defaultY)); - frame.setSize(getFrameSize(prefs, defaultW, defaultH)); + frame.setLocation(getLocation(prefs, defaultX, defaultY)); + frame.setSize(getSize(prefs, defaultW, defaultH)); PreferencesEventUpdater updater = new PreferencesEventUpdater(400, () -> updatePref(frame, prefs)); @@ -73,6 +74,50 @@ public void componentMoved(ComponentEvent e) { }); } + /** + * Align the dialog default in the middle of the screen using then "packed" sizes + * + * @param dialog the Dialog to show + * @param dialogUniqueId the id of the the dialog + */ + public static void registerFrame(JDialog dialog, String dialogUniqueId) { + dialog.pack(); + dialog.setLocationRelativeTo(null); + Point location = dialog.getLocation(); + int defaultX = location.x; + int defaultY = location.y; + Dimension size = dialog.getSize(); + int defaultW = size.width; + int defaultH = size.height; + + registerDialog(dialog, dialogUniqueId, defaultX, defaultY, defaultW, defaultH); + } + + public static void registerDialog(JDialog dialog, String dialogUniqueId, int defaultX, int defaultY, int defaultW, int defaultH) { + if (System.getProperty("disable.ui.pref.storage", "false").equalsIgnoreCase("true")) { + return; + } + + Preferences prefs = Preferences.userRoot().node(FrameMonitor.class.getSimpleName() + "-" + dialogUniqueId); + + dialog.setLocation(getLocation(prefs, defaultX, defaultY)); + dialog.setSize(getSize(prefs, defaultW, defaultH)); + + PreferencesEventUpdater updater = new PreferencesEventUpdater(400, () -> updatePref(dialog, prefs)); + + dialog.addComponentListener(new ComponentAdapter() { + @Override + public void componentResized(ComponentEvent e) { + updater.update(); + } + + @Override + public void componentMoved(ComponentEvent e) { + updater.update(); + } + }); + } + private static void updatePref(JFrame frame, Preferences prefs) { if (System.getProperty("disable.ui.pref.storage", "false").equalsIgnoreCase("true")) { return; @@ -87,13 +132,27 @@ private static void updatePref(JFrame frame, Preferences prefs) { Logger.trace("Updated prefs for " + frame.getClass().getSimpleName() + " Pos: (" + location.x + "," + location.y + ") Size W: " + size.width + " H: " + size.height); } - private static Dimension getFrameSize(Preferences pref, int defaultW, int defaultH) { + private static void updatePref(JDialog dialog, Preferences prefs) { + if (System.getProperty("disable.ui.pref.storage", "false").equalsIgnoreCase("true")) { + return; + } + + Point location = dialog.getLocation(); + prefs.putInt("x", location.x); + prefs.putInt("y", location.y); + Dimension size = dialog.getSize(); + prefs.putInt("w", size.width); + prefs.putInt("h", size.height); + Logger.trace("Updated prefs for " + dialog.getClass().getSimpleName() + " Pos: (" + location.x + "," + location.y + ") Size W: " + size.width + " H: " + size.height); + } + + private static Dimension getSize(Preferences pref, int defaultW, int defaultH) { int w = pref.getInt("w", defaultW); int h = pref.getInt("h", defaultH); return new Dimension(w, h); } - private static Point getFrameLocation(Preferences pref, int defaultX, int defaultY) { + private static Point getLocation(Preferences pref, int defaultX, int defaultY) { int x = pref.getInt("x", defaultX); int y = pref.getInt("y", defaultY); return new Point(x, y); diff --git a/src/main/java/jcs/ui/util/MacOsAdapter.java b/src/main/java/jcs/ui/util/MacOsAdapter.java deleted file mode 100755 index b7021e0e..00000000 --- a/src/main/java/jcs/ui/util/MacOsAdapter.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright (C) 2019 frans. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA - */ -package jcs.ui.util; - -import java.awt.Desktop; -import java.awt.Taskbar; -import java.awt.desktop.AboutEvent; -import java.awt.desktop.AboutHandler; -import java.awt.desktop.OpenFilesEvent; -import java.awt.desktop.OpenFilesHandler; -import java.awt.desktop.PreferencesEvent; -import java.awt.desktop.PreferencesHandler; -import java.awt.desktop.QuitEvent; -import java.awt.desktop.QuitHandler; -import java.awt.desktop.QuitResponse; -import java.awt.image.BufferedImage; -import java.io.IOException; -import javax.imageio.ImageIO; -import javax.swing.UIManager; -import javax.swing.UnsupportedLookAndFeelException; -import jcs.JCS; -import org.tinylog.Logger; - -/** - * - * @author frans - */ -public class MacOsAdapter { - - private UICallback uiCallback; - //private JTouchBar touchBar; - - public MacOsAdapter() { - init(); - } - - public static void setMacOsProperties() { - System.setProperty("apple.awt.application.name", "JCS"); - System.setProperty("apple.laf.useScreenMenuBar", "true"); - System.setProperty("apple.awt.application.appearance", "system"); - } - - public void setUiCallback(UICallback uiCallback) { - this.uiCallback = uiCallback; - } - - private void init() { - try { - UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { - Logger.warn("Can't set the LookAndFeel: " + ex); - } - try { - Desktop desktop = Desktop.getDesktop(); - desktop.setAboutHandler(new JCSAboutHandler()); - desktop.setQuitHandler(new JCSQuitHandler()); - desktop.setPreferencesHandler(new JCSPreferencesHandler()); - - Taskbar taskbar = Taskbar.getTaskbar(); - try { - //BufferedImage img = ImageIO.read(JCS.class.getResource("/media/jcs-train-64.png")); - BufferedImage img = ImageIO.read(JCS.class.getResource("/media/jcs-train-2-512.png")); - taskbar.setIconImage(img); - } catch (final UnsupportedOperationException e) { - Logger.warn("The os does not support: 'taskbar.setIconImage'"); - } catch (final SecurityException e) { - Logger.warn("There was a security exception for: 'taskbar.setIconImage'"); - } - - //initTouchBar(); - } catch (SecurityException | IllegalArgumentException | IOException ex) { - Logger.warn("Failed to register with MacOS: " + ex); - } - } - -// private void initTouchBar() { -//// try { -// touchBar = new JTouchBar(); -// touchBar.setCustomizationIdentifier("JCSTouchBar"); -// -// //Load the images -// //Image powerImage = new Image(new DataInputStream(MacOsAdapter.class.getResourceAsStream("/media/power-red-24.png"))); -// //Image displayLayoutImage = new Image(new DataInputStream(MacOsAdapter.class.getResourceAsStream("/media/earth-yellow-24.png"))); -// //Image locomotiveImage = new Image(new DataInputStream(MacOsAdapter.class.getResourceAsStream("/media/electric-loc-yellow-24.png"))); -// //Image turnoutImage = new Image(new DataInputStream(MacOsAdapter.class.getResourceAsStream("/media/turnout-yellow-24.png"))); -// //Image signalImage = new Image(new DataInputStream(MacOsAdapter.class.getResourceAsStream("/media/signal-yellow-24.png"))); -// //Image diagnosticsImage = new Image(new DataInputStream(MacOsAdapter.class.getResourceAsStream("/media/stethoscope-yellow-24.png"))); -// //Image designImage = new Image(new DataInputStream(MacOsAdapter.class.getResourceAsStream("/media/layout-yellow-24.png"))); -// //Show label -// TouchBarTextField touchBarTextField = new TouchBarTextField(); -// touchBarTextField.setStringValue("JCS"); -// touchBar.addItem(new TouchBarItem("touchBarTextField", touchBarTextField, true)); -// -// //jTouchBar.addItem(new TouchBarItem(TouchBarItem.NSTouchBarItemIdentifierFlexibleSpace)); -// //jTouchBar.addItem(new TouchBarItem(TouchBarItem.NSTouchBarItemIdentifierFixedSpaceSmall)); -// //Buttons -// //TouchBarButton stopButton = new TouchBarButton(); -// //stopButton.setImage(powerImage); -// //stopButton.setAction((TouchBarView view) -> { -// // Logger.trace("Touchbar Stop button clicked..."); -// // JCS.getJCSFrame().stop(); -// //}); -// //touchBar.addItem(new TouchBarItem("stopButton", stopButton, true)); -// //TouchBarButton overviewButton = new TouchBarButton(); -// //overviewButton.setImage(displayLayoutImage); -// //overviewButton.setAction((TouchBarView view) -> { -// //Logger.trace("Touchbar Overview button clicked..."); -// //JCSGUI.getJCSFrame().showDisplayLayoutPanel(); -// //}); -// //touchBar.addItem(new TouchBarItem("overviewButton", overviewButton, true)); -// //TouchBarButton locoButton = new TouchBarButton(); -// //locoButton.setImage(locomotiveImage); -// //locoButton.setAction((TouchBarView view) -> { -// // Logger.trace("Touchbar Loco button clicked..."); -// // JCS.getJCSFrame().showLocomotives(); -// //}); -// //touchBar.addItem(new TouchBarItem("locoButton", locoButton, true)); -// //TouchBarButton turnoutsButton = new TouchBarButton(); -// //turnoutsButton.setImage(turnoutImage); -// //turnoutsButton.setAction((TouchBarView view) -> { -// // Logger.trace("Touchbar Turnouts button clicked..."); -// // JCS.getJCSFrame().showTurnouts(); -// //}); -// //touchBar.addItem(new TouchBarItem("turnoutsButton", turnoutsButton, true)); -// //TouchBarButton signalsButton = new TouchBarButton(); -// //signalsButton.setImage(signalImage); -// //signalsButton.setAction((TouchBarView view) -> { -// // Logger.trace("Touchbar Signals button clicked..."); -// // JCS.getJCSFrame().showSignals(); -// //}); -// //touchBar.addItem(new TouchBarItem("signalsButton", signalsButton, true)); -// //TouchBarButton diagnosticsButton = new TouchBarButton(); -// //diagnosticsButton.setTitle("Diagnostics"); -// //diagnosticsButton.setImage(diagnosticsImage); -// //diagnosticsButton.setAction((TouchBarView view) -> { -// // Logger.trace("Touchbar diagnostics button clicked..."); -// // JCS.getJCSFrame().showDiagnostics(); -// //}); -// //touchBar.addItem(new TouchBarItem("diagnosticsButton", diagnosticsButton, true)); -//// TouchBarButton designButton = new TouchBarButton(); -//// //diagnosticsButton.setTitle("Design"); -//// designButton.setImage(designImage); -//// designButton.setAction((TouchBarView view) -> { -//// Logger.trace("Touchbar design button clicked..."); -//// JCS.getJCSFrame().showDesignLayoutPanel(); -//// }); -//// touchBar.addItem(new TouchBarItem("designButton", designButton, true)); -//// } catch (IOException e) { -//// Logger.error(e); -//// } -// } - -// public void showTouchbar(Component c) { -// this.touchBar.show(c); -// } - - private class JCSQuitHandler implements QuitHandler { - - @Override - public void handleQuitRequestWith(QuitEvent e, QuitResponse response) { - uiCallback.handleQuitRequest(); - } - } - - private class JCSAboutHandler implements AboutHandler { - - @Override - public void handleAbout(AboutEvent e) { - uiCallback.handleAbout(); - } - } - - private class JCSPreferencesHandler implements PreferencesHandler { - - @Override - public void handlePreferences(PreferencesEvent e) { - uiCallback.handlePreferences(); - } - } - - private class JCSOpenFilesHandler implements OpenFilesHandler { - - @Override - public void openFiles(OpenFilesEvent e) { - //STUB - uiCallback.openFiles(null); - } - } - -} From c8451b1f1705ed9b0df0879a461a2e5f804cfecc Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Sat, 15 Mar 2025 14:44:08 +0100 Subject: [PATCH 36/70] Fix compile issue --- src/main/java/jcs/ui/options/LocomotivePreferencesPanel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/jcs/ui/options/LocomotivePreferencesPanel.java b/src/main/java/jcs/ui/options/LocomotivePreferencesPanel.java index 4d55800d..6dc449f7 100755 --- a/src/main/java/jcs/ui/options/LocomotivePreferencesPanel.java +++ b/src/main/java/jcs/ui/options/LocomotivePreferencesPanel.java @@ -729,7 +729,7 @@ private void saveBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_saveBtnA initModels(); locomotiveList.setSelectedValue(selectedLocomotive, true); - JCS.settingsChanged(new RefreshEvent("locomotives")); + //JCS.settingsChanged(new RefreshEvent("locomotives")); } }//GEN-LAST:event_saveBtnActionPerformed @@ -1152,7 +1152,7 @@ public Void doInBackground() { setProgress((int) progress); } - JCS.settingsChanged(new RefreshEvent("locomotives")); + //JCS.settingsChanged(new RefreshEvent("locomotives")); firePropertyChange("done", "", "Locomotives Synchronized"); From 5cc5b9568bf39e50d3a40702c8f5a3366ae6c13c Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Thu, 20 Mar 2025 21:14:39 +0100 Subject: [PATCH 37/70] Changing Menu plus adding Menu Items. Keyboar now usable in edit mode --- src/main/java/jcs/ui/JCSFrame.form | 131 ++--- src/main/java/jcs/ui/JCSFrame.java | 530 ++++++++++-------- src/main/java/jcs/ui/StatusPanel.form | 129 +++++ src/main/java/jcs/ui/StatusPanel.java | 27 + src/main/java/jcs/ui/layout/LayoutCanvas.java | 9 +- src/main/java/jcs/ui/layout/LayoutPanel.form | 66 +-- src/main/java/jcs/ui/layout/LayoutPanel.java | 93 ++- 7 files changed, 605 insertions(+), 380 deletions(-) diff --git a/src/main/java/jcs/ui/JCSFrame.form b/src/main/java/jcs/ui/JCSFrame.form index fc4cef65..c6cb31d3 100755 --- a/src/main/java/jcs/ui/JCSFrame.form +++ b/src/main/java/jcs/ui/JCSFrame.form @@ -31,6 +31,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -82,10 +121,10 @@ - + - - + + @@ -110,14 +149,15 @@ - + - - - + + + + - + @@ -131,6 +171,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -332,27 +392,6 @@ - - - - - - - - - - - - - - - - - - - - - @@ -749,40 +788,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/main/java/jcs/ui/JCSFrame.java b/src/main/java/jcs/ui/JCSFrame.java index 6f9fa29a..5c1ed4ca 100755 --- a/src/main/java/jcs/ui/JCSFrame.java +++ b/src/main/java/jcs/ui/JCSFrame.java @@ -40,7 +40,7 @@ import javax.swing.BoxLayout; import javax.swing.ImageIcon; import javax.swing.JButton; -import javax.swing.JCheckBox; +import javax.swing.JCheckBoxMenuItem; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JMenu; @@ -63,6 +63,7 @@ import jcs.commandStation.events.PowerEvent; import jcs.commandStation.entities.InfoBean; import jcs.persistence.PersistenceFactory; +import jcs.ui.layout.LayoutCanvas; import jcs.ui.layout.LayoutPanel; import jcs.ui.options.CommandStationDialog; import jcs.ui.options.CommandStationPanel; @@ -85,6 +86,8 @@ public class JCSFrame extends JFrame implements UICallback, DisconnectionEventLi private final Map actionMap; private FeedbackSensorDialog feedbackMonitor; + private boolean editMode = false; + /** * Creates new form JCSFrame */ @@ -112,144 +115,24 @@ public JCSFrame() { } initJCS(); - -// if (SystemInfo.isMacFullWindowContentSupported) { -// //avoid overlap of the red/orange/green buttons and the window title -// this.jcsToolBar.add(Box.createHorizontalStrut(70), 0); -// //this.jcsToolBar.setb -// } } initKeyStrokes(); } private void initJCS() { if (PersistenceFactory.getService() != null) { - this.setTitle(this.getTitleString()); + setTitle(this.getTitleString()); -// if (RunUtil.isMacOSX()) { -// this.setTitle(""); -// } if (JCS.getJcsCommandStation().isConnected()) { setControllerProperties(); } - //Show the default panel showOverviewPanel(); - + editMode = false; //JCS.addRefreshListener(dispatcherStatusPanel); } } - private class PowerAction extends AbstractAction { - - private static final long serialVersionUID = 4263882874269440066L; - - @Override - public void actionPerformed(ActionEvent e) { - powerButton.doClick(50); - } - } - - private class QuitAction extends AbstractAction { - - private static final long serialVersionUID = 106411709893099942L; - - @Override - public void actionPerformed(ActionEvent e) { - QuitApp(); - } - } - - private class ShowMonitorAction extends AbstractAction { - - private static final long serialVersionUID = -3352181383049583600L; - - @Override - public void actionPerformed(ActionEvent e) { - showSensorMonitor(); - } - } - - private class HomeAction extends AbstractAction { - - private static final long serialVersionUID = 6369350924548859534L; - - @Override - public void actionPerformed(ActionEvent e) { - showOverviewPanel(); - } - } - - private class EditAction extends AbstractAction { - - private static final long serialVersionUID = -4725560671766567186L; - - @Override - public void actionPerformed(ActionEvent e) { - showEditLayoutPanel(); - } - } - - private class SelectModeKeyAction extends AbstractAction { - - private static final long serialVersionUID = -5543240676519086334L; - - @Override - public void actionPerformed(ActionEvent e) { - Logger.info("Select"); - } - } - - private class AddModeKeyAction extends AbstractAction { - - private static final long serialVersionUID = -429465825958791906L; - - @Override - public void actionPerformed(ActionEvent e) { - Logger.info("Add"); - } - } - - private class DeleteModeKeyAction extends AbstractAction { - - private static final long serialVersionUID = 569113006687591145L; - - @Override - public void actionPerformed(ActionEvent e) { - Logger.info("Delete"); - } - } - - private class RotateKeyAction extends AbstractAction { - - private static final long serialVersionUID = -292237743142583719L; - - @Override - public void actionPerformed(ActionEvent e) { - Logger.info("Rotate"); - } - } - - private class FlipHorizontalKeyAction extends AbstractAction { - - private static final long serialVersionUID = 7657976620206362097L; - - @Override - public void actionPerformed(ActionEvent e) { - Logger.info("Flip Horizontal"); - } - } - - private class FlipVerticalKeyAction extends AbstractAction { - - private static final long serialVersionUID = -4269202419142803636L; - - @Override - public void actionPerformed(ActionEvent e) { - Logger.info("Flip Vertical"); - } - } - private void initKeyStrokes() { KeyStroke keySpace = KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0); KeyStroke keyQuit = KeyStroke.getKeyStroke(KeyEvent.VK_Q, KeyEvent.CTRL_DOWN_MASK); @@ -315,6 +198,7 @@ public void hideExtraToolbar(JToolBar toolbar) { public void showOverviewPanel() { CardLayout card = (CardLayout) centerPanel.getLayout(); card.show(centerPanel, "overviewPanel"); + editMode = false; overviewPanel.loadLayout(); } @@ -325,34 +209,40 @@ public void showLocomotives() { public void showTurnouts() { CardLayout card = (CardLayout) this.centerPanel.getLayout(); - card.show(this.centerPanel, "turnoutsPanel"); + card.show(centerPanel, "turnoutsPanel"); + editMode = false; } public void showSignals() { CardLayout card = (CardLayout) this.centerPanel.getLayout(); - card.show(this.centerPanel, "signalsPanel"); + card.show(centerPanel, "signalsPanel"); + editMode = false; } public void showKeyboards() { CardLayout card = (CardLayout) this.centerPanel.getLayout(); - card.show(this.centerPanel, "diagnosticPanel"); + card.show(centerPanel, "diagnosticPanel"); + editMode = false; } public void showSettings() { CardLayout card = (CardLayout) this.centerPanel.getLayout(); - card.show(this.centerPanel, "settingsPanel"); + card.show(centerPanel, "settingsPanel"); + editMode = false; } public void showVNCConsole() { CardLayout card = (CardLayout) this.centerPanel.getLayout(); - card.show(this.centerPanel, "vncPanel"); + card.show(centerPanel, "vncPanel"); + editMode = false; } public void showEditLayoutPanel() { if (!AutoPilot.isAutoModeActive()) { - CardLayout card = (CardLayout) this.centerPanel.getLayout(); - card.show(this.centerPanel, "designPanel"); + CardLayout card = (CardLayout) centerPanel.getLayout(); + card.show(centerPanel, "designPanel"); layoutPanel.loadLayout(); + editMode = true; } } @@ -373,7 +263,7 @@ private void setControllerProperties() { this.powerButton.setSelected(connected); } boolean virt = JCS.getJcsCommandStation().isVirtual(); - virtualCB.setSelected(virt); + virtualCBMI.setSelected(virt); } } @@ -398,7 +288,6 @@ private void initComponents() { jcsToolBar = new JToolBar(); connectButton = new JToggleButton(); filler1 = new Box.Filler(new Dimension(5, 0), new Dimension(5, 0), new Dimension(5, 32767)); - virtualCB = new JCheckBox(); filler2 = new Box.Filler(new Dimension(5, 0), new Dimension(5, 0), new Dimension(5, 32767)); powerButton = new JToggleButton(); filler3 = new Box.Filler(new Dimension(20, 0), new Dimension(20, 0), new Dimension(20, 32767)); @@ -413,7 +302,6 @@ private void initComponents() { autoPilotBtn = new JToggleButton(); startAllLocsBtn = new JButton(); filler9 = new Box.Filler(new Dimension(20, 0), new Dimension(20, 0), new Dimension(20, 32767)); - resetAutoPilotBtn = new JButton(); filler10 = new Box.Filler(new Dimension(20, 0), new Dimension(20, 0), new Dimension(20, 32767)); statusPanel = new StatusPanel(); mainPanel = new JPanel(); @@ -446,16 +334,22 @@ private void initComponents() { fileMenu = new JMenu(); quitMI = new JMenuItem(); connectMI = new JMenuItem(); + virtualCBMI = new JCheckBoxMenuItem(); + autoPilotMI = new JMenuItem(); + startAllLocsMI = new JMenuItem(); + resetAutopilotMI = new JMenuItem(); editMenu = new JMenu(); rotateTileMI = new JMenuItem(); flipTileHorizontallyMI = new JMenuItem(); flipTileVerticallyMI = new JMenuItem(); deleteTileMI = new JMenuItem(); - viewMenu = new JMenu(); + windowMenu = new JMenu(); showHome = new JMenuItem(); editLayout = new JMenuItem(); - showSensorMonitor = new JMenuItem(); + vncMI = new JMenuItem(); showKeyboard = new JMenuItem(); + showSensorMonitor = new JMenuItem(); + showRoutesMI = new JMenuItem(); settingsMenu = new JMenu(); showLocosMI = new JMenuItem(); showAccessoryMI = new JMenuItem(); @@ -512,21 +406,6 @@ public void actionPerformed(ActionEvent evt) { filler1.setName("filler1"); // NOI18N jcsToolBar.add(filler1); - virtualCB.setText("Virtual"); - virtualCB.setToolTipText("Enable Virtual Mode"); - virtualCB.setFocusable(false); - virtualCB.setHorizontalTextPosition(SwingConstants.LEFT); - virtualCB.setMaximumSize(new Dimension(65, 30)); - virtualCB.setMinimumSize(new Dimension(65, 30)); - virtualCB.setName("virtualCB"); // NOI18N - virtualCB.setPreferredSize(new Dimension(65, 30)); - virtualCB.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent evt) { - virtualCBActionPerformed(evt); - } - }); - jcsToolBar.add(virtualCB); - filler2.setName("filler2"); // NOI18N jcsToolBar.add(filler2); @@ -699,24 +578,6 @@ public void actionPerformed(ActionEvent evt) { filler9.setName("filler9"); // NOI18N jcsToolBar.add(filler9); - resetAutoPilotBtn.setIcon(new ImageIcon(getClass().getResource("/media/reset-happy.png"))); // NOI18N - resetAutoPilotBtn.setToolTipText("Stop and Reset AutoPilot"); - resetAutoPilotBtn.setBorder(BorderFactory.createLineBorder(new Color(204, 204, 204))); - resetAutoPilotBtn.setFocusable(false); - resetAutoPilotBtn.setHorizontalTextPosition(SwingConstants.CENTER); - resetAutoPilotBtn.setMargin(new Insets(0, 0, 0, 0)); - resetAutoPilotBtn.setMaximumSize(new Dimension(40, 40)); - resetAutoPilotBtn.setMinimumSize(new Dimension(40, 40)); - resetAutoPilotBtn.setName("resetAutoPilotBtn"); // NOI18N - resetAutoPilotBtn.setPreferredSize(new Dimension(40, 40)); - resetAutoPilotBtn.setVerticalTextPosition(SwingConstants.BOTTOM); - resetAutoPilotBtn.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent evt) { - resetAutoPilotBtnActionPerformed(evt); - } - }); - jcsToolBar.add(resetAutoPilotBtn); - filler10.setName("filler10"); // NOI18N jcsToolBar.add(filler10); @@ -903,6 +764,45 @@ public void actionPerformed(ActionEvent evt) { }); fileMenu.add(connectMI); + virtualCBMI.setText("Virtual Connection"); + virtualCBMI.setName("virtualCBMI"); // NOI18N + virtualCBMI.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + virtualCBMIActionPerformed(evt); + } + }); + fileMenu.add(virtualCBMI); + + autoPilotMI.setText("Autopilot"); + autoPilotMI.setToolTipText("Switch Autopilot on"); + autoPilotMI.setName("autoPilotMI"); // NOI18N + autoPilotMI.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + autoPilotMIActionPerformed(evt); + } + }); + fileMenu.add(autoPilotMI); + + startAllLocsMI.setText("Start All Locomotives"); + startAllLocsMI.setToolTipText("Start All Locomotives"); + startAllLocsMI.setName("startAllLocsMI"); // NOI18N + startAllLocsMI.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + startAllLocsMIActionPerformed(evt); + } + }); + fileMenu.add(startAllLocsMI); + + resetAutopilotMI.setText("Reset Autopilot"); + resetAutopilotMI.setToolTipText("Reset Autopilot"); + resetAutopilotMI.setName("resetAutopilotMI"); // NOI18N + resetAutopilotMI.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + resetAutopilotMIActionPerformed(evt); + } + }); + fileMenu.add(resetAutopilotMI); + jcsMenuBar.add(fileMenu); editMenu.setText("Edit"); @@ -951,8 +851,8 @@ public void actionPerformed(ActionEvent evt) { jcsMenuBar.add(editMenu); - viewMenu.setText("View"); - viewMenu.setName("viewMenu"); // NOI18N + windowMenu.setText("Window"); + windowMenu.setName("windowMenu"); // NOI18N showHome.setMnemonic('H'); showHome.setText("Home"); @@ -963,7 +863,7 @@ public void actionPerformed(ActionEvent evt) { showHomeActionPerformed(evt); } }); - viewMenu.add(showHome); + windowMenu.add(showHome); editLayout.setMnemonic('E'); editLayout.setText("Edit Layout"); @@ -974,17 +874,18 @@ public void actionPerformed(ActionEvent evt) { editLayoutActionPerformed(evt); } }); - viewMenu.add(editLayout); + windowMenu.add(editLayout); - showSensorMonitor.setMnemonic('M'); - showSensorMonitor.setText("Sensor Monitor"); - showSensorMonitor.setName("showSensorMonitor"); // NOI18N - showSensorMonitor.addActionListener(new ActionListener() { + vncMI.setMnemonic('V'); + vncMI.setText("VNC"); + vncMI.setToolTipText("Show VNC screen"); + vncMI.setName("vncMI"); // NOI18N + vncMI.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { - showSensorMonitorActionPerformed(evt); + vncMIActionPerformed(evt); } }); - viewMenu.add(showSensorMonitor); + windowMenu.add(vncMI); showKeyboard.setMnemonic('K'); showKeyboard.setText("Keyboard"); @@ -995,9 +896,29 @@ public void actionPerformed(ActionEvent evt) { showKeyboardActionPerformed(evt); } }); - viewMenu.add(showKeyboard); + windowMenu.add(showKeyboard); + + showSensorMonitor.setMnemonic('M'); + showSensorMonitor.setText("Sensor Monitor"); + showSensorMonitor.setName("showSensorMonitor"); // NOI18N + showSensorMonitor.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + showSensorMonitorActionPerformed(evt); + } + }); + windowMenu.add(showSensorMonitor); + + showRoutesMI.setText("Show Routes"); + showRoutesMI.setToolTipText("Show Routes"); + showRoutesMI.setName("showRoutesMI"); // NOI18N + showRoutesMI.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + showRoutesMIActionPerformed(evt); + } + }); + windowMenu.add(showRoutesMI); - jcsMenuBar.add(viewMenu); + jcsMenuBar.add(windowMenu); settingsMenu.setText("Settings"); settingsMenu.setName("settingsMenu"); // NOI18N @@ -1143,37 +1064,35 @@ public void connect(boolean connect) { connected = JCS.getJcsCommandStation().isConnected(); if (info != null && connected) { - this.connectButton.setSelected(true); - this.controllerDescriptionLbl.setText(info.getProductName()); - this.controllerCatalogNumberLbl.setText(info.getArticleNumber()); - this.controllerSerialNumberLbl.setText(info.getSerialNumber()); - this.controllerHostNameLbl.setText(info.getHostname()); - this.powerButton.setSelected(JCS.getJcsCommandStation().isPowerOn()); - this.connectMI.setText("Disconnect"); + connectButton.setSelected(true); + controllerDescriptionLbl.setText(info.getProductName()); + controllerCatalogNumberLbl.setText(info.getArticleNumber()); + controllerSerialNumberLbl.setText(info.getSerialNumber()); + controllerHostNameLbl.setText(info.getHostname()); + powerButton.setSelected(JCS.getJcsCommandStation().isPowerOn()); + connectMI.setText("Disconnect"); } else { - this.connectButton.setSelected(false); - this.controllerHostNameLbl.setText("Disconnected"); - this.powerButton.setSelected(JCS.getJcsCommandStation().isPowerOn()); + connectButton.setSelected(false); + controllerHostNameLbl.setText("Disconnected"); + powerButton.setSelected(JCS.getJcsCommandStation().isPowerOn()); } } else { JCS.getJcsCommandStation().disconnect(); - this.controllerDescriptionLbl.setText("-"); - this.controllerCatalogNumberLbl.setText("-"); - this.controllerSerialNumberLbl.setText("-"); - this.controllerHostNameLbl.setText("Disconnected"); + controllerDescriptionLbl.setText("-"); + controllerCatalogNumberLbl.setText("-"); + controllerSerialNumberLbl.setText("-"); + controllerHostNameLbl.setText("Disconnected"); - this.connectMI.setText("Connect"); + connectMI.setText("Connect"); } } JCS.getJcsCommandStation().addDisconnectionEventListener(this); - this.powerButton.setEnabled(connect && connected); - this.showFeedbackMonitorBtn.setEnabled(connect && connected); - - //TODO Connect the VNCPanel to the Command station and support VNC property - this.showVNCBtn.setEnabled(connect && connected); + powerButton.setEnabled(connect && connected); + showFeedbackMonitorBtn.setEnabled(connect && connected); - this.setControllerProperties(); + showVNCBtn.setEnabled(connect && connected); + setControllerProperties(); } private void connectButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_connectButtonActionPerformed @@ -1224,7 +1143,10 @@ private void showVNCBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_showV private void autoPilotBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_autoPilotBtnActionPerformed //Logger.trace(evt.getActionCommand() + (autoPilotBtn.isSelected() ? " Enable" : " Disable") + " Auto mode"); + startAutopilot(); + }//GEN-LAST:event_autoPilotBtnActionPerformed + private void startAutopilot() { if (autoPilotBtn.isSelected()) { startAllLocsBtn.setEnabled(true); dispatcherStatusPanel.showDispatcherTab(); @@ -1235,24 +1157,11 @@ private void autoPilotBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_aut } AutoPilot.runAutoPilot(autoPilotBtn.isSelected()); - }//GEN-LAST:event_autoPilotBtnActionPerformed - - private void resetAutoPilotBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_resetAutoPilotBtnActionPerformed - AutoPilot.reset(); - }//GEN-LAST:event_resetAutoPilotBtnActionPerformed + } - private void virtualCBActionPerformed(ActionEvent evt) {//GEN-FIRST:event_virtualCBActionPerformed - Logger.trace(evt.getActionCommand() + " Switch Virtual Mode " + (virtualCB.isSelected() ? "On" : "Off")); - if (JCS.getJcsCommandStation() != null) { - JCS.getJcsCommandStation().setVirtual(virtualCB.isSelected()); - } - }//GEN-LAST:event_virtualCBActionPerformed private void startAllLocsBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_startAllLocsBtnActionPerformed - int result = JOptionPane.showConfirmDialog(this, "Are you sure you want to start All Locomotives?", "Start ALL Locomotives", JOptionPane.YES_NO_OPTION); - if (result == JOptionPane.YES_OPTION) { - AutoPilot.startAllLocomotives(); - } + startAllLocomotives(); }//GEN-LAST:event_startAllLocsBtnActionPerformed private void showAccessoryMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_showAccessoryMIActionPerformed @@ -1264,22 +1173,63 @@ private void showPropertiesMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event }//GEN-LAST:event_showPropertiesMIActionPerformed private void rotateTileMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_rotateTileMIActionPerformed - // TODO add your handling code here: + if (editMode) { + layoutPanel.rotateSelectedTile(); + } }//GEN-LAST:event_rotateTileMIActionPerformed private void flipTileHorizontallyMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_flipTileHorizontallyMIActionPerformed - // TODO add your handling code here: + if (editMode) { + layoutPanel.flipSelectedTileHorizontal(); + } }//GEN-LAST:event_flipTileHorizontallyMIActionPerformed private void flipTileVerticallyMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_flipTileVerticallyMIActionPerformed - - // TODO add your handling code here: + if (editMode) { + layoutPanel.flipSelectedTileVerical(); + } }//GEN-LAST:event_flipTileVerticallyMIActionPerformed private void deleteTileMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_deleteTileMIActionPerformed - // TODO add your handling code here: + if (editMode) { + layoutPanel.deleteSelectedTile(); + } }//GEN-LAST:event_deleteTileMIActionPerformed + private void virtualCBMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_virtualCBMIActionPerformed + Logger.trace(evt.getActionCommand() + " Switch Virtual Connection " + (virtualCBMI.isSelected() ? "On" : "Off")); + if (JCS.getJcsCommandStation() != null) { + JCS.getJcsCommandStation().setVirtual(virtualCBMI.isSelected()); + } + }//GEN-LAST:event_virtualCBMIActionPerformed + + private void vncMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_vncMIActionPerformed + showVNCConsole(); + }//GEN-LAST:event_vncMIActionPerformed + + private void autoPilotMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_autoPilotMIActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_autoPilotMIActionPerformed + + private void resetAutopilotMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_resetAutopilotMIActionPerformed + AutoPilot.reset(); + }//GEN-LAST:event_resetAutopilotMIActionPerformed + + private void startAllLocsMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_startAllLocsMIActionPerformed + startAllLocomotives(); + }//GEN-LAST:event_startAllLocsMIActionPerformed + + private void showRoutesMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_showRoutesMIActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_showRoutesMIActionPerformed + + private void startAllLocomotives() { + int result = JOptionPane.showConfirmDialog(this, "Are you sure you want to start All Locomotives?", "Start ALL Locomotives", JOptionPane.YES_NO_OPTION); + if (result == JOptionPane.YES_OPTION) { + AutoPilot.startAllLocomotives(); + } + } + private String getTitleString() { String jcsVersion = VersionInfo.getVersion(); @@ -1300,10 +1250,10 @@ public void openFiles(List files) { public void onDisconnect(DisconnectionEvent event) { JOptionPane.showMessageDialog(this, "CommandStation " + event.getSource() + " is disconnected.", "Disconnection error", JOptionPane.ERROR_MESSAGE); - this.controllerHostNameLbl.setText("Disconnected"); - this.connectMI.setText("Connect"); - this.connectButton.setSelected(false); - this.showVNCBtn.setEnabled(false); + controllerHostNameLbl.setText("Disconnected"); + connectMI.setText("Connect"); + connectButton.setSelected(false); + showVNCBtn.setEnabled(false); } @Override @@ -1339,9 +1289,11 @@ public void powerChanged(PowerEvent event) { powerButton.setSelected(event.isPower()); } + // Variables declaration - do not modify//GEN-BEGIN:variables private JMenuItem aboutMI; private JToggleButton autoPilotBtn; + private JMenuItem autoPilotMI; private JPanel bottomLeftPanel; private JPanel centerPanel; private CommandStationPanel commandStationPanel; @@ -1388,7 +1340,7 @@ public void powerChanged(PowerEvent event) { private LayoutPanel overviewPanel; private JToggleButton powerButton; private JMenuItem quitMI; - private JButton resetAutoPilotBtn; + private JMenuItem resetAutopilotMI; private JMenuItem rotateTileMI; private JMenu settingsMenu; private JPanel settingsPanel; @@ -1402,13 +1354,135 @@ public void powerChanged(PowerEvent event) { private JMenuItem showLocosMI; private JButton showOverviewBtn; private JMenuItem showPropertiesMI; + private JMenuItem showRoutesMI; private JMenuItem showSensorMonitor; private JButton showVNCBtn; private JButton startAllLocsBtn; + private JMenuItem startAllLocsMI; private StatusPanel statusPanel; private JPanel toolbarPanel; - private JMenu viewMenu; - private JCheckBox virtualCB; + private JCheckBoxMenuItem virtualCBMI; + private JMenuItem vncMI; private VNCPanel vncPanel; + private JMenu windowMenu; // End of variables declaration//GEN-END:variables + + private class PowerAction extends AbstractAction { + + private static final long serialVersionUID = 4263882874269440066L; + + @Override + public void actionPerformed(ActionEvent e) { + powerButton.doClick(50); + } + } + + private class QuitAction extends AbstractAction { + + private static final long serialVersionUID = 106411709893099942L; + + @Override + public void actionPerformed(ActionEvent e) { + QuitApp(); + } + } + + private class ShowMonitorAction extends AbstractAction { + + private static final long serialVersionUID = -3352181383049583600L; + + @Override + public void actionPerformed(ActionEvent e) { + showSensorMonitor(); + } + } + + private class HomeAction extends AbstractAction { + + private static final long serialVersionUID = 6369350924548859534L; + + @Override + public void actionPerformed(ActionEvent e) { + showOverviewPanel(); + } + } + + private class EditAction extends AbstractAction { + + private static final long serialVersionUID = -4725560671766567186L; + + @Override + public void actionPerformed(ActionEvent e) { + showEditLayoutPanel(); + } + } + + private class SelectModeKeyAction extends AbstractAction { + + private static final long serialVersionUID = -5543240676519086334L; + + @Override + public void actionPerformed(ActionEvent e) { + if (editMode) { + layoutPanel.setMode(LayoutCanvas.Mode.SELECT); + } + } + } + + private class AddModeKeyAction extends AbstractAction { + + private static final long serialVersionUID = -429465825958791906L; + + @Override + public void actionPerformed(ActionEvent e) { + if (editMode) { + layoutPanel.setMode(LayoutCanvas.Mode.ADD); + } + } + } + + private class DeleteModeKeyAction extends AbstractAction { + + private static final long serialVersionUID = 569113006687591145L; + + @Override + public void actionPerformed(ActionEvent e) { + if (editMode) { + layoutPanel.setMode(LayoutCanvas.Mode.DELETE); + } + } + } + + private class RotateKeyAction extends AbstractAction { + + private static final long serialVersionUID = -292237743142583719L; + + @Override + public void actionPerformed(ActionEvent e) { + if (editMode) { + layoutPanel.rotateSelectedTile(); + } + } + } + + private class FlipHorizontalKeyAction extends AbstractAction { + + private static final long serialVersionUID = 7657976620206362097L; + + @Override + public void actionPerformed(ActionEvent e) { + layoutPanel.flipSelectedTileHorizontal(); + } + } + + private class FlipVerticalKeyAction extends AbstractAction { + + private static final long serialVersionUID = -4269202419142803636L; + + @Override + public void actionPerformed(ActionEvent e) { + layoutPanel.flipSelectedTileVerical(); + } + } + } diff --git a/src/main/java/jcs/ui/StatusPanel.form b/src/main/java/jcs/ui/StatusPanel.form index cb64c254..71e2b00b 100644 --- a/src/main/java/jcs/ui/StatusPanel.form +++ b/src/main/java/jcs/ui/StatusPanel.form @@ -28,6 +28,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/jcs/ui/StatusPanel.java b/src/main/java/jcs/ui/StatusPanel.java index 9c564819..12e6a5e2 100644 --- a/src/main/java/jcs/ui/StatusPanel.java +++ b/src/main/java/jcs/ui/StatusPanel.java @@ -70,6 +70,10 @@ public void onMeasurement(MeasurementEvent event) { // //GEN-BEGIN:initComponents private void initComponents() { + jPanel1 = new javax.swing.JPanel(); + connectedLbl = new javax.swing.JLabel(); + virtualConnectionLbl = new javax.swing.JLabel(); + autopilotLbl = new javax.swing.JLabel(); measurePanel = new javax.swing.JPanel(); voltageLbl = new javax.swing.JLabel(); currentLbl = new javax.swing.JLabel(); @@ -80,6 +84,25 @@ private void initComponents() { setPreferredSize(new java.awt.Dimension(1200, 45)); setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.RIGHT, 0, 0)); + jPanel1.setPreferredSize(new java.awt.Dimension(300, 27)); + java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); + flowLayout1.setAlignOnBaseline(true); + jPanel1.setLayout(flowLayout1); + + connectedLbl.setText("con"); + connectedLbl.setToolTipText("Connected"); + jPanel1.add(connectedLbl); + + virtualConnectionLbl.setText("virt"); + virtualConnectionLbl.setToolTipText("Virtual Connection"); + jPanel1.add(virtualConnectionLbl); + + autopilotLbl.setText("Auto"); + autopilotLbl.setToolTipText("Autopilot running"); + jPanel1.add(autopilotLbl); + + add(jPanel1); + voltageLbl.setText("-"); voltageLbl.setToolTipText(""); voltageLbl.setPreferredSize(new java.awt.Dimension(55, 20)); @@ -101,10 +124,14 @@ private void initComponents() { // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel autopilotLbl; + private javax.swing.JLabel connectedLbl; private javax.swing.JLabel currentLbl; + private javax.swing.JPanel jPanel1; private javax.swing.JPanel jPanel2; private javax.swing.JPanel measurePanel; private javax.swing.JLabel tempLbl; + private javax.swing.JLabel virtualConnectionLbl; private javax.swing.JLabel voltageLbl; // End of variables declaration//GEN-END:variables diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.java b/src/main/java/jcs/ui/layout/LayoutCanvas.java index d5da470c..a3ce2914 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.java +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.java @@ -26,19 +26,16 @@ import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import javax.swing.AbstractAction; import javax.swing.JFrame; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; -import javax.swing.KeyStroke; import javax.swing.SwingUtilities; import jcs.commandStation.autopilot.AutoPilot; import jcs.entities.BlockBean; @@ -390,6 +387,12 @@ private Tile addTile(Point p, TileType tileType, Orientation orientation, Direct } } + void deleteSelectedTile() { + Logger.trace("Selected Tile " + selectedTile.getId()); + removeTile(selectedTile); + selectedTile = null; + } + void removeTile(Tile tile) { Tile toBeDeleted = (Tile) getComponentAt(tile.getCenter()); if (toBeDeleted != null) { diff --git a/src/main/java/jcs/ui/layout/LayoutPanel.form b/src/main/java/jcs/ui/layout/LayoutPanel.form index 8f2962af..b512ef69 100755 --- a/src/main/java/jcs/ui/layout/LayoutPanel.form +++ b/src/main/java/jcs/ui/layout/LayoutPanel.form @@ -317,6 +317,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -402,39 +435,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/main/java/jcs/ui/layout/LayoutPanel.java b/src/main/java/jcs/ui/layout/LayoutPanel.java index 3ffacdd6..cd9515c0 100755 --- a/src/main/java/jcs/ui/layout/LayoutPanel.java +++ b/src/main/java/jcs/ui/layout/LayoutPanel.java @@ -50,6 +50,8 @@ */ public class LayoutPanel extends JPanel { + private static final long serialVersionUID = 2275543202224445302L; + private final boolean readonly; public LayoutPanel() { @@ -133,46 +135,37 @@ private void postInit() { this.flipHorizontalBtn.setEnabled(!readonly); this.flipHorizontalBtn.setVisible(!readonly); - - //Todo Remove the Autopilot related things from this panel - //this.autoPilotBtn.setEnabled(readonly && JCS.getJcsCommandStation().isPowerOn()); -// this.autoPilotBtn.setEnabled(readonly); -// this.autoPilotBtn.setVisible(readonly); -// this.resetAutopilotBtn.setEnabled(readonly); -// this.resetAutopilotBtn.setVisible(readonly); -// this.startAllLocomotivesBtn.setEnabled(readonly && this.autoPilotBtn.isSelected()); -// this.startAllLocomotivesBtn.setVisible(readonly); - } else { -// this.toolBar.remove(this.autoPilotBtn); -// this.autoPilotBtn.setEnabled(readonly); -// this.autoPilotBtn.setVisible(readonly); -// this.toolBar.remove(this.resetAutopilotBtn); -// this.resetAutopilotBtn.setEnabled(readonly); -// this.resetAutopilotBtn.setVisible(readonly); -// this.toolBar.remove(this.startAllLocomotivesBtn); -// this.startAllLocomotivesBtn.setEnabled(readonly); -// this.startAllLocomotivesBtn.setVisible(readonly); } - this.toolBar.remove(this.autoPilotBtn); this.toolBar.remove(this.resetAutopilotBtn); this.toolBar.remove(this.startAllLocomotivesBtn); if (readonly) { loadLayout(); - - Powerlistener powerlistener = new Powerlistener(this); + Powerlistener powerlistener = new Powerlistener(); JCS.getJcsCommandStation().addPowerEventListener(powerlistener); - } } -// void saveLayout() { -// this.canvas.saveLayout(); -// } public void loadLayout() { - this.canvas.loadLayoutInBackground(); + canvas.loadLayoutInBackground(); + } + + public void rotateSelectedTile() { + canvas.rotateSelectedTile(); + } + + public void flipSelectedTileHorizontal() { + canvas.flipSelectedTileHorizontal(); + } + + public void flipSelectedTileVerical() { + canvas.flipSelectedTileVertical(); + } + + public void deleteSelectedTile() { + canvas.deleteSelectedTile(); } /** @@ -205,12 +198,12 @@ private void initComponents() { startAllLocomotivesBtn = new JToggleButton(); resetAutopilotBtn = new JButton(); filler1 = new Box.Filler(new Dimension(20, 0), new Dimension(20, 0), new Dimension(20, 32767)); + gridBtn = new JToggleButton(); + filler2 = new Box.Filler(new Dimension(20, 0), new Dimension(20, 0), new Dimension(20, 32767)); selectBtn = new JButton(); addBtn = new JButton(); deleteBtn = new JButton(); filler3 = new Box.Filler(new Dimension(20, 0), new Dimension(20, 0), new Dimension(20, 32767)); - gridBtn = new JToggleButton(); - filler2 = new Box.Filler(new Dimension(20, 0), new Dimension(20, 0), new Dimension(20, 32767)); straightBtn = new JToggleButton(); curvedBtn = new JToggleButton(); blockBtn = new JToggleButton(); @@ -421,6 +414,20 @@ public void actionPerformed(ActionEvent evt) { toolBar.add(resetAutopilotBtn); toolBar.add(filler1); + gridBtn.setIcon(new ImageIcon(getClass().getResource("/media/grid-2-24.png"))); // NOI18N + gridBtn.setSelected(true); + gridBtn.setToolTipText("Show Grid"); + gridBtn.setHorizontalTextPosition(SwingConstants.CENTER); + gridBtn.setSelectedIcon(new ImageIcon(getClass().getResource("/media/grid-dot-24.png"))); // NOI18N + gridBtn.setVerticalTextPosition(SwingConstants.BOTTOM); + gridBtn.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + gridBtnActionPerformed(evt); + } + }); + toolBar.add(gridBtn); + toolBar.add(filler2); + selectBtn.setIcon(new ImageIcon(getClass().getResource("/media/cursor-24-y.png"))); // NOI18N selectBtn.setToolTipText("Select"); selectBtn.setFocusable(false); @@ -467,20 +474,6 @@ public void actionPerformed(ActionEvent evt) { toolBar.add(deleteBtn); toolBar.add(filler3); - gridBtn.setIcon(new ImageIcon(getClass().getResource("/media/grid-2-24.png"))); // NOI18N - gridBtn.setSelected(true); - gridBtn.setToolTipText("Show Grid"); - gridBtn.setHorizontalTextPosition(SwingConstants.CENTER); - gridBtn.setSelectedIcon(new ImageIcon(getClass().getResource("/media/grid-dot-24.png"))); // NOI18N - gridBtn.setVerticalTextPosition(SwingConstants.BOTTOM); - gridBtn.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent evt) { - gridBtnActionPerformed(evt); - } - }); - toolBar.add(gridBtn); - toolBar.add(filler2); - tileBtnGroup.add(straightBtn); straightBtn.setIcon(new ImageIcon(getClass().getResource("/media/new-straight.png"))); // NOI18N straightBtn.setToolTipText("Straight Track"); @@ -926,13 +919,13 @@ private void resetAutopilotBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:even }//GEN-LAST:event_resetAutopilotBtnActionPerformed private void setTileType(TileBean.TileType tileType) { - this.canvas.setTileType(tileType); + canvas.setTileType(tileType); } private void setDirection(Direction direction) { - this.canvas.setDirection(direction); + canvas.setDirection(direction); } - + public void setMode(LayoutCanvas.Mode mode) { switch (mode) { case SELECT -> { @@ -957,17 +950,11 @@ public void setMode(LayoutCanvas.Mode mode) { } } - this.canvas.setMode(mode); + canvas.setMode(mode); } private class Powerlistener implements PowerEventListener { - private final LayoutPanel layoutPanel; - - Powerlistener(LayoutPanel layoutPanel) { - this.layoutPanel = layoutPanel; - } - @Override public void onPowerChange(PowerEvent event) { Logger.info("Track Power is " + (event.isPower() ? "on" : "off")); From 4674440076e43e373028b6d8833a8b826b560045 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Fri, 28 Mar 2025 21:07:15 +0100 Subject: [PATCH 38/70] Added tile loader --- src/main/java/jcs/ui/layout/LayoutPanel.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/main/java/jcs/ui/layout/LayoutPanel.java b/src/main/java/jcs/ui/layout/LayoutPanel.java index cd9515c0..f1258ff8 100755 --- a/src/main/java/jcs/ui/layout/LayoutPanel.java +++ b/src/main/java/jcs/ui/layout/LayoutPanel.java @@ -44,9 +44,20 @@ import org.tinylog.Logger; /** - * This canvas / Panel is used to draw the layout + * The `LayoutPanel` class is a custom `JPanel` used to visually represent and manipulate a layout. + * It provides a graphical canvas (`LayoutCanvas`) for drawing and editing elements,
+ * along with a toolbar offering various tools for adding, deleting, manipulating, and loading/saving layouts. + * The panel can operate in read-only mode, disabling editing functionalities. + * + * It uses a tile-based system to represent tracks and other elements, allowing for easy manipulation and modification of the layout.
+ * The class handles events related to adding, deleting, rotating, + * and flipping tiles, as well as loading and saving layout configurations.
+ * It supports different tile types (straight tracks, curved tracks, blocks, sensors, signals, switches, and crossings), each + * with different properties and behaviors. + * external resource (e.g., a + * database or configuration file) to load and save layout data. It also incorporates an undo/redo mechanism for easy recovery from mistakes.It provides options for showing/hiding the grid and offers + * different modes of operation (adding, deleting, selecting, moving). * - * @author frans */ public class LayoutPanel extends JPanel { From 08e8d169c51088aaed456844bd560cda93b44482 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Wed, 2 Apr 2025 20:53:41 +0200 Subject: [PATCH 39/70] Added Dialogs, Dialogs are accessible via menu and menu items. Some refactoring. --- src/main/java/jcs/JCS.java | 17 - .../commandStation/JCSCommandStationImpl.java | 1 - .../jcs/persistence/H2PersistenceService.java | 90 ++++- .../jcs/persistence/PersistenceFactory.java | 4 +- .../jcs/persistence/PersistenceService.java | 382 +++++++++++++++++- .../java/jcs/ui/FeedbackSensorDialog.java | 2 +- src/main/java/jcs/ui/JCSFrame.form | 4 +- src/main/java/jcs/ui/JCSFrame.java | 79 ++-- .../java/jcs/ui/options/PropertiesPanel.java | 278 ------------- .../java/jcs/ui/settings/AccessoryDialog.form | 33 ++ .../java/jcs/ui/settings/AccessoryDialog.java | 86 ++++ .../AccessorySettingsPanel.form} | 0 .../AccessorySettingsPanel.java} | 14 +- .../CommandStationDialog.form | 4 +- .../CommandStationDialog.java | 6 +- .../CommandStationPanel.form | 0 .../CommandStationPanel.java | 2 +- .../IconFileChooser.form | 0 .../IconFileChooser.java | 2 +- .../jcs/ui/settings/LocomotiveDialog.form | 35 ++ .../jcs/ui/settings/LocomotiveDialog.java | 90 +++++ .../LocomotiveSettingsPanel.form} | 0 .../LocomotiveSettingsPanel.java} | 10 +- .../{options => settings}/OptionDialog.form | 8 +- .../{options => settings}/OptionDialog.java | 20 +- .../jcs/ui/settings/PropertiesDialog.form | 33 ++ .../jcs/ui/settings/PropertiesDialog.java | 86 ++++ .../PropertySettingsPanel.form} | 0 .../ui/settings/PropertySettingsPanel.java | 280 +++++++++++++ .../table/BeanTableModel.java | 2 +- .../table/ButtonColumn.java | 2 +- .../table/ControllerInfoTableModel.java | 2 +- .../table/PropertiesTableModel.java | 2 +- .../table/SensorTableModel.java | 2 +- .../table/SignalTableModel.java | 2 +- .../table/TurnoutTableModel.java | 2 +- 36 files changed, 1190 insertions(+), 390 deletions(-) delete mode 100755 src/main/java/jcs/ui/options/PropertiesPanel.java create mode 100644 src/main/java/jcs/ui/settings/AccessoryDialog.form create mode 100644 src/main/java/jcs/ui/settings/AccessoryDialog.java rename src/main/java/jcs/ui/{options/AccessoryPreferencesPanel.form => settings/AccessorySettingsPanel.form} (100%) rename src/main/java/jcs/ui/{options/AccessoryPreferencesPanel.java => settings/AccessorySettingsPanel.java} (99%) rename src/main/java/jcs/ui/{options => settings}/CommandStationDialog.form (98%) rename src/main/java/jcs/ui/{options => settings}/CommandStationDialog.java (95%) rename src/main/java/jcs/ui/{options => settings}/CommandStationPanel.form (100%) rename src/main/java/jcs/ui/{options => settings}/CommandStationPanel.java (99%) rename src/main/java/jcs/ui/{options => settings}/IconFileChooser.form (100%) rename src/main/java/jcs/ui/{options => settings}/IconFileChooser.java (99%) create mode 100644 src/main/java/jcs/ui/settings/LocomotiveDialog.form create mode 100644 src/main/java/jcs/ui/settings/LocomotiveDialog.java rename src/main/java/jcs/ui/{options/LocomotivePreferencesPanel.form => settings/LocomotiveSettingsPanel.form} (100%) rename src/main/java/jcs/ui/{options/LocomotivePreferencesPanel.java => settings/LocomotiveSettingsPanel.java} (99%) rename src/main/java/jcs/ui/{options => settings}/OptionDialog.form (96%) rename src/main/java/jcs/ui/{options => settings}/OptionDialog.java (92%) create mode 100644 src/main/java/jcs/ui/settings/PropertiesDialog.form create mode 100644 src/main/java/jcs/ui/settings/PropertiesDialog.java rename src/main/java/jcs/ui/{options/PropertiesPanel.form => settings/PropertySettingsPanel.form} (100%) create mode 100755 src/main/java/jcs/ui/settings/PropertySettingsPanel.java rename src/main/java/jcs/ui/{options => settings}/table/BeanTableModel.java (99%) rename src/main/java/jcs/ui/{options => settings}/table/ButtonColumn.java (99%) rename src/main/java/jcs/ui/{options => settings}/table/ControllerInfoTableModel.java (99%) rename src/main/java/jcs/ui/{options => settings}/table/PropertiesTableModel.java (98%) rename src/main/java/jcs/ui/{options => settings}/table/SensorTableModel.java (99%) rename src/main/java/jcs/ui/{options => settings}/table/SignalTableModel.java (98%) rename src/main/java/jcs/ui/{options => settings}/table/TurnoutTableModel.java (98%) diff --git a/src/main/java/jcs/JCS.java b/src/main/java/jcs/JCS.java index 3189fe84..5fd2167d 100755 --- a/src/main/java/jcs/JCS.java +++ b/src/main/java/jcs/JCS.java @@ -118,7 +118,6 @@ private void startGui() { desktop.setAboutHandler(new JCSAboutHandler()); desktop.setQuitHandler(new JCSQuitHandler()); desktop.setPreferencesHandler(new JCSPreferencesHandler()); - Taskbar taskbar = Taskbar.getTaskbar(); try { @@ -190,22 +189,6 @@ public void run() { Logger.info("JCS " + VersionInfo.getVersion() + " session finished"); } -// @Deprecated -// public static void addRefreshListener(RefreshEventListener refreshListener) { -// instance.refreshEventListeners.add(refreshListener); -// } - -// @Deprecated -// public static void removeRefreshListener(RefreshEventListener refreshListener) { -// instance.refreshEventListeners.remove(refreshListener); -// } - -// public static void settingsChanged(RefreshEvent refreshEvent) { -// for (RefreshEventListener rel : instance.refreshEventListeners) { -// rel.onChange(refreshEvent); -// } -// } - public static JCS getInstance() { if (instance == null) { instance = new JCS(); diff --git a/src/main/java/jcs/commandStation/JCSCommandStationImpl.java b/src/main/java/jcs/commandStation/JCSCommandStationImpl.java index 9420125b..9037f844 100755 --- a/src/main/java/jcs/commandStation/JCSCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/JCSCommandStationImpl.java @@ -73,7 +73,6 @@ public class JCSCommandStationImpl implements JCSCommandStation { private Map feedbackControllers; private final List anonymousSensorListeners; - //private final Map sensorEventListeners; private final List accessoryEventListeners; private final List LocomotiveFunctionEventListeners; diff --git a/src/main/java/jcs/persistence/H2PersistenceService.java b/src/main/java/jcs/persistence/H2PersistenceService.java index 001e1e64..98464ca2 100755 --- a/src/main/java/jcs/persistence/H2PersistenceService.java +++ b/src/main/java/jcs/persistence/H2PersistenceService.java @@ -18,6 +18,8 @@ import com.dieselpoint.norm.Database; import com.dieselpoint.norm.DbException; import java.awt.Image; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; import java.io.File; import java.io.IOException; import java.util.ArrayList; @@ -48,11 +50,13 @@ public class H2PersistenceService implements PersistenceService { private final HashMap imageCache; private final HashMap functionImageCache; + private final PropertyChangeSupport changeSupport; public H2PersistenceService() { connect(); imageCache = new HashMap<>(); functionImageCache = new HashMap<>(); + changeSupport = new PropertyChangeSupport(this); setJCSPropertiesAsSystemProperties(); } @@ -62,6 +66,14 @@ private void connect() { database.setSqlMaker(new H2SqlMaker()); } + public void addPropertyChangeListener(PropertyChangeListener listener) { + changeSupport.addPropertyChangeListener(listener); + } + + public void removePropertyChangeListener(PropertyChangeListener listener) { + changeSupport.removePropertyChangeListener(listener); + } + @Override public List getProperties() { List props = database.results(JCSPropertyBean.class); @@ -76,15 +88,15 @@ public JCSPropertyBean getProperty(String key) { @Override public JCSPropertyBean persist(JCSPropertyBean property) { - JCSPropertyBean prop - = database.where("p_key=?", property.getKey()).first(JCSPropertyBean.class); - if (prop != null) { + JCSPropertyBean oldProp = database.where("p_key=?", property.getKey()).first(JCSPropertyBean.class); + if (oldProp != null) { int rows = database.update(property).getRowsAffected(); Logger.trace(rows + " rows updated"); } else { int rows = database.insert(property).getRowsAffected(); Logger.trace(rows + " rows inserted"); } + changeSupport.firePropertyChange("data.property", oldProp, property); return property; } @@ -92,6 +104,7 @@ public JCSPropertyBean persist(JCSPropertyBean property) { public void remove(JCSPropertyBean property) { int rows = database.delete(property).getRowsAffected(); Logger.trace(rows + " rows deleted"); + changeSupport.firePropertyChange("data.property.deleted", property, null); } @Override @@ -116,8 +129,7 @@ public List getAssignedSensors() { @Override public SensorBean getSensor(Integer deviceId, Integer contactId) { Object[] args = new Object[]{deviceId, contactId}; - SensorBean sensor - = database.where("device_id=? and contact_id=?", args).first(SensorBean.class); + SensorBean sensor = database.where("device_id=? and contact_id=?", args).first(SensorBean.class); return sensor; } @@ -132,11 +144,12 @@ public SensorBean persist(SensorBean sensor) { SensorBean prev = database.where("id=?", sensor.getId()).first(SensorBean.class); if (prev != null) { - // sensor.setName(prev.getName()); database.update(sensor); } else { database.insert(sensor); } + + changeSupport.firePropertyChange("data.sensor", prev, sensor); return sensor; } @@ -150,6 +163,7 @@ public void remove(SensorBean sensor) { int rows = database.delete(sensor).getRowsAffected(); Logger.trace(sensor + " rows + " + rows + " deleted"); + changeSupport.firePropertyChange("data.sensor.deleted", sensor, null); } @Override @@ -340,11 +354,13 @@ public FunctionBean persist(FunctionBean functionBean) { } } try { - if (database.where("id=?", functionBean.getId()).first(FunctionBean.class) != null) { + FunctionBean prev = database.where("id=?", functionBean.getId()).first(FunctionBean.class); + if (prev != null) { database.update(functionBean); } else { database.insert(functionBean); } + changeSupport.firePropertyChange("data.function", prev, functionBean); } catch (DbException dbe) { Logger.error("Error: " + dbe.getMessage()); Logger.debug("SQL: " + dbe.getSql()); @@ -365,12 +381,14 @@ private List persistFunctionBeans(List functionsBean @Override public synchronized LocomotiveBean persist(LocomotiveBean locomotive) { try { - if (database.where("id=?", locomotive.getId()).first(LocomotiveBean.class) != null) { + LocomotiveBean prev = database.where("id=?", locomotive.getId()).first(LocomotiveBean.class); + if (prev != null) { database.update(locomotive); } else { database.sql("delete from locomotive_functions where locomotive_id =?", locomotive.getId()).execute(); database.insert(locomotive); } + changeSupport.firePropertyChange("data.locomotive", prev, locomotive); } catch (Exception e) { Logger.error(e); } @@ -386,11 +404,12 @@ public synchronized LocomotiveBean persist(LocomotiveBean locomotive) { @Override public synchronized void remove(LocomotiveBean locomotive) { - // First femove the functions + // First remove the functions database.sql("delete from locomotive_functions where locomotive_id =?", locomotive.getId()).execute(); int rows = database.delete(locomotive).getRowsAffected(); Logger.trace(rows + " rows deleted"); + changeSupport.firePropertyChange("data.locomotive.deleted", locomotive, null); } @Override @@ -401,10 +420,10 @@ public Image getLocomotiveImage(String imageName) { if (image != null) { int size = 100; float aspect = (float) image.getHeight(null) / (float) image.getWidth(null); - this.imageCache.put(imageName, image.getScaledInstance(size, (int) (size * aspect), Image.SCALE_SMOOTH)); + imageCache.put(imageName, image.getScaledInstance(size, (int) (size * aspect), Image.SCALE_SMOOTH)); } } - return this.imageCache.get(imageName); + return imageCache.get(imageName); } @Override @@ -415,10 +434,10 @@ public Image getFunctionImage(String imageName) { if (image != null) { int size = 30; float aspect = (float) image.getHeight(null) / (float) image.getWidth(null); - this.functionImageCache.put(imageName, image.getScaledInstance(size, (int) (size * aspect), Image.SCALE_SMOOTH)); + functionImageCache.put(imageName, image.getScaledInstance(size, (int) (size * aspect), Image.SCALE_SMOOTH)); } } - return this.functionImageCache.get(imageName); + return functionImageCache.get(imageName); } @Override @@ -530,11 +549,13 @@ public AccessoryBean getAccessoryByAddress(Integer address) { @Override public synchronized AccessoryBean persist(AccessoryBean accessory) { - if (database.where("id=?", accessory.getId()).first(AccessoryBean.class) != null) { + AccessoryBean prev = database.where("id=?", accessory.getId()).first(AccessoryBean.class); + if (prev != null) { database.update(accessory); } else { database.insert(accessory); } + changeSupport.firePropertyChange("data.accessory", prev, accessory); return accessory; } @@ -544,6 +565,7 @@ public synchronized void remove(AccessoryBean accessory) { database.sql("update tiles set sensor_id = null where accessory_id =?", accessory.getId()).execute(); int rows = database.delete(accessory).getRowsAffected(); Logger.trace(rows + " Accessories deleted"); + changeSupport.firePropertyChange("data.accessory.deleted", accessory, null); } private TileBean addReleatedObjects(TileBean tileBean, BlockBean blockBean) { @@ -612,16 +634,18 @@ public synchronized TileBean persist(TileBean tileBean) { } if (tileBean.getId() != null) { - if (database.where("id=?", tileBean.getId()).first(TileBean.class) != null) { + TileBean prev = database.where("id=?", tileBean.getId()).first(TileBean.class); + if (prev != null) { database.update(tileBean).getRowsAffected(); //Logger.trace("Updated " + tileBean); } else { database.insert(tileBean); } + changeSupport.firePropertyChange("data.tile", prev, tileBean); } if (tileBean.getBlockBean() != null) { - this.persist(tileBean.getBlockBean()); + persist(tileBean.getBlockBean()); } return tileBean; @@ -633,10 +657,11 @@ public synchronized void remove(TileBean tileBean) { if (tileBean.getBlockBean() != null) { BlockBean bb = tileBean.getBlockBean(); - this.remove(bb); + remove(bb); } int rows = database.delete(tileBean).getRowsAffected(); Logger.trace(rows + " TileBean(s) deleted"); + changeSupport.firePropertyChange("data.tile.deleted", tileBean, null); } @Override @@ -687,7 +712,8 @@ private List getRouteElements(String routeId) { } private RouteElementBean persist(RouteElementBean routeElement) { - if (database.where("id=?", routeElement.getId()).first(RouteElementBean.class) != null) { + RouteElementBean prev = database.where("id=?", routeElement.getId()).first(RouteElementBean.class); + if (prev != null) { database.update(routeElement); } else { database.insert(routeElement); @@ -752,7 +778,8 @@ public synchronized List getRoutes(String fromTileId, String fromSuff @Override public synchronized RouteBean persist(RouteBean route) { - if (database.where("id=?", route.getId()).first(RouteBean.class) != null) { + RouteBean prev = database.where("id=?", route.getId()).first(RouteBean.class); + if (prev != null) { database.update(route); } else { database.insert(route); @@ -773,6 +800,7 @@ public synchronized RouteBean persist(RouteBean route) { } route.setRouteElements(rblr); } + changeSupport.firePropertyChange("data.route", prev, route); return route; } @@ -795,7 +823,9 @@ private void removeRouteByTileId(String tileId) { } for (String rid : routIds) { + RouteBean route = this.getRoute(rid); database.sql("delete from routes where id =?", rid).execute(); + changeSupport.firePropertyChange("data.route.deleted", route, null); } } @@ -808,12 +838,14 @@ public synchronized void remove(RouteBean route) { int rows = this.database.delete(route).getRowsAffected(); Logger.trace(rows + " rows deleted"); + changeSupport.firePropertyChange("data.route.deleted", route, null); } public synchronized void removeAllRoutes() { database.sql("delete from route_elements").execute(); int rows = database.sql("delete from routes").execute().getRowsAffected(); Logger.trace("Deleted " + rows + " routes"); + changeSupport.firePropertyChange("data.routes.deleted", null, null); } private void setJCSPropertiesAsSystemProperties() { @@ -898,12 +930,19 @@ public synchronized BlockBean persist(BlockBean block) { } } - if (block != null && block.getId() != null && database.where("id=?", block.getId()).first(BlockBean.class) != null) { - database.update(block); + BlockBean prev = null; + if (block != null && block.getId() != null) { + prev = database.where("id=?", block.getId()).first(BlockBean.class); + if (prev != null) { + database.update(block); + } else { + database.insert(block); + } } else { database.insert(block); } + changeSupport.firePropertyChange("data.blockr", prev, block); return block; } @@ -911,12 +950,14 @@ public synchronized BlockBean persist(BlockBean block) { public synchronized void remove(BlockBean block) { int rows = this.database.delete(block).getRowsAffected(); Logger.trace(rows + " rows deleted"); + changeSupport.firePropertyChange("data.sblock.deleted", block, null); } @Override public synchronized void removeAllBlocks() { int rows = database.sql("delete from blocks").execute().getRowsAffected(); Logger.trace("Deleted " + rows + " blocks"); + changeSupport.firePropertyChange("data.block.deleted", null, null); } @Override @@ -938,18 +979,23 @@ public CommandStationBean getDefaultCommandStation() { @Override public synchronized CommandStationBean persist(CommandStationBean commandStationBean) { - if (database.where("id=?", commandStationBean.getId()).first(CommandStationBean.class) != null) { + CommandStationBean prev = database.where("id=?", commandStationBean.getId()).first(CommandStationBean.class); + if (prev != null) { database.update(commandStationBean); } else { Logger.warn("Can't Create CommandStation " + commandStationBean); } + changeSupport.firePropertyChange("data.commandStation", prev, commandStationBean); return commandStationBean; } @Override public synchronized CommandStationBean changeDefaultCommandStation(CommandStationBean newDefaultCommandStationBean) { + CommandStationBean prev = getDefaultCommandStation(); Object[] args = new Object[]{newDefaultCommandStationBean.getId(), newDefaultCommandStationBean.getId()}; database.sql("update command_stations set default_cs = case when id = ? then true else false end, enabled = case when id = ? then true else false end", args).execute(); + + changeSupport.firePropertyChange("data.commandStation", prev, newDefaultCommandStationBean); return newDefaultCommandStationBean; } diff --git a/src/main/java/jcs/persistence/PersistenceFactory.java b/src/main/java/jcs/persistence/PersistenceFactory.java index e35668a1..afe1caee 100755 --- a/src/main/java/jcs/persistence/PersistenceFactory.java +++ b/src/main/java/jcs/persistence/PersistenceFactory.java @@ -50,8 +50,8 @@ protected boolean createPersistenceService() { if (persistenceServiceImpl == null) { RunUtil.loadProperties(); RunUtil.loadExternalProperties(); - - persistenceServiceImpl = System.getProperty("persistenceService","jcs.persistence.H2PersistenceService"); + + persistenceServiceImpl = System.getProperty("persistenceService", "jcs.persistence.H2PersistenceService"); } H2DatabaseUtil.setProperties(); diff --git a/src/main/java/jcs/persistence/PersistenceService.java b/src/main/java/jcs/persistence/PersistenceService.java index 5e0d8182..28ec731c 100755 --- a/src/main/java/jcs/persistence/PersistenceService.java +++ b/src/main/java/jcs/persistence/PersistenceService.java @@ -16,6 +16,7 @@ package jcs.persistence; import java.awt.Image; +import java.beans.PropertyChangeListener; import java.util.List; import jcs.entities.AccessoryBean; import jcs.entities.BlockBean; @@ -31,136 +32,513 @@ /** * The Persistence Service takes care of all persistence functionality which is needed within the JCS Application * - * @author frans */ public interface PersistenceService { + /** + * Adds a PropertyChangeListener to the service. Used for observing changes to persisted data. + * + * @param listener The PropertyChangeListener to add. + */ + void addPropertyChangeListener(PropertyChangeListener listener); + + /** + * Removes a PropertyChangeListener from the service. + * + * @param listener The PropertyChangeListener to remove. + */ + void removePropertyChangeListener(PropertyChangeListener listener); + + /** + * Retrieves all JCSPropertyBeans. + * + * @return A List of JCSPropertyBeans. + */ List getProperties(); + /** + * Retrieves a JCSPropertyBean by its key. + * + * @param key The key of the JCSPropertyBean to retrieve. + * @return The JCSPropertyBean, or null if not found. + */ JCSPropertyBean getProperty(String key); + /** + * Persists a JCSPropertyBean. + * + * @param propertyBean The JCSPropertyBean to persist. + * @return The persisted JCSPropertyBean. + */ JCSPropertyBean persist(JCSPropertyBean propertyBean); + /** + * Removes a JCSPropertyBean. + * + * @param property The JCSPropertyBean to remove. + */ void remove(JCSPropertyBean property); // Sensors + /** + * Retrieves all SensorBeans. + * + * @return A List of SensorBeans. + */ List getSensors(); + /** + * Retrieves all assigned SensorBeans. + * + * @return A List of assigned SensorBeans. + */ List getAssignedSensors(); + /** + * Retrieves a SensorBean by its ID. + * + * @param id The ID of the SensorBean to retrieve. + * @return The SensorBean, or null if not found. + */ SensorBean getSensor(String id); + /** + * Retrieves a SensorBean by device and contact ID. + * + * @param deviceId The device ID. + * @param contactId The contact ID. + * @return The SensorBean, or null if not found. + */ SensorBean getSensor(Integer deviceId, Integer contactId); + /** + * Persists a SensorBean. + * + * @param sensor The SensorBean to persist. + * @return The persisted SensorBean. + */ SensorBean persist(SensorBean sensor); + /** + * Removes a SensorBean. + * + * @param sensor The SensorBean to remove. + */ void remove(SensorBean sensor); + /** + * Generates a list of SensorBeans based on bus lengths. + * + * @param deviceId The device ID. + * @param bus0len Length of bus 0. + * @param bus1len Length of bus 1. + * @param bus2len Length of bus 2. + * @param bus3len Length of bus 3. + * @return A List of generated SensorBeans. + */ List generateSensorBeans(Integer deviceId, Integer bus0len, Integer bus1len, Integer bus2len, Integer bus3len); // Locomotive + /** + * Retrieves all LocomotiveBeans. + * + * @return A List of all LocomotiveBeans. + */ List getAllLocomotives(); + /** + * Retrieves all LocomotiveBeans (filter not specified). + * + * @return A List of LocomotiveBeans. Implied filter behavior unclear. + */ List getLocomotives(); + /** + * Retrieves LocomotiveBeans based on a show flag. + * + * @param show The show flag. + * @return A List of LocomotiveBeans. + */ List getLocomotives(boolean show); + /** + * Retrieves LocomotiveBeans by command station ID. + * + * @param commandStationId The command station ID. + * @return A List of LocomotiveBeans. + */ List getLocomotivesByCommandStationId(String commandStationId); + /** + * Retrieves LocomotiveBeans by command station ID and show flag. + * + * @param commandStationId The command station ID. + * @param show The show flag. + * @return A List of LocomotiveBeans. + */ List getLocomotivesByCommandStationId(String commandStationId, Boolean show); + /** + * Retrieves a LocomotiveBean by address, decoder type, and command station ID. + * + * @param address The address. + * @param decoderType The decoder type. + * @param commandStionId The command station ID. + * @return The LocomotiveBean, or null if not found. + */ LocomotiveBean getLocomotive(Integer address, DecoderType decoderType, String commandStionId); + /** + * Retrieves a LocomotiveBean by UID and command station ID. + * + * @param locUid The locomotive UID. + * @param commandStionId The command station ID. + * @return The LocomotiveBean, or null if not found. + */ LocomotiveBean getLocomotive(Integer locUid, String commandStionId); + /** + * Retrieves a LocomotiveBean by ID. + * + * @param id The ID of the LocomotiveBean to retrieve. + * @return The LocomotiveBean, or null if not found. + */ LocomotiveBean getLocomotive(Long id); + /** + * Persists a LocomotiveBean. + * + * @param locomotive The LocomotiveBean to persist. + * @return The persisted LocomotiveBean. + */ LocomotiveBean persist(LocomotiveBean locomotive); + /** + * Retrieves a list of FunctionBeans associated with a locomotive. + * + * @param locomotiveId The ID of the locomotive. + * @return A List of FunctionBeans. + */ List getLocomotiveFunctions(Long locomotiveId); + /** + * Retrieves a FunctionBean associated with a locomotive and function number. + * + * @param locomotiveId The ID of the locomotive. + * @param number The function number. + * @return The FunctionBean, or null if not found. + */ FunctionBean getLocomotiveFunction(Long locomotiveId, Integer number); + /** + * Persists a FunctionBean. + * + * @param functionBean The FunctionBean to persist. + * @return The persisted FunctionBean. + */ FunctionBean persist(FunctionBean functionBean); + /** + * Removes a LocomotiveBean. + * + * @param locomotiveBean The LocomotiveBean to remove. + */ void remove(LocomotiveBean locomotiveBean); // Accessories + /** + * Retrieves all AccessoryBeans. + * + * @return A List of AccessoryBeans. + */ List getAccessories(); + /** + * Retrieves AccessoryBeans by command station ID. + * + * @param commandStationId The command station ID. + * @return A List of AccessoryBeans. + */ List getAccessoriesByCommandStationId(String commandStationId); + /** + * Checks if an accessory is locked. + * + * @param accessoryId The ID of the accessory. + * @return True if the accessory is locked, false otherwise. + */ boolean isAccessoryLocked(String accessoryId); + /** + * Retrieves all turnout AccessoryBeans. + * + * @return A List of turnout AccessoryBeans. + */ List getTurnouts(); + /** + * Retrieves all signal AccessoryBeans. + * + * @return A List of signal AccessoryBeans. + */ List getSignals(); + /** + * Retrieves an AccessoryBean by address and command station ID. + * + * @param address The address. + * @param commandStationId The command station ID. + * @return The AccessoryBean, or null if not found. + */ AccessoryBean getAccessoryByAddressAndCommandStationId(Integer address, String commandStationId); + /** + * Retrieves an AccessoryBean by ID. + * + * @param id The ID of the AccessoryBean to retrieve. + * @return The AccessoryBean, or null if not found. + */ AccessoryBean getAccessory(String id); + /** + * Retrieves an AccessoryBean by address. + * + * @param address The address. + * @return The AccessoryBean, or null if not found. + */ AccessoryBean getAccessoryByAddress(Integer address); + /** + * Persists an AccessoryBean. + * + * @param accessoryBean The AccessoryBean to persist. + * @return The persisted AccessoryBean. + */ AccessoryBean persist(AccessoryBean accessoryBean); + /** + * Removes an AccessoryBean. + * + * @param accessoryBean The AccessoryBean to remove. + */ void remove(AccessoryBean accessoryBean); // Tile + /** + * Retrieves all TileBeans. + * + * @return A List of TileBeans. + */ List getTileBeans(); + /** + * Retrieves TileBeans by tile type. + * + * @param tileType The tile type. + * @return A List of TileBeans. + */ List getTileBeansByTileType(TileBean.TileType tileType); + /** + * Retrieves a TileBean by ID. + * + * @param id The ID of the TileBean to retrieve. + * @return The TileBean, or null if not found. + */ TileBean getTileBean(String id); + /** + * Retrieves a TileBean by x and y coordinates. + * + * @param x The x coordinate. + * @param y The y coordinate. + * @return The TileBean, or null if not found. + */ TileBean getTileBean(Integer x, Integer y); + /** + * Persists a TileBean. + * + * @param tileBean The TileBean to persist. + * @return The persisted TileBean. + */ TileBean persist(TileBean tileBean); + /** + * Persists a list of TileBeans. + * + * @param tiles The list of TileBeans to persist. + */ void persist(List tiles); + /** + * Removes a TileBean. + * + * @param tile The TileBean to remove. + */ void remove(TileBean tile); + /** + * Retrieves all RouteBeans. + * + * @return A List of RouteBeans. + */ List getRoutes(); + /** + * Retrieves a RouteBean by ID. + * + * @param id The ID of the RouteBean to retrieve. + * @return The RouteBean, or null if not found. + */ RouteBean getRoute(String id); + /** + * Retrieves RouteBeans by fromTileId and fromSuffix. + * + * @param fromTileId The fromTileId. + * @param fromSuffix The fromSuffix. + * @return A List of RouteBeans. + */ List getRoutes(String fromTileId, String fromSuffix); + /** + * Retrieves a RouteBean by fromTileId, fromSuffix, toTileId, and toSuffix. + * + * @param fromTileId The fromTileId. + * @param fromSuffix The fromSuffix. + * @param toTileId The toTileId. + * @param toSuffix The toSuffix. + * @return The RouteBean, or null if not found. + */ RouteBean getRoute(String fromTileId, String fromSuffix, String toTileId, String toSuffix); + /** + * Persists a RouteBean. + * + * @param routeBean The RouteBean to persist. + * @return The persisted RouteBean. + */ RouteBean persist(RouteBean routeBean); + /** + * Removes a RouteBean. + * + * @param routeBean The RouteBean to remove. + */ void remove(RouteBean routeBean); + /** + * Retrieves a BlockBean by locomotive ID. + * + * @param locomotiveId The locomotive ID. + * @return The BlockBean, or null if not found. + */ BlockBean getBlockByLocomotiveId(Long locomotiveId); + /** + * Retrieves all BlockBeans. + * + * @return A List of BlockBeans. + */ List getBlocks(); + /** + * Retrieves a BlockBean by ID. + * + * @param id The ID of the BlockBean to retrieve. + * @return The BlockBean, or null if not found. + */ BlockBean getBlock(String id); + /** + * Retrieves a BlockBean by tile ID. + * + * @param tileId The tile ID. + * @return The BlockBean, or null if not found. + */ BlockBean getBlockByTileId(String tileId); + /** + * Persists a BlockBean. + * + * @param block The BlockBean to persist. + * @return The persisted BlockBean. + */ BlockBean persist(BlockBean block); + /** + * Removes a BlockBean. + * + * @param block The BlockBean to remove. + */ void remove(BlockBean block); + /** + * Removes all BlockBeans. + */ void removeAllBlocks(); + /** + * Retrieves all CommandStationBeans. + * + * @return A List of CommandStationBeans. + */ List getCommandStations(); + /** + * Retrieves a CommandStationBean by ID. + * + * @param id The ID of the CommandStationBean to retrieve. + * @return The CommandStationBean, or null if not found. + */ CommandStationBean getCommandStation(String id); + /** + * Retrieves the default CommandStationBean. + * + * @return The default CommandStationBean. + */ CommandStationBean getDefaultCommandStation(); + /** + * Persists a CommandStationBean. + * + * @param commandStationBean The CommandStationBean to persist. + * @return The persisted CommandStationBean. + */ CommandStationBean persist(CommandStationBean commandStationBean); + /** + * Changes the default CommandStationBean. + * + * @param newDefaultCommandStationBean The new default CommandStationBean. + * @return The new default CommandStationBean. + */ CommandStationBean changeDefaultCommandStation(CommandStationBean newDefaultCommandStationBean); + /** + * Retrieves a locomotive image. + * + * @param imageName The name of the image file. + * @return The Image, or null if not found. + */ Image getLocomotiveImage(String imageName); + /** + * Retrieves a function image. + * + * @param imageName The name of the image file. + * @return The Image, or null if not found. + */ Image getFunctionImage(String imageName); + /** + * Reads an image file. + * + * @param imageName The name of the image file. + * @param function True if the image is a function image, false otherwise. + * @return The Image, or null if not found. + */ Image readImage(String imageName, boolean function); - } diff --git a/src/main/java/jcs/ui/FeedbackSensorDialog.java b/src/main/java/jcs/ui/FeedbackSensorDialog.java index 52bc1e1f..a6b95a63 100644 --- a/src/main/java/jcs/ui/FeedbackSensorDialog.java +++ b/src/main/java/jcs/ui/FeedbackSensorDialog.java @@ -27,7 +27,7 @@ import javax.swing.UnsupportedLookAndFeelException; import javax.swing.table.DefaultTableCellRenderer; import jcs.JCS; -import jcs.ui.options.table.SensorTableModel; +import jcs.ui.settings.table.SensorTableModel; import jcs.ui.util.FrameMonitor; import jcs.util.RunUtil; import org.tinylog.Logger; diff --git a/src/main/java/jcs/ui/JCSFrame.form b/src/main/java/jcs/ui/JCSFrame.form index c6cb31d3..75009124 100755 --- a/src/main/java/jcs/ui/JCSFrame.form +++ b/src/main/java/jcs/ui/JCSFrame.form @@ -1011,7 +1011,7 @@ - + @@ -1077,7 +1077,7 @@ - + diff --git a/src/main/java/jcs/ui/JCSFrame.java b/src/main/java/jcs/ui/JCSFrame.java index 5c1ed4ca..d5973453 100755 --- a/src/main/java/jcs/ui/JCSFrame.java +++ b/src/main/java/jcs/ui/JCSFrame.java @@ -65,9 +65,11 @@ import jcs.persistence.PersistenceFactory; import jcs.ui.layout.LayoutCanvas; import jcs.ui.layout.LayoutPanel; -import jcs.ui.options.CommandStationDialog; -import jcs.ui.options.CommandStationPanel; -import jcs.ui.options.OptionDialog; +import jcs.ui.settings.AccessoryDialog; +import jcs.ui.settings.CommandStationDialog; +import jcs.ui.settings.CommandStationPanel; +import jcs.ui.settings.LocomotiveDialog; +import jcs.ui.settings.OptionDialog; import jcs.ui.util.FrameMonitor; import jcs.ui.util.UICallback; import jcs.util.RunUtil; @@ -88,6 +90,10 @@ public class JCSFrame extends JFrame implements UICallback, DisconnectionEventLi private boolean editMode = false; + private LocomotiveDialog locomotiveDialog; + private AccessoryDialog accessoryDialog; + private CommandStationDialog commandStationDialog; + /** * Creates new form JCSFrame */ @@ -202,42 +208,67 @@ public void showOverviewPanel() { overviewPanel.loadLayout(); } - public void showLocomotives() { + private void showLocomotives() { Logger.debug("Show Locomotives"); - handlePreferences(); + + if (locomotiveDialog == null) { + locomotiveDialog = new LocomotiveDialog(this, true); + locomotiveDialog.pack(); + locomotiveDialog.setLocationRelativeTo(null); + } + locomotiveDialog.setVisible(true); } - public void showTurnouts() { - CardLayout card = (CardLayout) this.centerPanel.getLayout(); - card.show(centerPanel, "turnoutsPanel"); - editMode = false; + private void showAccessories() { + if (accessoryDialog == null) { + accessoryDialog = new AccessoryDialog(this, true); + accessoryDialog.pack(); + accessoryDialog.setLocationRelativeTo(null); + } + accessoryDialog.setVisible(true); } - public void showSignals() { - CardLayout card = (CardLayout) this.centerPanel.getLayout(); - card.show(centerPanel, "signalsPanel"); - editMode = false; + private void showProperties() { + } - public void showKeyboards() { - CardLayout card = (CardLayout) this.centerPanel.getLayout(); - card.show(centerPanel, "diagnosticPanel"); - editMode = false; + private void showCommandStations() { + if (commandStationDialog == null) { + commandStationDialog = new CommandStationDialog(this, true); + commandStationDialog.pack(); + commandStationDialog.setLocationRelativeTo(null); + } + commandStationDialog.setVisible(true); } - public void showSettings() { +// private void showTurnouts() { +// CardLayout card = (CardLayout) this.centerPanel.getLayout(); +// card.show(centerPanel, "turnoutsPanel"); +// editMode = false; +// } +// private void showSignals() { +// CardLayout card = (CardLayout) this.centerPanel.getLayout(); +// card.show(centerPanel, "signalsPanel"); +// editMode = false; +// } + private void showKeyboards() { CardLayout card = (CardLayout) this.centerPanel.getLayout(); - card.show(centerPanel, "settingsPanel"); + card.show(centerPanel, "diagnosticPanel"); editMode = false; } - public void showVNCConsole() { +// private void showSettings() { +// CardLayout card = (CardLayout) this.centerPanel.getLayout(); +// card.show(centerPanel, "settingsPanel"); +// editMode = false; +// } + private void showVNCConsole() { CardLayout card = (CardLayout) this.centerPanel.getLayout(); card.show(centerPanel, "vncPanel"); editMode = false; } - public void showEditLayoutPanel() { + private void showEditLayoutPanel() { if (!AutoPilot.isAutoModeActive()) { CardLayout card = (CardLayout) centerPanel.getLayout(); card.show(centerPanel, "designPanel"); @@ -1123,9 +1154,7 @@ private void connectMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_connec }//GEN-LAST:event_connectMIActionPerformed private void showCommandStationsMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_showCommandStationsMIActionPerformed - CommandStationDialog csd = new CommandStationDialog(this, true); - csd.setLocationRelativeTo(null); - csd.setVisible(true); + showCommandStations(); }//GEN-LAST:event_showCommandStationsMIActionPerformed private void aboutMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_aboutMIActionPerformed @@ -1165,7 +1194,7 @@ private void startAllLocsBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_ }//GEN-LAST:event_startAllLocsBtnActionPerformed private void showAccessoryMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_showAccessoryMIActionPerformed - // TODO add your handling code here: + showAccessories(); }//GEN-LAST:event_showAccessoryMIActionPerformed private void showPropertiesMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_showPropertiesMIActionPerformed diff --git a/src/main/java/jcs/ui/options/PropertiesPanel.java b/src/main/java/jcs/ui/options/PropertiesPanel.java deleted file mode 100755 index f6e29773..00000000 --- a/src/main/java/jcs/ui/options/PropertiesPanel.java +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Copyright 2023 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.options; - -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.FlowLayout; -import java.awt.Insets; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import javax.swing.BorderFactory; -import javax.swing.Box; -import javax.swing.ImageIcon; -import javax.swing.JButton; -import javax.swing.JDialog; -import javax.swing.JFrame; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JTable; -import javax.swing.ListSelectionModel; -import javax.swing.UIManager; -import javax.swing.UnsupportedLookAndFeelException; -import jcs.JCS; -import jcs.entities.JCSPropertyBean; -import jcs.persistence.PersistenceFactory; -import jcs.ui.options.table.PropertiesTableModel; -import org.tinylog.Logger; - -/** - * - * @author frans - */ -public class PropertiesPanel extends JPanel { - - private final PropertiesTableModel propertiesTableModel; - - public PropertiesPanel() { - propertiesTableModel = new PropertiesTableModel(); - initComponents(); - alignPropertiesTable(); - } - - private void alignPropertiesTable() { - //this.propertiesTable.getColumnModel().getColumn(0).setPreferredWidth(50); - //DefaultTableCellRenderer centerRenderer = new DefaultTableCellRenderer(); - //centerRenderer.setHorizontalAlignment(JLabel.CENTER); - //this.propertiesTable.getColumnModel().getColumn(0).setCellRenderer(centerRenderer); - } - - /** - * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. - */ - @SuppressWarnings("deprecation") - // //GEN-BEGIN:initComponents - private void initComponents() { - - topPanel = new JPanel(); - refreshBtn = new JButton(); - newBtn = new JButton(); - centerPanel = new JPanel(); - propertiesTableScrollPane = new JScrollPane(); - propertiesTable = new JTable(); - bottomPanel = new JPanel(); - deleteBtn = new JButton(); - filler1 = new Box.Filler(new Dimension(50, 0), new Dimension(200, 0), new Dimension(150, 32767)); - saveBtn = new JButton(); - - setMinimumSize(new Dimension(1000, 600)); - setPreferredSize(new Dimension(1000, 600)); - setLayout(new BorderLayout()); - - topPanel.setMinimumSize(new Dimension(1000, 50)); - topPanel.setPreferredSize(new Dimension(1000, 50)); - topPanel.setRequestFocusEnabled(false); - FlowLayout flowLayout1 = new FlowLayout(FlowLayout.RIGHT); - flowLayout1.setAlignOnBaseline(true); - topPanel.setLayout(flowLayout1); - - refreshBtn.setIcon(new ImageIcon(getClass().getResource("/media/refresh-24.png"))); // NOI18N - refreshBtn.setText("Refresh"); - refreshBtn.setMargin(new Insets(2, 2, 2, 2)); - refreshBtn.setMaximumSize(new Dimension(120, 36)); - refreshBtn.setMinimumSize(new Dimension(120, 36)); - refreshBtn.setPreferredSize(new Dimension(120, 36)); - refreshBtn.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent evt) { - refreshBtnActionPerformed(evt); - } - }); - topPanel.add(refreshBtn); - - newBtn.setIcon(new ImageIcon(getClass().getResource("/media/add-24.png"))); // NOI18N - newBtn.setText("New"); - newBtn.setToolTipText("Create new Locomotive"); - newBtn.setMaximumSize(new Dimension(120, 36)); - newBtn.setMinimumSize(new Dimension(120, 36)); - newBtn.setPreferredSize(new Dimension(120, 36)); - newBtn.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent evt) { - newBtnActionPerformed(evt); - } - }); - topPanel.add(newBtn); - - add(topPanel, BorderLayout.NORTH); - - centerPanel.setMinimumSize(new Dimension(1000, 540)); - centerPanel.setPreferredSize(new Dimension(1000, 500)); - centerPanel.setLayout(new BorderLayout()); - - propertiesTableScrollPane.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1)); - propertiesTableScrollPane.setPreferredSize(new Dimension(500, 1000)); - - propertiesTable.setModel(propertiesTableModel); - propertiesTable.setDoubleBuffered(true); - propertiesTable.setGridColor(new Color(204, 204, 204)); - propertiesTable.setPreferredSize(new Dimension(480, 470)); - propertiesTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - propertiesTable.getTableHeader().setReorderingAllowed(false); - propertiesTable.addMouseListener(new MouseAdapter() { - public void mouseClicked(MouseEvent evt) { - propertiesTableMouseClicked(evt); - } - }); - propertiesTableScrollPane.setViewportView(propertiesTable); - - centerPanel.add(propertiesTableScrollPane, BorderLayout.PAGE_START); - - add(centerPanel, BorderLayout.CENTER); - - bottomPanel.setPreferredSize(new Dimension(1014, 50)); - bottomPanel.setRequestFocusEnabled(false); - FlowLayout flowLayout12 = new FlowLayout(FlowLayout.RIGHT); - flowLayout12.setAlignOnBaseline(true); - bottomPanel.setLayout(flowLayout12); - - deleteBtn.setIcon(new ImageIcon(getClass().getResource("/media/delete-24.png"))); // NOI18N - deleteBtn.setText("Delete"); - deleteBtn.setMaximumSize(new Dimension(100, 36)); - deleteBtn.setMinimumSize(new Dimension(100, 36)); - deleteBtn.setPreferredSize(new Dimension(100, 36)); - deleteBtn.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent evt) { - deleteBtnActionPerformed(evt); - } - }); - bottomPanel.add(deleteBtn); - bottomPanel.add(filler1); - - saveBtn.setIcon(new ImageIcon(getClass().getResource("/media/save-24.png"))); // NOI18N - saveBtn.setText("Save"); - saveBtn.setMaximumSize(new Dimension(100, 36)); - saveBtn.setMinimumSize(new Dimension(100, 36)); - saveBtn.setPreferredSize(new Dimension(100, 36)); - saveBtn.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent evt) { - saveBtnActionPerformed(evt); - } - }); - bottomPanel.add(saveBtn); - - add(bottomPanel, BorderLayout.SOUTH); - }// //GEN-END:initComponents - - - private void newBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_newBtnActionPerformed - propertiesTableModel.refresh(); - alignPropertiesTable(); - - Logger.debug("Create new JCSProperty..."); - JCSPropertyBean p = new JCSPropertyBean(); - propertiesTableModel.addRow(p); - }//GEN-LAST:event_newBtnActionPerformed - - private void propertiesTableMouseClicked(MouseEvent evt) {//GEN-FIRST:event_propertiesTableMouseClicked - JTable source = (JTable) evt.getSource(); - int row = source.rowAtPoint(evt.getPoint()); - - JCSPropertyBean p = propertiesTableModel.getControllableDeviceAt(row); - if (p != null) { - Logger.debug("Selected row: " + row + ", Property Key: " + p.getKey()); - } - }//GEN-LAST:event_propertiesTableMouseClicked - - public void refresh() { - propertiesTableModel.refresh(); - alignPropertiesTable(); - } - - private void refreshBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_refreshBtnActionPerformed - refresh(); - }//GEN-LAST:event_refreshBtnActionPerformed - - private void saveBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_saveBtnActionPerformed - int selectedRow = this.propertiesTable.getSelectedRow(); - JCSPropertyBean p = this.propertiesTableModel.getControllableDeviceAt(selectedRow); - Logger.debug("Save the Property: " + p + " ID: " + p.getKey()); - - JCSPropertyBean cp = PersistenceFactory.getService().getProperty(p.getKey()); - if (cp != null) { - //p.setId(cp.getId()); - Logger.debug("Found existing " + cp); - } - - PersistenceFactory.getService().persist(p); - - propertiesTableModel.refresh(); - alignPropertiesTable(); - }//GEN-LAST:event_saveBtnActionPerformed - - private void deleteBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_deleteBtnActionPerformed - int selectedRow = this.propertiesTable.getSelectedRow(); - JCSPropertyBean p = this.propertiesTableModel.getControllableDeviceAt(selectedRow); - if (JCS.getJcsCommandStation() != null) { - Logger.trace("Delete the Property: " + p); - PersistenceFactory.getService().remove(p); - } - propertiesTableModel.refresh(); - alignPropertiesTable(); - }//GEN-LAST:event_deleteBtnActionPerformed - - public static void main(String args[]) { - try { - UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { - Logger.warn("Can't set the LookAndFeel: " + ex); - } - java.awt.EventQueue.invokeLater(() -> { - - PropertiesPanel testPanel = new PropertiesPanel(); - JFrame testFrame = new JFrame(); - JDialog testDialog = new JDialog(testFrame, true); - - testDialog.add(testPanel); - - testDialog.addWindowListener(new java.awt.event.WindowAdapter() { - @Override - public void windowClosing(java.awt.event.WindowEvent e) { - System.exit(0); - } - }); - testDialog.pack(); - testDialog.setLocationRelativeTo(null); - - testDialog.setVisible(true); - }); - } - - - // Variables declaration - do not modify//GEN-BEGIN:variables - private JPanel bottomPanel; - private JPanel centerPanel; - private JButton deleteBtn; - private Box.Filler filler1; - private JButton newBtn; - private JTable propertiesTable; - private JScrollPane propertiesTableScrollPane; - private JButton refreshBtn; - private JButton saveBtn; - private JPanel topPanel; - // End of variables declaration//GEN-END:variables -} diff --git a/src/main/java/jcs/ui/settings/AccessoryDialog.form b/src/main/java/jcs/ui/settings/AccessoryDialog.form new file mode 100644 index 00000000..c97768cd --- /dev/null +++ b/src/main/java/jcs/ui/settings/AccessoryDialog.form @@ -0,0 +1,33 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/jcs/ui/settings/AccessoryDialog.java b/src/main/java/jcs/ui/settings/AccessoryDialog.java new file mode 100644 index 00000000..d10f786e --- /dev/null +++ b/src/main/java/jcs/ui/settings/AccessoryDialog.java @@ -0,0 +1,86 @@ +/* + * Copyright 2025 fransjacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.settings; + +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; +import org.tinylog.Logger; + +/** + * + * @author fransjacobs + */ +public class AccessoryDialog extends javax.swing.JDialog { + + private static final long serialVersionUID = 1666127249735678517L; + + /** + * Creates new form AccessoryDialog + */ + public AccessoryDialog(java.awt.Frame parent, boolean modal) { + super(parent, modal); + initComponents(); + } + + /** + * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + accessorySettingsPanel1 = new jcs.ui.settings.AccessorySettingsPanel(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + getContentPane().add(accessorySettingsPanel1, java.awt.BorderLayout.CENTER); + + pack(); + }// //GEN-END:initComponents + + /** + * @param args the command line arguments + */ + public static void main(String args[]) { + /* Set the FlatLightLaf look and feel */ + // + try { + UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { + Logger.warn("Can't set the LookAndFeel: " + ex); + } + // + + /* Create and display the dialog */ + java.awt.EventQueue.invokeLater(() -> { + AccessoryDialog dialog = new AccessoryDialog(new javax.swing.JFrame(), true); + dialog.addWindowListener(new java.awt.event.WindowAdapter() { + @Override + public void windowClosing(java.awt.event.WindowEvent e) { + System.exit(0); + } + }); + dialog.setTitle("Accessory Settings"); + dialog.pack(); + dialog.setLocationRelativeTo(null); + + dialog.setVisible(true); + }); + } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private jcs.ui.settings.AccessorySettingsPanel accessorySettingsPanel1; + // End of variables declaration//GEN-END:variables +} diff --git a/src/main/java/jcs/ui/options/AccessoryPreferencesPanel.form b/src/main/java/jcs/ui/settings/AccessorySettingsPanel.form similarity index 100% rename from src/main/java/jcs/ui/options/AccessoryPreferencesPanel.form rename to src/main/java/jcs/ui/settings/AccessorySettingsPanel.form diff --git a/src/main/java/jcs/ui/options/AccessoryPreferencesPanel.java b/src/main/java/jcs/ui/settings/AccessorySettingsPanel.java similarity index 99% rename from src/main/java/jcs/ui/options/AccessoryPreferencesPanel.java rename to src/main/java/jcs/ui/settings/AccessorySettingsPanel.java index e471fe15..f23184c4 100644 --- a/src/main/java/jcs/ui/options/AccessoryPreferencesPanel.java +++ b/src/main/java/jcs/ui/settings/AccessorySettingsPanel.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package jcs.ui.options; +package jcs.ui.settings; import java.awt.BorderLayout; import java.awt.Dimension; @@ -82,7 +82,9 @@ * * @author Frans Jacobs */ -public class AccessoryPreferencesPanel extends JPanel implements PropertyChangeListener { +public class AccessorySettingsPanel extends JPanel implements PropertyChangeListener { + + private static final long serialVersionUID = -8354030030958257426L; private final AccessoryBeanListModel accessoryListModel; //TODO: support for multiple AccessoryControllers @@ -95,7 +97,7 @@ public class AccessoryPreferencesPanel extends JPanel implements PropertyChangeL private SynchronizationTask task; - public AccessoryPreferencesPanel() { + public AccessorySettingsPanel() { accessoryListModel = new AccessoryBeanListModel(); protocolCBModel = new DefaultComboBoxModel(Protocol.values()); @@ -166,7 +168,6 @@ private void setFieldValues() { } this.statesSpinner.setValue(states); - //Integer state = selectedAccessory.getState(); if (null == selectedAccessory.getAccessoryValue()) { this.currentGreenStateLabel.setVisible(false); this.currentRedStateLabel.setVisible(false); @@ -208,7 +209,6 @@ private void setFieldValues() { selectedAccessory.setSource("Manual Inserted"); } - //String commandStationId = selectedAccessory.getCommandStationId(); boolean synch = selectedAccessory.isSynchronize(); synchronizeCB.setSelected(synch); } else { @@ -987,6 +987,8 @@ public int compare(AccessoryBean a, AccessoryBean b) { class AccessoryBeanListModel extends AbstractListModel { + private static final long serialVersionUID = 3490682684799724780L; + private final List all; private final List filtered; @@ -1216,7 +1218,7 @@ public static void main(String args[]) { } java.awt.EventQueue.invokeLater(() -> { - AccessoryPreferencesPanel testPanel = new AccessoryPreferencesPanel(); + AccessorySettingsPanel testPanel = new AccessorySettingsPanel(); JFrame testFrame = new JFrame(); JDialog testDialog = new JDialog(testFrame, true); diff --git a/src/main/java/jcs/ui/options/CommandStationDialog.form b/src/main/java/jcs/ui/settings/CommandStationDialog.form similarity index 98% rename from src/main/java/jcs/ui/options/CommandStationDialog.form rename to src/main/java/jcs/ui/settings/CommandStationDialog.form index 5db9cbf7..72767561 100644 --- a/src/main/java/jcs/ui/options/CommandStationDialog.form +++ b/src/main/java/jcs/ui/settings/CommandStationDialog.form @@ -26,7 +26,7 @@ - + @@ -132,4 +132,4 @@ - + \ No newline at end of file diff --git a/src/main/java/jcs/ui/options/CommandStationDialog.java b/src/main/java/jcs/ui/settings/CommandStationDialog.java similarity index 95% rename from src/main/java/jcs/ui/options/CommandStationDialog.java rename to src/main/java/jcs/ui/settings/CommandStationDialog.java index 9f77230b..e9aa527e 100644 --- a/src/main/java/jcs/ui/options/CommandStationDialog.java +++ b/src/main/java/jcs/ui/settings/CommandStationDialog.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package jcs.ui.options; +package jcs.ui.settings; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; @@ -40,7 +40,7 @@ public CommandStationDialog(java.awt.Frame parent, boolean modal) { // //GEN-BEGIN:initComponents private void initComponents() { - commandStationPanel1 = new jcs.ui.options.CommandStationPanel(); + commandStationPanel1 = new jcs.ui.settings.CommandStationPanel(); southPanel = new javax.swing.JPanel(); exitBtn = new javax.swing.JButton(); @@ -99,7 +99,7 @@ public void windowClosing(java.awt.event.WindowEvent e) { } // Variables declaration - do not modify//GEN-BEGIN:variables - private jcs.ui.options.CommandStationPanel commandStationPanel1; + private jcs.ui.settings.CommandStationPanel commandStationPanel1; private javax.swing.JButton exitBtn; private javax.swing.JPanel southPanel; // End of variables declaration//GEN-END:variables diff --git a/src/main/java/jcs/ui/options/CommandStationPanel.form b/src/main/java/jcs/ui/settings/CommandStationPanel.form similarity index 100% rename from src/main/java/jcs/ui/options/CommandStationPanel.form rename to src/main/java/jcs/ui/settings/CommandStationPanel.form diff --git a/src/main/java/jcs/ui/options/CommandStationPanel.java b/src/main/java/jcs/ui/settings/CommandStationPanel.java similarity index 99% rename from src/main/java/jcs/ui/options/CommandStationPanel.java rename to src/main/java/jcs/ui/settings/CommandStationPanel.java index ed397e5a..0b5ad271 100644 --- a/src/main/java/jcs/ui/options/CommandStationPanel.java +++ b/src/main/java/jcs/ui/settings/CommandStationPanel.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package jcs.ui.options; +package jcs.ui.settings; import com.fazecast.jSerialComm.SerialPort; import com.fazecast.jSerialComm.SerialPortInvalidPortException; diff --git a/src/main/java/jcs/ui/options/IconFileChooser.form b/src/main/java/jcs/ui/settings/IconFileChooser.form similarity index 100% rename from src/main/java/jcs/ui/options/IconFileChooser.form rename to src/main/java/jcs/ui/settings/IconFileChooser.form diff --git a/src/main/java/jcs/ui/options/IconFileChooser.java b/src/main/java/jcs/ui/settings/IconFileChooser.java similarity index 99% rename from src/main/java/jcs/ui/options/IconFileChooser.java rename to src/main/java/jcs/ui/settings/IconFileChooser.java index 93fecde1..e9f7c243 100644 --- a/src/main/java/jcs/ui/options/IconFileChooser.java +++ b/src/main/java/jcs/ui/settings/IconFileChooser.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package jcs.ui.options; +package jcs.ui.settings; import java.io.File; import jcs.entities.CommandStationBean; diff --git a/src/main/java/jcs/ui/settings/LocomotiveDialog.form b/src/main/java/jcs/ui/settings/LocomotiveDialog.form new file mode 100644 index 00000000..6c4307ca --- /dev/null +++ b/src/main/java/jcs/ui/settings/LocomotiveDialog.form @@ -0,0 +1,35 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/jcs/ui/settings/LocomotiveDialog.java b/src/main/java/jcs/ui/settings/LocomotiveDialog.java new file mode 100644 index 00000000..19cf1dfc --- /dev/null +++ b/src/main/java/jcs/ui/settings/LocomotiveDialog.java @@ -0,0 +1,90 @@ +/* + * Copyright 2025 fransjacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.settings; + +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; +import org.tinylog.Logger; + +/** + * + * @author fransjacobs + */ +public class LocomotiveDialog extends JDialog { + + private static final long serialVersionUID = -8749583530332472412L; + + /** + * Creates new form LocomotiveDialog + */ + public LocomotiveDialog(JFrame parent, boolean modal) { + super(parent, modal); + initComponents(); + } + + /** + * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + locomotiveSettingsPanel1 = new jcs.ui.settings.LocomotiveSettingsPanel(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + setTitle("Locomotives"); + getContentPane().add(locomotiveSettingsPanel1, java.awt.BorderLayout.CENTER); + + pack(); + }// //GEN-END:initComponents + + /** + * Only for testing + * @param args the command line arguments + */ + public static void main(String args[]) { + /* Set the FlatLightLaf look and feel */ + // + try { + UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { + Logger.warn("Can't set the LookAndFeel: " + ex); + } + // + + /* Create and display the dialog */ + java.awt.EventQueue.invokeLater(() -> { + LocomotiveDialog dialog = new LocomotiveDialog(new javax.swing.JFrame(), true); + dialog.addWindowListener(new java.awt.event.WindowAdapter() { + @Override + public void windowClosing(java.awt.event.WindowEvent e) { + System.exit(0); + } + }); + + dialog.pack(); + dialog.setLocationRelativeTo(null); + dialog.setVisible(true); + + }); + } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private jcs.ui.settings.LocomotiveSettingsPanel locomotiveSettingsPanel1; + // End of variables declaration//GEN-END:variables +} diff --git a/src/main/java/jcs/ui/options/LocomotivePreferencesPanel.form b/src/main/java/jcs/ui/settings/LocomotiveSettingsPanel.form similarity index 100% rename from src/main/java/jcs/ui/options/LocomotivePreferencesPanel.form rename to src/main/java/jcs/ui/settings/LocomotiveSettingsPanel.form diff --git a/src/main/java/jcs/ui/options/LocomotivePreferencesPanel.java b/src/main/java/jcs/ui/settings/LocomotiveSettingsPanel.java similarity index 99% rename from src/main/java/jcs/ui/options/LocomotivePreferencesPanel.java rename to src/main/java/jcs/ui/settings/LocomotiveSettingsPanel.java index 6dc449f7..f7f8c11f 100755 --- a/src/main/java/jcs/ui/options/LocomotivePreferencesPanel.java +++ b/src/main/java/jcs/ui/settings/LocomotiveSettingsPanel.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package jcs.ui.options; +package jcs.ui.settings; import java.awt.BorderLayout; import java.awt.Dimension; @@ -72,10 +72,8 @@ import javax.swing.event.ChangeListener; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; -import jcs.JCS; import jcs.commandStation.ControllerFactory; import jcs.commandStation.DecoderController; -import jcs.commandStation.events.RefreshEvent; import jcs.entities.CommandStationBean; import jcs.entities.FunctionBean; import jcs.entities.LocomotiveBean; @@ -88,7 +86,7 @@ /** * Dialog panel for importing and editing locomotive settings */ -public class LocomotivePreferencesPanel extends JPanel implements PropertyChangeListener { +public class LocomotiveSettingsPanel extends JPanel implements PropertyChangeListener { private static final long serialVersionUID = -2076222213624366106L; @@ -99,7 +97,7 @@ public class LocomotivePreferencesPanel extends JPanel implements PropertyChange private SynchronizationTask task; - public LocomotivePreferencesPanel() { + public LocomotiveSettingsPanel() { locoListModel = new LocomotiveBeanListModel(); decoderTypes = new DefaultComboBoxModel(DecoderType.values()); @@ -1176,7 +1174,7 @@ public static void main(String args[]) { } java.awt.EventQueue.invokeLater(() -> { - LocomotivePreferencesPanel testPanel = new LocomotivePreferencesPanel(); + LocomotiveSettingsPanel testPanel = new LocomotiveSettingsPanel(); JFrame testFrame = new JFrame(); JDialog testDialog = new JDialog(testFrame, true); diff --git a/src/main/java/jcs/ui/options/OptionDialog.form b/src/main/java/jcs/ui/settings/OptionDialog.form similarity index 96% rename from src/main/java/jcs/ui/options/OptionDialog.form rename to src/main/java/jcs/ui/settings/OptionDialog.form index c35baaa1..61f5ecba 100755 --- a/src/main/java/jcs/ui/options/OptionDialog.form +++ b/src/main/java/jcs/ui/settings/OptionDialog.form @@ -83,7 +83,7 @@ - + @@ -95,7 +95,7 @@ - + @@ -107,7 +107,7 @@ - + @@ -119,7 +119,7 @@ - + diff --git a/src/main/java/jcs/ui/options/OptionDialog.java b/src/main/java/jcs/ui/settings/OptionDialog.java similarity index 92% rename from src/main/java/jcs/ui/options/OptionDialog.java rename to src/main/java/jcs/ui/settings/OptionDialog.java index 4970d092..70c86333 100755 --- a/src/main/java/jcs/ui/options/OptionDialog.java +++ b/src/main/java/jcs/ui/settings/OptionDialog.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package jcs.ui.options; +package jcs.ui.settings; import java.awt.BorderLayout; import java.awt.Component; @@ -67,9 +67,9 @@ private void initComponents() { centerPanel = new JPanel(); prefsTP = new JTabbedPane(); commandStationPanel = new CommandStationPanel(); - locomotivePanel = new LocomotivePreferencesPanel(); - accessoryPreferencesPanel = new AccessoryPreferencesPanel(); - propertiesPanel = new PropertiesPanel(); + locomotivePanel = new LocomotiveSettingsPanel(); + accessoryPreferencesPanel = new AccessorySettingsPanel(); + propertiesPanel = new PropertySettingsPanel(); southPanel = new JPanel(); closeBtn = new JButton(); @@ -143,11 +143,11 @@ private void closeBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_closeBt private void prefsTPStateChanged(ChangeEvent evt) {//GEN-FIRST:event_prefsTPStateChanged Component c = this.prefsTP.getSelectedComponent(); - if (c instanceof LocomotivePreferencesPanel) { + if (c instanceof LocomotiveSettingsPanel) { //this.locomotivePanel.refresh(); - } else if (c instanceof AccessoryPreferencesPanel) { + } else if (c instanceof AccessorySettingsPanel) { //this.turnoutPanel.refresh(); - } else if (c instanceof PropertiesPanel) { + } else if (c instanceof PropertySettingsPanel) { //this.propertiesPanel.refresh(); } @@ -178,13 +178,13 @@ public void windowClosing(java.awt.event.WindowEvent e) { // Variables declaration - do not modify//GEN-BEGIN:variables - private AccessoryPreferencesPanel accessoryPreferencesPanel; + private AccessorySettingsPanel accessoryPreferencesPanel; private JPanel centerPanel; private JButton closeBtn; private CommandStationPanel commandStationPanel; - private LocomotivePreferencesPanel locomotivePanel; + private LocomotiveSettingsPanel locomotivePanel; private JTabbedPane prefsTP; - private PropertiesPanel propertiesPanel; + private PropertySettingsPanel propertiesPanel; private JPanel southPanel; private JPanel topPanel; // End of variables declaration//GEN-END:variables diff --git a/src/main/java/jcs/ui/settings/PropertiesDialog.form b/src/main/java/jcs/ui/settings/PropertiesDialog.form new file mode 100644 index 00000000..98c862c1 --- /dev/null +++ b/src/main/java/jcs/ui/settings/PropertiesDialog.form @@ -0,0 +1,33 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/jcs/ui/settings/PropertiesDialog.java b/src/main/java/jcs/ui/settings/PropertiesDialog.java new file mode 100644 index 00000000..4dd088a5 --- /dev/null +++ b/src/main/java/jcs/ui/settings/PropertiesDialog.java @@ -0,0 +1,86 @@ +/* + * Copyright 2025 fransjacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.settings; + +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; +import org.tinylog.Logger; + +/** + * + * @author fransjacobs + */ +public class PropertiesDialog extends javax.swing.JDialog { + + private static final long serialVersionUID = 4193772390514185927L; + + /** + * Creates new form PropertiesDialog + */ + public PropertiesDialog(java.awt.Frame parent, boolean modal) { + super(parent, modal); + initComponents(); + } + + /** + * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + propertySettingsPanel1 = new jcs.ui.settings.PropertySettingsPanel(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + getContentPane().add(propertySettingsPanel1, java.awt.BorderLayout.CENTER); + + pack(); + }// //GEN-END:initComponents + + /** + * @param args the command line arguments + */ + public static void main(String args[]) { + /* Set the FlatLightLaf look and feel */ + // + try { + UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { + Logger.warn("Can't set the LookAndFeel: " + ex); + } + // + + /* Create and display the dialog */ + java.awt.EventQueue.invokeLater(() -> { + PropertiesDialog dialog = new PropertiesDialog(new javax.swing.JFrame(), true); + dialog.addWindowListener(new java.awt.event.WindowAdapter() { + @Override + public void windowClosing(java.awt.event.WindowEvent e) { + System.exit(0); + } + }); + dialog.setTitle("Property Settings"); + dialog.pack(); + dialog.setLocationRelativeTo(null); + + dialog.setVisible(true); + }); + } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private jcs.ui.settings.PropertySettingsPanel propertySettingsPanel1; + // End of variables declaration//GEN-END:variables +} diff --git a/src/main/java/jcs/ui/options/PropertiesPanel.form b/src/main/java/jcs/ui/settings/PropertySettingsPanel.form similarity index 100% rename from src/main/java/jcs/ui/options/PropertiesPanel.form rename to src/main/java/jcs/ui/settings/PropertySettingsPanel.form diff --git a/src/main/java/jcs/ui/settings/PropertySettingsPanel.java b/src/main/java/jcs/ui/settings/PropertySettingsPanel.java new file mode 100755 index 00000000..1e10efd2 --- /dev/null +++ b/src/main/java/jcs/ui/settings/PropertySettingsPanel.java @@ -0,0 +1,280 @@ +/* + * Copyright 2023 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.settings; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.ListSelectionModel; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; +import jcs.JCS; +import jcs.entities.JCSPropertyBean; +import jcs.persistence.PersistenceFactory; +import jcs.ui.settings.table.PropertiesTableModel; +import org.tinylog.Logger; + +/** + * + * @author frans + */ +public class PropertySettingsPanel extends JPanel { + + private static final long serialVersionUID = 4081697818771057621L; + + private final PropertiesTableModel propertiesTableModel; + + public PropertySettingsPanel() { + propertiesTableModel = new PropertiesTableModel(); + initComponents(); + alignPropertiesTable(); + } + + private void alignPropertiesTable() { + //this.propertiesTable.getColumnModel().getColumn(0).setPreferredWidth(50); + //DefaultTableCellRenderer centerRenderer = new DefaultTableCellRenderer(); + //centerRenderer.setHorizontalAlignment(JLabel.CENTER); + //this.propertiesTable.getColumnModel().getColumn(0).setCellRenderer(centerRenderer); + } + + /** + * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. + */ + @SuppressWarnings("deprecation") + // //GEN-BEGIN:initComponents + private void initComponents() { + + topPanel = new JPanel(); + refreshBtn = new JButton(); + newBtn = new JButton(); + centerPanel = new JPanel(); + propertiesTableScrollPane = new JScrollPane(); + propertiesTable = new JTable(); + bottomPanel = new JPanel(); + deleteBtn = new JButton(); + filler1 = new Box.Filler(new Dimension(50, 0), new Dimension(200, 0), new Dimension(150, 32767)); + saveBtn = new JButton(); + + setMinimumSize(new Dimension(1000, 600)); + setPreferredSize(new Dimension(1000, 600)); + setLayout(new BorderLayout()); + + topPanel.setMinimumSize(new Dimension(1000, 50)); + topPanel.setPreferredSize(new Dimension(1000, 50)); + topPanel.setRequestFocusEnabled(false); + FlowLayout flowLayout1 = new FlowLayout(FlowLayout.RIGHT); + flowLayout1.setAlignOnBaseline(true); + topPanel.setLayout(flowLayout1); + + refreshBtn.setIcon(new ImageIcon(getClass().getResource("/media/refresh-24.png"))); // NOI18N + refreshBtn.setText("Refresh"); + refreshBtn.setMargin(new Insets(2, 2, 2, 2)); + refreshBtn.setMaximumSize(new Dimension(120, 36)); + refreshBtn.setMinimumSize(new Dimension(120, 36)); + refreshBtn.setPreferredSize(new Dimension(120, 36)); + refreshBtn.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + refreshBtnActionPerformed(evt); + } + }); + topPanel.add(refreshBtn); + + newBtn.setIcon(new ImageIcon(getClass().getResource("/media/add-24.png"))); // NOI18N + newBtn.setText("New"); + newBtn.setToolTipText("Create new Locomotive"); + newBtn.setMaximumSize(new Dimension(120, 36)); + newBtn.setMinimumSize(new Dimension(120, 36)); + newBtn.setPreferredSize(new Dimension(120, 36)); + newBtn.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + newBtnActionPerformed(evt); + } + }); + topPanel.add(newBtn); + + add(topPanel, BorderLayout.NORTH); + + centerPanel.setMinimumSize(new Dimension(1000, 540)); + centerPanel.setPreferredSize(new Dimension(1000, 500)); + centerPanel.setLayout(new BorderLayout()); + + propertiesTableScrollPane.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1)); + propertiesTableScrollPane.setPreferredSize(new Dimension(500, 1000)); + + propertiesTable.setModel(propertiesTableModel); + propertiesTable.setDoubleBuffered(true); + propertiesTable.setGridColor(new Color(204, 204, 204)); + propertiesTable.setPreferredSize(new Dimension(480, 470)); + propertiesTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + propertiesTable.getTableHeader().setReorderingAllowed(false); + propertiesTable.addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent evt) { + propertiesTableMouseClicked(evt); + } + }); + propertiesTableScrollPane.setViewportView(propertiesTable); + + centerPanel.add(propertiesTableScrollPane, BorderLayout.PAGE_START); + + add(centerPanel, BorderLayout.CENTER); + + bottomPanel.setPreferredSize(new Dimension(1014, 50)); + bottomPanel.setRequestFocusEnabled(false); + FlowLayout flowLayout12 = new FlowLayout(FlowLayout.RIGHT); + flowLayout12.setAlignOnBaseline(true); + bottomPanel.setLayout(flowLayout12); + + deleteBtn.setIcon(new ImageIcon(getClass().getResource("/media/delete-24.png"))); // NOI18N + deleteBtn.setText("Delete"); + deleteBtn.setMaximumSize(new Dimension(100, 36)); + deleteBtn.setMinimumSize(new Dimension(100, 36)); + deleteBtn.setPreferredSize(new Dimension(100, 36)); + deleteBtn.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + deleteBtnActionPerformed(evt); + } + }); + bottomPanel.add(deleteBtn); + bottomPanel.add(filler1); + + saveBtn.setIcon(new ImageIcon(getClass().getResource("/media/save-24.png"))); // NOI18N + saveBtn.setText("Save"); + saveBtn.setMaximumSize(new Dimension(100, 36)); + saveBtn.setMinimumSize(new Dimension(100, 36)); + saveBtn.setPreferredSize(new Dimension(100, 36)); + saveBtn.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + saveBtnActionPerformed(evt); + } + }); + bottomPanel.add(saveBtn); + + add(bottomPanel, BorderLayout.SOUTH); + }// //GEN-END:initComponents + + + private void newBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_newBtnActionPerformed + propertiesTableModel.refresh(); + alignPropertiesTable(); + + Logger.debug("Create new JCSProperty..."); + JCSPropertyBean p = new JCSPropertyBean(); + propertiesTableModel.addRow(p); + }//GEN-LAST:event_newBtnActionPerformed + + private void propertiesTableMouseClicked(MouseEvent evt) {//GEN-FIRST:event_propertiesTableMouseClicked + JTable source = (JTable) evt.getSource(); + int row = source.rowAtPoint(evt.getPoint()); + + JCSPropertyBean p = propertiesTableModel.getControllableDeviceAt(row); + if (p != null) { + Logger.debug("Selected row: " + row + ", Property Key: " + p.getKey()); + } + }//GEN-LAST:event_propertiesTableMouseClicked + + public void refresh() { + propertiesTableModel.refresh(); + alignPropertiesTable(); + } + + private void refreshBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_refreshBtnActionPerformed + refresh(); + }//GEN-LAST:event_refreshBtnActionPerformed + + private void saveBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_saveBtnActionPerformed + int selectedRow = this.propertiesTable.getSelectedRow(); + JCSPropertyBean p = this.propertiesTableModel.getControllableDeviceAt(selectedRow); + Logger.debug("Save the Property: " + p + " ID: " + p.getKey()); + + JCSPropertyBean cp = PersistenceFactory.getService().getProperty(p.getKey()); + if (cp != null) { + //p.setId(cp.getId()); + Logger.debug("Found existing " + cp); + } + + PersistenceFactory.getService().persist(p); + + propertiesTableModel.refresh(); + alignPropertiesTable(); + }//GEN-LAST:event_saveBtnActionPerformed + + private void deleteBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_deleteBtnActionPerformed + int selectedRow = this.propertiesTable.getSelectedRow(); + JCSPropertyBean p = this.propertiesTableModel.getControllableDeviceAt(selectedRow); + if (JCS.getJcsCommandStation() != null) { + Logger.trace("Delete the Property: " + p); + PersistenceFactory.getService().remove(p); + } + propertiesTableModel.refresh(); + alignPropertiesTable(); + }//GEN-LAST:event_deleteBtnActionPerformed + + public static void main(String args[]) { + try { + UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { + Logger.warn("Can't set the LookAndFeel: " + ex); + } + java.awt.EventQueue.invokeLater(() -> { + + PropertySettingsPanel testPanel = new PropertySettingsPanel(); + JFrame testFrame = new JFrame(); + JDialog testDialog = new JDialog(testFrame, true); + + testDialog.add(testPanel); + + testDialog.addWindowListener(new java.awt.event.WindowAdapter() { + @Override + public void windowClosing(java.awt.event.WindowEvent e) { + System.exit(0); + } + }); + testDialog.pack(); + testDialog.setLocationRelativeTo(null); + + testDialog.setVisible(true); + }); + } + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private JPanel bottomPanel; + private JPanel centerPanel; + private JButton deleteBtn; + private Box.Filler filler1; + private JButton newBtn; + private JTable propertiesTable; + private JScrollPane propertiesTableScrollPane; + private JButton refreshBtn; + private JButton saveBtn; + private JPanel topPanel; + // End of variables declaration//GEN-END:variables +} diff --git a/src/main/java/jcs/ui/options/table/BeanTableModel.java b/src/main/java/jcs/ui/settings/table/BeanTableModel.java similarity index 99% rename from src/main/java/jcs/ui/options/table/BeanTableModel.java rename to src/main/java/jcs/ui/settings/table/BeanTableModel.java index cfd6e239..2c6ea6d3 100755 --- a/src/main/java/jcs/ui/options/table/BeanTableModel.java +++ b/src/main/java/jcs/ui/settings/table/BeanTableModel.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package jcs.ui.options.table; +package jcs.ui.settings.table; import java.io.Serializable; import java.util.List; diff --git a/src/main/java/jcs/ui/options/table/ButtonColumn.java b/src/main/java/jcs/ui/settings/table/ButtonColumn.java similarity index 99% rename from src/main/java/jcs/ui/options/table/ButtonColumn.java rename to src/main/java/jcs/ui/settings/table/ButtonColumn.java index bc8e3840..69388c80 100755 --- a/src/main/java/jcs/ui/options/table/ButtonColumn.java +++ b/src/main/java/jcs/ui/settings/table/ButtonColumn.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package jcs.ui.options.table; +package jcs.ui.settings.table; import java.awt.Color; import java.awt.Component; diff --git a/src/main/java/jcs/ui/options/table/ControllerInfoTableModel.java b/src/main/java/jcs/ui/settings/table/ControllerInfoTableModel.java similarity index 99% rename from src/main/java/jcs/ui/options/table/ControllerInfoTableModel.java rename to src/main/java/jcs/ui/settings/table/ControllerInfoTableModel.java index 2630e314..06527fe0 100644 --- a/src/main/java/jcs/ui/options/table/ControllerInfoTableModel.java +++ b/src/main/java/jcs/ui/settings/table/ControllerInfoTableModel.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package jcs.ui.options.table; +package jcs.ui.settings.table; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/jcs/ui/options/table/PropertiesTableModel.java b/src/main/java/jcs/ui/settings/table/PropertiesTableModel.java similarity index 98% rename from src/main/java/jcs/ui/options/table/PropertiesTableModel.java rename to src/main/java/jcs/ui/settings/table/PropertiesTableModel.java index a0342bc4..91f26de4 100755 --- a/src/main/java/jcs/ui/options/table/PropertiesTableModel.java +++ b/src/main/java/jcs/ui/settings/table/PropertiesTableModel.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package jcs.ui.options.table; +package jcs.ui.settings.table; import java.util.ArrayList; import java.util.Collections; diff --git a/src/main/java/jcs/ui/options/table/SensorTableModel.java b/src/main/java/jcs/ui/settings/table/SensorTableModel.java similarity index 99% rename from src/main/java/jcs/ui/options/table/SensorTableModel.java rename to src/main/java/jcs/ui/settings/table/SensorTableModel.java index af7aca97..6c40b982 100644 --- a/src/main/java/jcs/ui/options/table/SensorTableModel.java +++ b/src/main/java/jcs/ui/settings/table/SensorTableModel.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package jcs.ui.options.table; +package jcs.ui.settings.table; import java.math.BigDecimal; import java.util.ArrayList; diff --git a/src/main/java/jcs/ui/options/table/SignalTableModel.java b/src/main/java/jcs/ui/settings/table/SignalTableModel.java similarity index 98% rename from src/main/java/jcs/ui/options/table/SignalTableModel.java rename to src/main/java/jcs/ui/settings/table/SignalTableModel.java index edbc6f59..1b3d8c5d 100755 --- a/src/main/java/jcs/ui/options/table/SignalTableModel.java +++ b/src/main/java/jcs/ui/settings/table/SignalTableModel.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package jcs.ui.options.table; +package jcs.ui.settings.table; import java.math.BigDecimal; import java.util.ArrayList; diff --git a/src/main/java/jcs/ui/options/table/TurnoutTableModel.java b/src/main/java/jcs/ui/settings/table/TurnoutTableModel.java similarity index 98% rename from src/main/java/jcs/ui/options/table/TurnoutTableModel.java rename to src/main/java/jcs/ui/settings/table/TurnoutTableModel.java index 7ebc3f6c..2959c6c6 100755 --- a/src/main/java/jcs/ui/options/table/TurnoutTableModel.java +++ b/src/main/java/jcs/ui/settings/table/TurnoutTableModel.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package jcs.ui.options.table; +package jcs.ui.settings.table; import java.math.BigDecimal; import java.util.ArrayList; From bb941ae551b42d66eaf5a61d384488449907c8ff Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Thu, 3 Apr 2025 21:00:39 +0200 Subject: [PATCH 40/70] Made the Menu and UI more consistent --- src/main/java/jcs/ui/JCSFrame.form | 9 -- src/main/java/jcs/ui/JCSFrame.java | 71 ++++++-------- src/main/java/jcs/ui/layout/LayoutPanel.java | 26 +++--- .../ui/settings/AccessorySettingsPanel.java | 31 ------- .../jcs/ui/settings/CommandStationPanel.java | 33 ------- .../ui/settings/LocomotiveSettingsPanel.java | 33 ------- .../jcs/ui/settings/PropertiesDialog.form | 4 +- .../jcs/ui/settings/PropertiesDialog.java | 8 +- .../ui/settings/PropertySettingsPanel.java | 31 ------- ...{OptionDialog.form => SettingsDialog.form} | 92 ++++--------------- ...{OptionDialog.java => SettingsDialog.java} | 91 ++++++------------ 11 files changed, 94 insertions(+), 335 deletions(-) rename src/main/java/jcs/ui/settings/{OptionDialog.form => SettingsDialog.form} (67%) rename src/main/java/jcs/ui/settings/{OptionDialog.java => SettingsDialog.java} (64%) diff --git a/src/main/java/jcs/ui/JCSFrame.form b/src/main/java/jcs/ui/JCSFrame.form index 75009124..6e3c4cc8 100755 --- a/src/main/java/jcs/ui/JCSFrame.form +++ b/src/main/java/jcs/ui/JCSFrame.form @@ -239,15 +239,6 @@ - - - - - - - - -
diff --git a/src/main/java/jcs/ui/JCSFrame.java b/src/main/java/jcs/ui/JCSFrame.java index d5973453..de16fc71 100755 --- a/src/main/java/jcs/ui/JCSFrame.java +++ b/src/main/java/jcs/ui/JCSFrame.java @@ -69,7 +69,8 @@ import jcs.ui.settings.CommandStationDialog; import jcs.ui.settings.CommandStationPanel; import jcs.ui.settings.LocomotiveDialog; -import jcs.ui.settings.OptionDialog; +import jcs.ui.settings.SettingsDialog; +import jcs.ui.settings.PropertiesDialog; import jcs.ui.util.FrameMonitor; import jcs.ui.util.UICallback; import jcs.util.RunUtil; @@ -93,6 +94,9 @@ public class JCSFrame extends JFrame implements UICallback, DisconnectionEventLi private LocomotiveDialog locomotiveDialog; private AccessoryDialog accessoryDialog; private CommandStationDialog commandStationDialog; + private PropertiesDialog propertiesDialog; + + private SettingsDialog settingsDialog; /** * Creates new form JCSFrame @@ -229,7 +233,12 @@ private void showAccessories() { } private void showProperties() { - + if (propertiesDialog == null) { + propertiesDialog = new PropertiesDialog(this, true); + propertiesDialog.pack(); + propertiesDialog.setLocationRelativeTo(null); + } + propertiesDialog.setVisible(true); } private void showCommandStations() { @@ -241,27 +250,18 @@ private void showCommandStations() { commandStationDialog.setVisible(true); } -// private void showTurnouts() { -// CardLayout card = (CardLayout) this.centerPanel.getLayout(); -// card.show(centerPanel, "turnoutsPanel"); -// editMode = false; -// } -// private void showSignals() { -// CardLayout card = (CardLayout) this.centerPanel.getLayout(); -// card.show(centerPanel, "signalsPanel"); -// editMode = false; -// } + private void showRoutes() { + if (editMode) { + layoutPanel.showRoutes(); + } + } + private void showKeyboards() { CardLayout card = (CardLayout) this.centerPanel.getLayout(); card.show(centerPanel, "diagnosticPanel"); editMode = false; } -// private void showSettings() { -// CardLayout card = (CardLayout) this.centerPanel.getLayout(); -// card.show(centerPanel, "settingsPanel"); -// editMode = false; -// } private void showVNCConsole() { CardLayout card = (CardLayout) this.centerPanel.getLayout(); card.show(centerPanel, "vncPanel"); @@ -386,7 +386,6 @@ private void initComponents() { showAccessoryMI = new JMenuItem(); showCommandStationsMI = new JMenuItem(); showPropertiesMI = new JMenuItem(); - optionsMI = new JMenuItem(); helpMenu = new JMenu(); aboutMI = new JMenuItem(); @@ -994,15 +993,6 @@ public void actionPerformed(ActionEvent evt) { }); settingsMenu.add(showPropertiesMI); - optionsMI.setText("Options"); - optionsMI.setName("optionsMI"); // NOI18N - optionsMI.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent evt) { - optionsMIActionPerformed(evt); - } - }); - settingsMenu.add(optionsMI); - jcsMenuBar.add(settingsMenu); helpMenu.setText("Help"); @@ -1041,10 +1031,6 @@ private void formWindowClosing(WindowEvent evt) {//GEN-FIRST:event_formWindowClo QuitApp(); }//GEN-LAST:event_formWindowClosing - private void optionsMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_optionsMIActionPerformed - handlePreferences(); - }//GEN-LAST:event_optionsMIActionPerformed - private void showEditDesignBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_showEditDesignBtnActionPerformed showEditLayoutPanel(); }//GEN-LAST:event_showEditDesignBtnActionPerformed @@ -1198,7 +1184,7 @@ private void showAccessoryMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_ }//GEN-LAST:event_showAccessoryMIActionPerformed private void showPropertiesMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_showPropertiesMIActionPerformed - // TODO add your handling code here: + showProperties(); }//GEN-LAST:event_showPropertiesMIActionPerformed private void rotateTileMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_rotateTileMIActionPerformed @@ -1249,7 +1235,7 @@ private void startAllLocsMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_s }//GEN-LAST:event_startAllLocsMIActionPerformed private void showRoutesMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_showRoutesMIActionPerformed - // TODO add your handling code here: + showRoutes(); }//GEN-LAST:event_showRoutesMIActionPerformed private void startAllLocomotives() { @@ -1301,17 +1287,17 @@ public void handleAbout() { dialog.setVisible(true); } + /** + * MacOs Settings, Show a Tabbed Dialog where each tab is one of the setting Dialog + */ @Override public void handlePreferences() { - Logger.trace("handlePreferences"); - - OptionDialog preferencesDialog = new OptionDialog(this, false); - preferencesDialog.setVisible(true); - - Logger.debug("refresh data..."); - //this.diagnosticPanel.refreshPanel(); - //this.overviewPanel.refreshPanel(); - + if (settingsDialog == null) { + settingsDialog = new SettingsDialog(this, true); + settingsDialog.pack(); + settingsDialog.setLocationRelativeTo(null); + } + settingsDialog.setVisible(true); } public void powerChanged(PowerEvent event) { @@ -1365,7 +1351,6 @@ public void powerChanged(PowerEvent event) { private JPanel leftPanel; private JSplitPane locoDisplaySP; private JPanel mainPanel; - private JMenuItem optionsMI; private LayoutPanel overviewPanel; private JToggleButton powerButton; private JMenuItem quitMI; diff --git a/src/main/java/jcs/ui/layout/LayoutPanel.java b/src/main/java/jcs/ui/layout/LayoutPanel.java index f1258ff8..46c58f4a 100755 --- a/src/main/java/jcs/ui/layout/LayoutPanel.java +++ b/src/main/java/jcs/ui/layout/LayoutPanel.java @@ -44,17 +44,12 @@ import org.tinylog.Logger; /** - * The `LayoutPanel` class is a custom `JPanel` used to visually represent and manipulate a layout. - * It provides a graphical canvas (`LayoutCanvas`) for drawing and editing elements,
- * along with a toolbar offering various tools for adding, deleting, manipulating, and loading/saving layouts. - * The panel can operate in read-only mode, disabling editing functionalities. - * + * The `LayoutPanel` class is a custom `JPanel` used to visually represent and manipulate a layout. It provides a graphical canvas (`LayoutCanvas`) for drawing and editing elements,
+ * along with a toolbar offering various tools for adding, deleting, manipulating, and loading/saving layouts. The panel can operate in read-only mode, disabling editing functionalities. + * * It uses a tile-based system to represent tracks and other elements, allowing for easy manipulation and modification of the layout.
- * The class handles events related to adding, deleting, rotating, - * and flipping tiles, as well as loading and saving layout configurations.
- * It supports different tile types (straight tracks, curved tracks, blocks, sensors, signals, switches, and crossings), each - * with different properties and behaviors. - * external resource (e.g., a + * The class handles events related to adding, deleting, rotating, and flipping tiles, as well as loading and saving layout configurations.
+ * It supports different tile types (straight tracks, curved tracks, blocks, sensors, signals, switches, and crossings), each with different properties and behaviors. external resource (e.g., a * database or configuration file) to load and save layout data. It also incorporates an undo/redo mechanism for easy recovery from mistakes.It provides options for showing/hiding the grid and offers * different modes of operation (adding, deleting, selecting, moving). * @@ -174,7 +169,7 @@ public void flipSelectedTileHorizontal() { public void flipSelectedTileVerical() { canvas.flipSelectedTileVertical(); } - + public void deleteSelectedTile() { canvas.deleteSelectedTile(); } @@ -870,8 +865,7 @@ private void crossRBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_crossR }//GEN-LAST:event_crossRBtnActionPerformed private void routeBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_routeBtnActionPerformed - Logger.debug("Start Routing..."); - this.canvas.showRoutesDialog(); + showRoutes(); }//GEN-LAST:event_routeBtnActionPerformed private void formComponentHidden(ComponentEvent evt) {//GEN-FIRST:event_formComponentHidden @@ -916,7 +910,7 @@ private void autoPilotBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_aut private void startAllLocomotivesBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_startAllLocomotivesBtnActionPerformed Logger.trace(evt.getActionCommand() + " Start All Locomotives " + this.startAllLocomotivesBtn.isSelected()); - if (this.startAllLocomotivesBtn.isSelected()) { + if (startAllLocomotivesBtn.isSelected()) { AutoPilot.startAllLocomotives(); } }//GEN-LAST:event_startAllLocomotivesBtnActionPerformed @@ -937,6 +931,10 @@ private void setDirection(Direction direction) { canvas.setDirection(direction); } + public void showRoutes() { + canvas.showRoutesDialog(); + } + public void setMode(LayoutCanvas.Mode mode) { switch (mode) { case SELECT -> { diff --git a/src/main/java/jcs/ui/settings/AccessorySettingsPanel.java b/src/main/java/jcs/ui/settings/AccessorySettingsPanel.java index f23184c4..3f14e8ee 100644 --- a/src/main/java/jcs/ui/settings/AccessorySettingsPanel.java +++ b/src/main/java/jcs/ui/settings/AccessorySettingsPanel.java @@ -46,7 +46,6 @@ import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; -import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JList; @@ -60,8 +59,6 @@ import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; -import javax.swing.UIManager; -import javax.swing.UnsupportedLookAndFeelException; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.ListSelectionEvent; @@ -1209,34 +1206,6 @@ public void done() { } } - //Testing - public static void main(String args[]) { - try { - UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { - Logger.error("Can't set the LookAndFeel: " + ex); - } - java.awt.EventQueue.invokeLater(() -> { - - AccessorySettingsPanel testPanel = new AccessorySettingsPanel(); - JFrame testFrame = new JFrame(); - JDialog testDialog = new JDialog(testFrame, true); - - testDialog.add(testPanel); - - testDialog.addWindowListener(new java.awt.event.WindowAdapter() { - @Override - public void windowClosing(java.awt.event.WindowEvent e) { - System.exit(0); - } - }); - testDialog.pack(); - testDialog.setLocationRelativeTo(null); - - testDialog.setVisible(true); - }); - } - // Variables declaration - do not modify//GEN-BEGIN:variables JScrollPane accessoriesSP; JList accessoryList; diff --git a/src/main/java/jcs/ui/settings/CommandStationPanel.java b/src/main/java/jcs/ui/settings/CommandStationPanel.java index 0b5ad271..4f07ae34 100644 --- a/src/main/java/jcs/ui/settings/CommandStationPanel.java +++ b/src/main/java/jcs/ui/settings/CommandStationPanel.java @@ -38,8 +38,6 @@ import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; -import javax.swing.JDialog; -import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JProgressBar; @@ -49,8 +47,6 @@ import javax.swing.SpinnerNumberModel; import javax.swing.SwingConstants; import javax.swing.SwingWorker; -import javax.swing.UIManager; -import javax.swing.UnsupportedLookAndFeelException; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import jcs.JCS; @@ -1581,35 +1577,6 @@ private DecoderController createCommandStation(CommandStationBean commandStation return ControllerFactory.getDecoderController(commandStationBean, false); } - public static void main(String args[]) { - try { - UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { - Logger.warn("Can't set the LookAndFeel: " + ex); - } - java.awt.EventQueue.invokeLater(() -> { - - CommandStationPanel testPanel = new CommandStationPanel(); - JFrame testFrame = new JFrame(); - JDialog testDialog = new JDialog(testFrame, true); - - testDialog.add(testPanel); - - testDialog.addWindowListener(new java.awt.event.WindowAdapter() { - @Override - public void windowClosing(java.awt.event.WindowEvent e) { - System.exit(0); - } - }); - - testDialog.pack(); - testDialog.setLocationRelativeTo(null); - - testDialog.setVisible(true); - }); - } - - // Variables declaration - do not modify//GEN-BEGIN:variables JPanel FeedbackPropertiesPanel; JCheckBox accessorySupportCB; diff --git a/src/main/java/jcs/ui/settings/LocomotiveSettingsPanel.java b/src/main/java/jcs/ui/settings/LocomotiveSettingsPanel.java index f7f8c11f..fccb6019 100755 --- a/src/main/java/jcs/ui/settings/LocomotiveSettingsPanel.java +++ b/src/main/java/jcs/ui/settings/LocomotiveSettingsPanel.java @@ -53,7 +53,6 @@ import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; -import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JList; @@ -66,8 +65,6 @@ import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; -import javax.swing.UIManager; -import javax.swing.UnsupportedLookAndFeelException; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.ListSelectionEvent; @@ -728,7 +725,6 @@ private void saveBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_saveBtnA locomotiveList.setSelectedValue(selectedLocomotive, true); //JCS.settingsChanged(new RefreshEvent("locomotives")); - } }//GEN-LAST:event_saveBtnActionPerformed @@ -1151,7 +1147,6 @@ public Void doInBackground() { } //JCS.settingsChanged(new RefreshEvent("locomotives")); - firePropertyChange("done", "", "Locomotives Synchronized"); return null; @@ -1165,34 +1160,6 @@ public void done() { } } - //Testing - public static void main(String args[]) { - try { - UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { - Logger.error("Can't set the LookAndFeel: " + ex); - } - java.awt.EventQueue.invokeLater(() -> { - - LocomotiveSettingsPanel testPanel = new LocomotiveSettingsPanel(); - JFrame testFrame = new JFrame(); - JDialog testDialog = new JDialog(testFrame, true); - - testDialog.add(testPanel); - - testDialog.addWindowListener(new java.awt.event.WindowAdapter() { - @Override - public void windowClosing(java.awt.event.WindowEvent e) { - System.exit(0); - } - }); - testDialog.pack(); - testDialog.setLocationRelativeTo(null); - - testDialog.setVisible(true); - }); - } - // Variables declaration - do not modify//GEN-BEGIN:variables JLabel addressLbl; JSpinner addressSpinner; diff --git a/src/main/java/jcs/ui/settings/PropertiesDialog.form b/src/main/java/jcs/ui/settings/PropertiesDialog.form index 98c862c1..223f99ee 100644 --- a/src/main/java/jcs/ui/settings/PropertiesDialog.form +++ b/src/main/java/jcs/ui/settings/PropertiesDialog.form @@ -3,6 +3,7 @@
+ @@ -18,11 +19,12 @@ + - + diff --git a/src/main/java/jcs/ui/settings/PropertiesDialog.java b/src/main/java/jcs/ui/settings/PropertiesDialog.java index 4dd088a5..0f0d7bc5 100644 --- a/src/main/java/jcs/ui/settings/PropertiesDialog.java +++ b/src/main/java/jcs/ui/settings/PropertiesDialog.java @@ -42,10 +42,11 @@ public PropertiesDialog(java.awt.Frame parent, boolean modal) { // //GEN-BEGIN:initComponents private void initComponents() { - propertySettingsPanel1 = new jcs.ui.settings.PropertySettingsPanel(); + propertySettingsPanel = new jcs.ui.settings.PropertySettingsPanel(); setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); - getContentPane().add(propertySettingsPanel1, java.awt.BorderLayout.CENTER); + setTitle("Properties"); + getContentPane().add(propertySettingsPanel, java.awt.BorderLayout.CENTER); pack(); }// //GEN-END:initComponents @@ -72,7 +73,6 @@ public void windowClosing(java.awt.event.WindowEvent e) { System.exit(0); } }); - dialog.setTitle("Property Settings"); dialog.pack(); dialog.setLocationRelativeTo(null); @@ -81,6 +81,6 @@ public void windowClosing(java.awt.event.WindowEvent e) { } // Variables declaration - do not modify//GEN-BEGIN:variables - private jcs.ui.settings.PropertySettingsPanel propertySettingsPanel1; + private jcs.ui.settings.PropertySettingsPanel propertySettingsPanel; // End of variables declaration//GEN-END:variables } diff --git a/src/main/java/jcs/ui/settings/PropertySettingsPanel.java b/src/main/java/jcs/ui/settings/PropertySettingsPanel.java index 1e10efd2..6d58db16 100755 --- a/src/main/java/jcs/ui/settings/PropertySettingsPanel.java +++ b/src/main/java/jcs/ui/settings/PropertySettingsPanel.java @@ -28,14 +28,10 @@ import javax.swing.Box; import javax.swing.ImageIcon; import javax.swing.JButton; -import javax.swing.JDialog; -import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.ListSelectionModel; -import javax.swing.UIManager; -import javax.swing.UnsupportedLookAndFeelException; import jcs.JCS; import jcs.entities.JCSPropertyBean; import jcs.persistence.PersistenceFactory; @@ -237,33 +233,6 @@ private void deleteBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_delete alignPropertiesTable(); }//GEN-LAST:event_deleteBtnActionPerformed - public static void main(String args[]) { - try { - UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { - Logger.warn("Can't set the LookAndFeel: " + ex); - } - java.awt.EventQueue.invokeLater(() -> { - - PropertySettingsPanel testPanel = new PropertySettingsPanel(); - JFrame testFrame = new JFrame(); - JDialog testDialog = new JDialog(testFrame, true); - - testDialog.add(testPanel); - - testDialog.addWindowListener(new java.awt.event.WindowAdapter() { - @Override - public void windowClosing(java.awt.event.WindowEvent e) { - System.exit(0); - } - }); - testDialog.pack(); - testDialog.setLocationRelativeTo(null); - - testDialog.setVisible(true); - }); - } - // Variables declaration - do not modify//GEN-BEGIN:variables private JPanel bottomPanel; diff --git a/src/main/java/jcs/ui/settings/OptionDialog.form b/src/main/java/jcs/ui/settings/SettingsDialog.form similarity index 67% rename from src/main/java/jcs/ui/settings/OptionDialog.form rename to src/main/java/jcs/ui/settings/SettingsDialog.form index 61f5ecba..929e22bb 100755 --- a/src/main/java/jcs/ui/settings/OptionDialog.form +++ b/src/main/java/jcs/ui/settings/SettingsDialog.form @@ -3,15 +3,12 @@ - + - - - @@ -27,29 +24,11 @@ - + - - - - - - - - - - - - - - - - - - @@ -65,15 +44,15 @@ - + - + - + @@ -83,18 +62,6 @@ - - - - - - - - - - - - @@ -119,6 +86,18 @@ + + + + + + + + + + + + @@ -135,42 +114,5 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/main/java/jcs/ui/settings/OptionDialog.java b/src/main/java/jcs/ui/settings/SettingsDialog.java similarity index 64% rename from src/main/java/jcs/ui/settings/OptionDialog.java rename to src/main/java/jcs/ui/settings/SettingsDialog.java index 70c86333..bb7fd0e5 100755 --- a/src/main/java/jcs/ui/settings/OptionDialog.java +++ b/src/main/java/jcs/ui/settings/SettingsDialog.java @@ -34,18 +34,17 @@ import org.tinylog.Logger; /** - * - * @author frans + * Settings Dialog combines the Settings Dialogs into one Dialog, so it can be shown in MacOS via the Settings Menu. */ -public class OptionDialog extends javax.swing.JDialog { +public class SettingsDialog extends javax.swing.JDialog { + + private static final long serialVersionUID = 4989500714204829315L; /** - * Creates new form NewJDialog - * * @param parent * @param modal */ - public OptionDialog(Frame parent, boolean modal) { + public SettingsDialog(Frame parent, boolean modal) { super(parent, modal); initComponents(); init(); @@ -63,85 +62,52 @@ private void init() { // //GEN-BEGIN:initComponents private void initComponents() { - topPanel = new JPanel(); centerPanel = new JPanel(); - prefsTP = new JTabbedPane(); - commandStationPanel = new CommandStationPanel(); + dialogTP = new JTabbedPane(); locomotivePanel = new LocomotiveSettingsPanel(); accessoryPreferencesPanel = new AccessorySettingsPanel(); + commandStationPanel = new CommandStationPanel(); propertiesPanel = new PropertySettingsPanel(); - southPanel = new JPanel(); - closeBtn = new JButton(); setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); - setTitle("Options"); + setTitle("Settings"); setAlwaysOnTop(true); setMinimumSize(new Dimension(1024, 750)); setName("Options"); // NOI18N - setPreferredSize(new Dimension(1024, 750)); - - topPanel.setMinimumSize(new Dimension(1024, 20)); - topPanel.setName("topPanel"); // NOI18N - topPanel.setPreferredSize(new Dimension(1024, 20)); - getContentPane().add(topPanel, BorderLayout.PAGE_START); centerPanel.setMinimumSize(new Dimension(1021, 750)); centerPanel.setName("centerPanel"); // NOI18N centerPanel.setLayout(new BorderLayout()); - prefsTP.setName("prefsTP"); // NOI18N - prefsTP.addChangeListener(new ChangeListener() { + dialogTP.setName("dialogTP"); // NOI18N + dialogTP.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent evt) { - prefsTPStateChanged(evt); + dialogTPStateChanged(evt); } }); - commandStationPanel.setName("commandStationPanel"); // NOI18N - prefsTP.addTab("Command Station", commandStationPanel); - locomotivePanel.setName("locomotivePanel"); // NOI18N - prefsTP.addTab("Locomotives", locomotivePanel); + dialogTP.addTab("Locomotives", locomotivePanel); accessoryPreferencesPanel.setName("accessoryPreferencesPanel"); // NOI18N - prefsTP.addTab("Accessories", accessoryPreferencesPanel); + dialogTP.addTab("Accessories", accessoryPreferencesPanel); + + commandStationPanel.setName("commandStationPanel"); // NOI18N + dialogTP.addTab("Command Stations", commandStationPanel); propertiesPanel.setName("propertiesPanel"); // NOI18N - prefsTP.addTab("Properties", propertiesPanel); + dialogTP.addTab("Properties", propertiesPanel); - centerPanel.add(prefsTP, BorderLayout.CENTER); - prefsTP.getAccessibleContext().setAccessibleName("Locomotives"); + centerPanel.add(dialogTP, BorderLayout.CENTER); + dialogTP.getAccessibleContext().setAccessibleName("Locomotives"); getContentPane().add(centerPanel, BorderLayout.CENTER); - southPanel.setName("southPanel"); // NOI18N - southPanel.setLayout(new FlowLayout(FlowLayout.RIGHT)); - - closeBtn.setIcon(new ImageIcon(getClass().getResource("/media/exit-24.png"))); // NOI18N - closeBtn.setText("Close"); - closeBtn.setMaximumSize(new Dimension(100, 36)); - closeBtn.setMinimumSize(new Dimension(100, 36)); - closeBtn.setName("closeBtn"); // NOI18N - closeBtn.setPreferredSize(new Dimension(100, 36)); - closeBtn.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent evt) { - closeBtnActionPerformed(evt); - } - }); - southPanel.add(closeBtn); - - getContentPane().add(southPanel, BorderLayout.PAGE_END); - pack(); }// //GEN-END:initComponents - private void closeBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_closeBtnActionPerformed - this.setVisible(false); - this.dispose(); - - }//GEN-LAST:event_closeBtnActionPerformed - - private void prefsTPStateChanged(ChangeEvent evt) {//GEN-FIRST:event_prefsTPStateChanged - Component c = this.prefsTP.getSelectedComponent(); + private void dialogTPStateChanged(ChangeEvent evt) {//GEN-FIRST:event_dialogTPStateChanged + Component c = this.dialogTP.getSelectedComponent(); if (c instanceof LocomotiveSettingsPanel) { //this.locomotivePanel.refresh(); @@ -152,26 +118,32 @@ private void prefsTPStateChanged(ChangeEvent evt) {//GEN-FIRST:event_prefsTPStat } Logger.debug("Refreshed " + (c != null ? c.getName() : "")); - }//GEN-LAST:event_prefsTPStateChanged + }//GEN-LAST:event_dialogTPStateChanged /** * @param args the command line arguments */ public static void main(String args[]) { + /* Set the FlatLightLaf look and feel */ + // try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { Logger.warn("Can't set the LookAndFeel: " + ex); } + // + /* Create and display the dialog */ java.awt.EventQueue.invokeLater(() -> { - OptionDialog dialog = new OptionDialog(new javax.swing.JFrame(), true); + SettingsDialog dialog = new SettingsDialog(new javax.swing.JFrame(), true); dialog.addWindowListener(new java.awt.event.WindowAdapter() { @Override public void windowClosing(java.awt.event.WindowEvent e) { System.exit(0); } }); + dialog.pack(); + dialog.setLocationRelativeTo(null); dialog.setVisible(true); }); } @@ -180,12 +152,9 @@ public void windowClosing(java.awt.event.WindowEvent e) { // Variables declaration - do not modify//GEN-BEGIN:variables private AccessorySettingsPanel accessoryPreferencesPanel; private JPanel centerPanel; - private JButton closeBtn; private CommandStationPanel commandStationPanel; + private JTabbedPane dialogTP; private LocomotiveSettingsPanel locomotivePanel; - private JTabbedPane prefsTP; private PropertySettingsPanel propertiesPanel; - private JPanel southPanel; - private JPanel topPanel; // End of variables declaration//GEN-END:variables } From 5cf70d1e43bb2f32210ff042c5b2026a454efa8a Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Mon, 7 Apr 2025 20:59:53 +0200 Subject: [PATCH 41/70] UI Changes adding a Smal Drive Cab Panel WIP! --- src/main/java/jcs/JCS.java | 137 +- .../java/jcs/ui/DispatcherStatusPanel.form | 13 +- .../java/jcs/ui/DispatcherStatusPanel.java | 11 +- src/main/java/jcs/ui/JCSFrame.form | 658 +------ src/main/java/jcs/ui/JCSFrame.java | 258 +-- .../DispatcherTablePanel.form | 4 +- .../DispatcherTablePanel.java | 4 +- .../LocomotiveTablePanel.form | 4 +- .../LocomotiveTablePanel.java | 4 +- .../java/jcs/ui/{ => panel}/SignalsPanel.form | 0 .../java/jcs/ui/{ => panel}/SignalsPanel.java | 34 +- .../jcs/ui/panel/SmallDriverCabPanel.form | 1666 +++++++++++++++++ .../jcs/ui/panel/SmallDriverCabPanel.java | 1346 +++++++++++++ .../jcs/ui/{ => panel}/TurnoutsPanel.form | 0 .../jcs/ui/{ => panel}/TurnoutsPanel.java | 41 +- src/main/java/jcs/ui/swing/layout/HBox.java | 160 -- src/main/java/jcs/ui/swing/layout/VBox.java | 147 -- 17 files changed, 3269 insertions(+), 1218 deletions(-) rename src/main/java/jcs/ui/{table => panel}/DispatcherTablePanel.form (98%) rename src/main/java/jcs/ui/{table => panel}/DispatcherTablePanel.java (98%) rename src/main/java/jcs/ui/{table => panel}/LocomotiveTablePanel.form (98%) rename src/main/java/jcs/ui/{table => panel}/LocomotiveTablePanel.java (98%) rename src/main/java/jcs/ui/{ => panel}/SignalsPanel.form (100%) rename src/main/java/jcs/ui/{ => panel}/SignalsPanel.java (78%) create mode 100644 src/main/java/jcs/ui/panel/SmallDriverCabPanel.form create mode 100644 src/main/java/jcs/ui/panel/SmallDriverCabPanel.java rename src/main/java/jcs/ui/{ => panel}/TurnoutsPanel.form (100%) rename src/main/java/jcs/ui/{ => panel}/TurnoutsPanel.java (81%) delete mode 100644 src/main/java/jcs/ui/swing/layout/HBox.java delete mode 100644 src/main/java/jcs/ui/swing/layout/VBox.java diff --git a/src/main/java/jcs/JCS.java b/src/main/java/jcs/JCS.java index 5fd2167d..d001ca1a 100755 --- a/src/main/java/jcs/JCS.java +++ b/src/main/java/jcs/JCS.java @@ -108,75 +108,6 @@ public static JCSCommandStation getJcsCommandStation() { return jcsCommandStation; } - private void startGui() { - JCS.logProgress("Check OS..."); - - if (RunUtil.isMacOSX()) { - - try { - Desktop desktop = Desktop.getDesktop(); - desktop.setAboutHandler(new JCSAboutHandler()); - desktop.setQuitHandler(new JCSQuitHandler()); - desktop.setPreferencesHandler(new JCSPreferencesHandler()); - - Taskbar taskbar = Taskbar.getTaskbar(); - try { - //BufferedImage img = ImageIO.read(JCS.class.getResource("/media/jcs-train-64.png")); - BufferedImage img = ImageIO.read(JCS.class.getResource("/media/jcs-train-2-512.png")); - taskbar.setIconImage(img); - } catch (final UnsupportedOperationException e) { - Logger.warn("The os does not support: 'taskbar.setIconImage'"); - } catch (final SecurityException e) { - Logger.warn("There was a security exception for: 'taskbar.setIconImage'"); - } - - } catch (SecurityException | IllegalArgumentException | IOException ex) { - Logger.warn("Failed to register with MacOS: " + ex); - } - - } - - java.awt.EventQueue.invokeLater(() -> { - jcsFrame = new JCSFrame(); - JCS.uiCallback = jcsFrame; - - //URL iconUrl = JCS.class.getResource("/media/jcs-train-64.png"); - URL iconUrl = JCS.class.getResource("/media/jcs-train-2-512.png"); - if (iconUrl != null) { - jcsFrame.setIconImage(new ImageIcon(iconUrl).getImage()); - } - - FrameMonitor.registerFrame(jcsFrame, JCS.class.getName()); - - jcsFrame.setVisible(true); - jcsFrame.toFront(); - jcsFrame.showOverviewPanel(); - if ("true".equalsIgnoreCase(System.getProperty("controller.autoconnect", "true"))) { - jcsFrame.connect(true); - } - }); - - JCS.logProgress("JCS started..."); - - int mb = 1024 * 1024; - Runtime runtime = Runtime.getRuntime(); - - StringBuilder sb = new StringBuilder(); - sb.append("Used Memory: "); - sb.append((runtime.totalMemory() - runtime.freeMemory()) / mb); - sb.append(" [MB]. Free Memory: "); - sb.append(runtime.freeMemory() / mb); - sb.append(" [MB]. Available Memory: "); - sb.append(runtime.totalMemory() / mb); - sb.append(" [MB]. Max Memory: "); - sb.append(runtime.maxMemory() / mb); - sb.append(" [MB]."); - - Logger.info(sb); - splashScreen.hideSplash(200); - splashScreen.close(); - } - /** * Executed at shutdown in response to a Ctrl-C etc. */ @@ -250,7 +181,6 @@ public static void main(String[] args) { System.setProperty("apple.awt.application.name", "JCS"); System.setProperty("apple.laf.useScreenMenuBar", "true"); System.setProperty("apple.awt.application.appearance", "system"); - } splashScreen = new JCSSplash(); @@ -310,6 +240,7 @@ public static void main(String[] args) { logProgress("Starting UI..."); JCS jcs = JCS.getInstance(); + jcs.startGui(); } else { Logger.error("Could not obtain a Persistent store. Quitting...."); @@ -320,6 +251,72 @@ public static void main(String[] args) { } } + private void startGui() { + JCS.logProgress("Starting UI..."); + + if (RunUtil.isMacOSX()) { + try { + Desktop desktop = Desktop.getDesktop(); + desktop.setAboutHandler(new JCSAboutHandler()); + desktop.setQuitHandler(new JCSQuitHandler()); + desktop.setPreferencesHandler(new JCSPreferencesHandler()); + + Taskbar taskbar = Taskbar.getTaskbar(); + try { + //BufferedImage img = ImageIO.read(JCS.class.getResource("/media/jcs-train-64.png")); + BufferedImage img = ImageIO.read(JCS.class.getResource("/media/jcs-train-2-512.png")); + taskbar.setIconImage(img); + } catch (final UnsupportedOperationException e) { + Logger.warn("The os does not support: 'taskbar.setIconImage'"); + } catch (final SecurityException e) { + Logger.warn("There was a security exception for: 'taskbar.setIconImage'"); + } + } catch (SecurityException | IllegalArgumentException | IOException ex) { + Logger.warn("Failed to register with MacOS: " + ex); + } + } + + java.awt.EventQueue.invokeLater(() -> { + jcsFrame = new JCSFrame(); + JCS.uiCallback = jcsFrame; + + //URL iconUrl = JCS.class.getResource("/media/jcs-train-64.png"); + URL iconUrl = JCS.class.getResource("/media/jcs-train-2-512.png"); + if (iconUrl != null) { + jcsFrame.setIconImage(new ImageIcon(iconUrl).getImage()); + } + + FrameMonitor.registerFrame(jcsFrame, JCS.class.getName()); + + jcsFrame.setVisible(true); + jcsFrame.toFront(); + jcsFrame.showOverviewPanel(); + if ("true".equalsIgnoreCase(System.getProperty("controller.autoconnect", "true"))) { + jcsFrame.connect(true); + } + }); + + JCS.logProgress("JCS started..."); + + int mb = 1024 * 1024; + Runtime runtime = Runtime.getRuntime(); + + StringBuilder sb = new StringBuilder(); + sb.append("Used Memory: "); + sb.append((runtime.totalMemory() - runtime.freeMemory()) / mb); + sb.append(" [MB]. Free Memory: "); + sb.append(runtime.freeMemory() / mb); + sb.append(" [MB]. Available Memory: "); + sb.append(runtime.totalMemory() / mb); + sb.append(" [MB]. Max Memory: "); + sb.append(runtime.maxMemory() / mb); + sb.append(" [MB]."); + + Logger.info(sb); + splashScreen.hideSplash(200); + splashScreen.close(); + } + private static class Powerlistener implements PowerEventListener { Powerlistener() { diff --git a/src/main/java/jcs/ui/DispatcherStatusPanel.form b/src/main/java/jcs/ui/DispatcherStatusPanel.form index 8a075537..7ddca164 100644 --- a/src/main/java/jcs/ui/DispatcherStatusPanel.form +++ b/src/main/java/jcs/ui/DispatcherStatusPanel.form @@ -1,6 +1,11 @@
+ + + + + @@ -11,7 +16,7 @@ - + @@ -19,7 +24,7 @@ - + @@ -30,7 +35,7 @@ - + @@ -39,7 +44,7 @@ - + diff --git a/src/main/java/jcs/ui/DispatcherStatusPanel.java b/src/main/java/jcs/ui/DispatcherStatusPanel.java index d9f52bc7..9df38962 100644 --- a/src/main/java/jcs/ui/DispatcherStatusPanel.java +++ b/src/main/java/jcs/ui/DispatcherStatusPanel.java @@ -56,12 +56,13 @@ public void onChange(RefreshEvent event) { private void initComponents() { tabsPane = new javax.swing.JTabbedPane(); - locomotiveTablePanel = new jcs.ui.table.LocomotiveTablePanel(); - dispatcherTablePanel = new jcs.ui.table.DispatcherTablePanel(); + locomotiveTablePanel = new jcs.ui.panel.LocomotiveTablePanel(); + dispatcherTablePanel = new jcs.ui.panel.DispatcherTablePanel(); + setPreferredSize(new java.awt.Dimension(300, 450)); setLayout(new java.awt.BorderLayout()); - tabsPane.setPreferredSize(new java.awt.Dimension(300, 800)); + tabsPane.setPreferredSize(new java.awt.Dimension(300, 440)); tabsPane.addTab("Locomotives", locomotiveTablePanel); tabsPane.addTab("Dispatcher", dispatcherTablePanel); @@ -70,8 +71,8 @@ private void initComponents() { // Variables declaration - do not modify//GEN-BEGIN:variables - private jcs.ui.table.DispatcherTablePanel dispatcherTablePanel; - private jcs.ui.table.LocomotiveTablePanel locomotiveTablePanel; + private jcs.ui.panel.DispatcherTablePanel dispatcherTablePanel; + private jcs.ui.panel.LocomotiveTablePanel locomotiveTablePanel; private javax.swing.JTabbedPane tabsPane; // End of variables declaration//GEN-END:variables diff --git a/src/main/java/jcs/ui/JCSFrame.form b/src/main/java/jcs/ui/JCSFrame.form index 6e3c4cc8..0296dc07 100755 --- a/src/main/java/jcs/ui/JCSFrame.form +++ b/src/main/java/jcs/ui/JCSFrame.form @@ -328,12 +328,12 @@ - + - + - + @@ -353,17 +353,20 @@ - + - + + + + - + @@ -383,29 +386,12 @@ - - - - - - - - - - - - - - - - - - + - + - + @@ -425,34 +411,31 @@ - + - + - - - - + - + - + - + - + - + @@ -495,23 +478,6 @@ - - - - - - - - - - - - - - - - - @@ -621,7 +587,7 @@ - + @@ -632,7 +598,7 @@ - + @@ -669,7 +635,7 @@ - + @@ -680,7 +646,7 @@ - + @@ -724,6 +690,23 @@ + + + + + + + + + + + + + + + + + @@ -762,35 +745,18 @@ - - - - - - - - - - - - - - - - - - + - + - + - + - + @@ -1118,534 +1084,46 @@ - + - - - - - - - - - - - - + + + + - + - - - + - + - - - - - - + - + - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - - - - - - - - - - diff --git a/src/main/java/jcs/ui/JCSFrame.java b/src/main/java/jcs/ui/JCSFrame.java index de16fc71..3012e305 100755 --- a/src/main/java/jcs/ui/JCSFrame.java +++ b/src/main/java/jcs/ui/JCSFrame.java @@ -65,6 +65,7 @@ import jcs.persistence.PersistenceFactory; import jcs.ui.layout.LayoutCanvas; import jcs.ui.layout.LayoutPanel; +import jcs.ui.panel.SmallDriverCabPanel; import jcs.ui.settings.AccessoryDialog; import jcs.ui.settings.CommandStationDialog; import jcs.ui.settings.CommandStationPanel; @@ -105,23 +106,19 @@ public JCSFrame() { actionMap = new HashMap<>(); initComponents(); - //TODO: see https://www.formdev.com/flatlaf/macos/ if (RunUtil.isMacOSX()) { //quitMI.setVisible(false); //optionsMI.setVisible(false); //settingsMenu.setVisible(false); + //see https://www.formdev.com/flatlaf/macos/ if (SystemInfo.isMacFullWindowContentSupported) { - getRootPane().putClientProperty("apple.awt.transparentTitleBar", true); - getRootPane().putClientProperty("apple.awt.fullWindowContent", true); - //this.getRootPane().putClientProperty( "apple.awt.windowTitleVisible", false ); - - getRootPane().putClientProperty("apple.awt.windowTitleVisible", false); - getRootPane().putClientProperty("apple.awt.brushMetalLook", true); + getRootPane().putClientProperty("apple.awt.transparentTitleBar", false); + getRootPane().putClientProperty("apple.awt.fullWindowContent", false); + //getRootPane().putClientProperty("apple.awt.windowTitleVisible", false); //avoid overlap of the red/orange/green buttons and the window title - jcsToolBar.add(Box.createHorizontalStrut(70), 0); - + //jcsToolBar.add(Box.createHorizontalStrut(70), 0); } initJCS(); @@ -283,14 +280,9 @@ private void setControllerProperties() { boolean connected = JCS.getJcsCommandStation().isConnected(); if (info != null) { this.connectButton.setSelected(connected); - this.controllerDescriptionLbl.setText(info.getProductName()); - this.controllerCatalogNumberLbl.setText(info.getArticleNumber()); - this.controllerSerialNumberLbl.setText(info.getSerialNumber()); - this.controllerHostNameLbl.setText(info.getHostname()); this.powerButton.setSelected(JCS.getJcsCommandStation().isPowerOn()); } else { this.connectButton.setSelected(connected); - this.controllerHostNameLbl.setText("Not Connected"); this.powerButton.setSelected(connected); } boolean virt = JCS.getJcsCommandStation().isVirtual(); @@ -317,23 +309,21 @@ private void initComponents() { toolbarPanel = new JPanel(); jcsToolBar = new JToolBar(); - connectButton = new JToggleButton(); - filler1 = new Box.Filler(new Dimension(5, 0), new Dimension(5, 0), new Dimension(5, 32767)); - filler2 = new Box.Filler(new Dimension(5, 0), new Dimension(5, 0), new Dimension(5, 32767)); powerButton = new JToggleButton(); - filler3 = new Box.Filler(new Dimension(20, 0), new Dimension(20, 0), new Dimension(20, 32767)); + filler1 = new Box.Filler(new Dimension(5, 0), new Dimension(5, 0), new Dimension(5, 32767)); + connectButton = new JToggleButton(); + filler2 = new Box.Filler(new Dimension(10, 0), new Dimension(10, 0), new Dimension(10, 32767)); showOverviewBtn = new JButton(); - filler4 = new Box.Filler(new Dimension(5, 0), new Dimension(5, 0), new Dimension(5, 32767)); showEditDesignBtn = new JButton(); showVNCBtn = new JButton(); showKeyboardBtn = new JButton(); - filler5 = new Box.Filler(new Dimension(20, 0), new Dimension(20, 0), new Dimension(20, 32767)); + filler3 = new Box.Filler(new Dimension(20, 0), new Dimension(20, 0), new Dimension(20, 32767)); showFeedbackMonitorBtn = new JButton(); - filler8 = new Box.Filler(new Dimension(20, 0), new Dimension(20, 0), new Dimension(20, 32767)); + filler4 = new Box.Filler(new Dimension(20, 0), new Dimension(20, 0), new Dimension(20, 32767)); autoPilotBtn = new JToggleButton(); + filler5 = new Box.Filler(new Dimension(5, 0), new Dimension(5, 0), new Dimension(5, 32767)); startAllLocsBtn = new JButton(); - filler9 = new Box.Filler(new Dimension(20, 0), new Dimension(20, 0), new Dimension(20, 32767)); - filler10 = new Box.Filler(new Dimension(20, 0), new Dimension(20, 0), new Dimension(20, 32767)); + filler8 = new Box.Filler(new Dimension(25, 0), new Dimension(25, 0), new Dimension(25, 32767)); statusPanel = new StatusPanel(); mainPanel = new JPanel(); locoDisplaySP = new JSplitPane(); @@ -345,22 +335,9 @@ private void initComponents() { commandStationPanel = new CommandStationPanel(); vncPanel = new VNCPanel(); leftPanel = new JPanel(); - bottomLeftPanel = new JPanel(); - filler7 = new Box.Filler(new Dimension(0, 10), new Dimension(0, 10), new Dimension(32767, 35)); - jPanel1 = new JPanel(); - controllerLbl = new JLabel(); - controllerDescriptionLbl = new JLabel(); - jPanel2 = new JPanel(); - controllerCatalogLbl = new JLabel(); - controllerCatalogNumberLbl = new JLabel(); - jPanel3 = new JPanel(); - controllerSerialLbl = new JLabel(); - controllerSerialNumberLbl = new JLabel(); - jPanel4 = new JPanel(); - controllerHostLbl = new JLabel(); - controllerHostNameLbl = new JLabel(); - filler6 = new Box.Filler(new Dimension(0, 110), new Dimension(0, 110), new Dimension(32767, 35)); + jSplitPane1 = new JSplitPane(); dispatcherStatusPanel = new DispatcherStatusPanel(); + smallDriverCabPanel1 = new SmallDriverCabPanel(); jcsMenuBar = new JMenuBar(); fileMenu = new JMenu(); quitMI = new JMenuItem(); @@ -413,6 +390,30 @@ public void windowClosing(WindowEvent evt) { jcsToolBar.setOpaque(false); jcsToolBar.setPreferredSize(new Dimension(1380, 42)); + powerButton.setIcon(new ImageIcon(getClass().getResource("/media/power-red-24.png"))); // NOI18N + powerButton.setToolTipText("Switch Track power On/Off"); + powerButton.setBorder(BorderFactory.createLineBorder(new Color(204, 204, 204))); + powerButton.setDoubleBuffered(true); + powerButton.setFocusable(false); + powerButton.setHorizontalTextPosition(SwingConstants.CENTER); + powerButton.setMargin(new Insets(0, 0, 0, 0)); + powerButton.setMaximumSize(new Dimension(40, 40)); + powerButton.setMinimumSize(new Dimension(40, 40)); + powerButton.setName("powerButton"); // NOI18N + powerButton.setPreferredSize(new Dimension(40, 40)); + powerButton.setSelectedIcon(new ImageIcon(getClass().getResource("/media/power-green-24.png"))); // NOI18N + powerButton.setVerticalTextPosition(SwingConstants.BOTTOM); + powerButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + powerButtonActionPerformed(evt); + } + }); + jcsToolBar.add(powerButton); + powerButton.getAccessibleContext().setAccessibleName("Power"); + + filler1.setName("filler1"); // NOI18N + jcsToolBar.add(filler1); + connectButton.setIcon(new ImageIcon(getClass().getResource("/media/monitor-off-24.png"))); // NOI18N connectButton.setToolTipText("Connect/Disconnect with Central Station"); connectButton.setBorder(BorderFactory.createLineBorder(new Color(204, 204, 204))); @@ -433,36 +434,9 @@ public void actionPerformed(ActionEvent evt) { }); jcsToolBar.add(connectButton); - filler1.setName("filler1"); // NOI18N - jcsToolBar.add(filler1); - filler2.setName("filler2"); // NOI18N jcsToolBar.add(filler2); - powerButton.setIcon(new ImageIcon(getClass().getResource("/media/power-red-24.png"))); // NOI18N - powerButton.setToolTipText("Switch Track power On/Off"); - powerButton.setBorder(BorderFactory.createLineBorder(new Color(204, 204, 204))); - powerButton.setDoubleBuffered(true); - powerButton.setFocusable(false); - powerButton.setHorizontalTextPosition(SwingConstants.CENTER); - powerButton.setMargin(new Insets(0, 0, 0, 0)); - powerButton.setMaximumSize(new Dimension(40, 40)); - powerButton.setMinimumSize(new Dimension(40, 40)); - powerButton.setName("powerButton"); // NOI18N - powerButton.setPreferredSize(new Dimension(40, 40)); - powerButton.setSelectedIcon(new ImageIcon(getClass().getResource("/media/power-green-24.png"))); // NOI18N - powerButton.setVerticalTextPosition(SwingConstants.BOTTOM); - powerButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent evt) { - powerButtonActionPerformed(evt); - } - }); - jcsToolBar.add(powerButton); - powerButton.getAccessibleContext().setAccessibleName("Power"); - - filler3.setName("filler3"); // NOI18N - jcsToolBar.add(filler3); - showOverviewBtn.setIcon(new ImageIcon(getClass().getResource("/media/home-24.png"))); // NOI18N showOverviewBtn.setToolTipText("Overview"); showOverviewBtn.setBorder(BorderFactory.createLineBorder(new Color(204, 204, 204))); @@ -482,9 +456,6 @@ public void actionPerformed(ActionEvent evt) { jcsToolBar.add(showOverviewBtn); showOverviewBtn.getAccessibleContext().setAccessibleName("Home"); - filler4.setName("filler4"); // NOI18N - jcsToolBar.add(filler4); - showEditDesignBtn.setIcon(new ImageIcon(getClass().getResource("/media/paintbrush-24.png"))); // NOI18N showEditDesignBtn.setToolTipText("Edit Layout"); showEditDesignBtn.setBorder(BorderFactory.createLineBorder(new Color(204, 204, 204))); @@ -542,8 +513,8 @@ public void actionPerformed(ActionEvent evt) { jcsToolBar.add(showKeyboardBtn); showKeyboardBtn.getAccessibleContext().setAccessibleName("Switchboard"); - filler5.setName("filler5"); // NOI18N - jcsToolBar.add(filler5); + filler3.setName("filler3"); // NOI18N + jcsToolBar.add(filler3); showFeedbackMonitorBtn.setIcon(new ImageIcon(getClass().getResource("/media/monitor-24.png"))); // NOI18N showFeedbackMonitorBtn.setToolTipText("Show Sensor Monitor"); @@ -562,8 +533,8 @@ public void actionPerformed(ActionEvent evt) { }); jcsToolBar.add(showFeedbackMonitorBtn); - filler8.setName("filler8"); // NOI18N - jcsToolBar.add(filler8); + filler4.setName("filler4"); // NOI18N + jcsToolBar.add(filler4); autoPilotBtn.setIcon(new ImageIcon(getClass().getResource("/media/pilot.png"))); // NOI18N autoPilotBtn.setToolTipText("En- or Disable automatic driving"); @@ -585,6 +556,9 @@ public void actionPerformed(ActionEvent evt) { }); jcsToolBar.add(autoPilotBtn); + filler5.setName("filler5"); // NOI18N + jcsToolBar.add(filler5); + startAllLocsBtn.setIcon(new ImageIcon(getClass().getResource("/media/arrowhead-right-gn.png"))); // NOI18N startAllLocsBtn.setToolTipText("Start all Locomotives"); startAllLocsBtn.setBorder(BorderFactory.createLineBorder(new Color(204, 204, 204))); @@ -605,11 +579,8 @@ public void actionPerformed(ActionEvent evt) { }); jcsToolBar.add(startAllLocsBtn); - filler9.setName("filler9"); // NOI18N - jcsToolBar.add(filler9); - - filler10.setName("filler10"); // NOI18N - jcsToolBar.add(filler10); + filler8.setName("filler8"); // NOI18N + jcsToolBar.add(filler8); toolbarPanel.add(jcsToolBar); @@ -671,99 +642,19 @@ public void actionPerformed(ActionEvent evt) { leftPanel.setPreferredSize(new Dimension(225, 772)); leftPanel.setLayout(new BorderLayout(1, 1)); - bottomLeftPanel.setBorder(BorderFactory.createTitledBorder("Controller Properties")); - bottomLeftPanel.setMinimumSize(new Dimension(220, 200)); - bottomLeftPanel.setName("bottomLeftPanel"); // NOI18N - bottomLeftPanel.setPreferredSize(new Dimension(200, 200)); - bottomLeftPanel.setLayout(new BoxLayout(bottomLeftPanel, BoxLayout.Y_AXIS)); - - filler7.setName("filler7"); // NOI18N - bottomLeftPanel.add(filler7); - - jPanel1.setName("jPanel1"); // NOI18N - FlowLayout flowLayout3 = new FlowLayout(FlowLayout.LEFT); - flowLayout3.setAlignOnBaseline(true); - jPanel1.setLayout(flowLayout3); - - controllerLbl.setHorizontalAlignment(SwingConstants.TRAILING); - controllerLbl.setLabelFor(controllerDescriptionLbl); - controllerLbl.setText("Controller:"); - controllerLbl.setDoubleBuffered(true); - controllerLbl.setHorizontalTextPosition(SwingConstants.CENTER); - controllerLbl.setName("controllerLbl"); // NOI18N - controllerLbl.setPreferredSize(new Dimension(75, 16)); - jPanel1.add(controllerLbl); - - controllerDescriptionLbl.setText("..."); - controllerDescriptionLbl.setName("controllerDescriptionLbl"); // NOI18N - controllerDescriptionLbl.setPreferredSize(new Dimension(125, 16)); - jPanel1.add(controllerDescriptionLbl); - - bottomLeftPanel.add(jPanel1); - - jPanel2.setName("jPanel2"); // NOI18N - FlowLayout flowLayout4 = new FlowLayout(FlowLayout.LEFT); - flowLayout4.setAlignOnBaseline(true); - jPanel2.setLayout(flowLayout4); - - controllerCatalogLbl.setHorizontalAlignment(SwingConstants.TRAILING); - controllerCatalogLbl.setLabelFor(controllerCatalogNumberLbl); - controllerCatalogLbl.setText("Model:"); - controllerCatalogLbl.setName("controllerCatalogLbl"); // NOI18N - controllerCatalogLbl.setOpaque(true); - controllerCatalogLbl.setPreferredSize(new Dimension(75, 16)); - jPanel2.add(controllerCatalogLbl); - - controllerCatalogNumberLbl.setText("..."); - controllerCatalogNumberLbl.setName("controllerCatalogNumberLbl"); // NOI18N - controllerCatalogNumberLbl.setPreferredSize(new Dimension(125, 16)); - jPanel2.add(controllerCatalogNumberLbl); - - bottomLeftPanel.add(jPanel2); - - jPanel3.setName("jPanel3"); // NOI18N - FlowLayout flowLayout6 = new FlowLayout(FlowLayout.LEFT); - flowLayout6.setAlignOnBaseline(true); - jPanel3.setLayout(flowLayout6); - - controllerSerialLbl.setHorizontalAlignment(SwingConstants.TRAILING); - controllerSerialLbl.setText("Serial:"); - controllerSerialLbl.setName("controllerSerialLbl"); // NOI18N - controllerSerialLbl.setPreferredSize(new Dimension(75, 16)); - jPanel3.add(controllerSerialLbl); - - controllerSerialNumberLbl.setText("..."); - controllerSerialNumberLbl.setName("controllerSerialNumberLbl"); // NOI18N - controllerSerialNumberLbl.setPreferredSize(new Dimension(125, 16)); - jPanel3.add(controllerSerialNumberLbl); - - bottomLeftPanel.add(jPanel3); - - jPanel4.setName("jPanel4"); // NOI18N - FlowLayout flowLayout5 = new FlowLayout(FlowLayout.LEFT); - flowLayout5.setAlignOnBaseline(true); - jPanel4.setLayout(flowLayout5); - - controllerHostLbl.setHorizontalAlignment(SwingConstants.TRAILING); - controllerHostLbl.setText("Host:"); - controllerHostLbl.setName("controllerHostLbl"); // NOI18N - controllerHostLbl.setPreferredSize(new Dimension(75, 16)); - jPanel4.add(controllerHostLbl); - - controllerHostNameLbl.setText("..."); - controllerHostNameLbl.setName("controllerHostNameLbl"); // NOI18N - controllerHostNameLbl.setPreferredSize(new Dimension(125, 16)); - jPanel4.add(controllerHostNameLbl); - - bottomLeftPanel.add(jPanel4); - - filler6.setName("filler6"); // NOI18N - bottomLeftPanel.add(filler6); - - leftPanel.add(bottomLeftPanel, BorderLayout.SOUTH); + jSplitPane1.setDividerLocation(500); + jSplitPane1.setOrientation(JSplitPane.VERTICAL_SPLIT); + jSplitPane1.setToolTipText(""); + jSplitPane1.setName("jSplitPane1"); // NOI18N dispatcherStatusPanel.setName("dispatcherStatusPanel"); // NOI18N - leftPanel.add(dispatcherStatusPanel, BorderLayout.CENTER); + dispatcherStatusPanel.setPreferredSize(new Dimension(300, 450)); + jSplitPane1.setLeftComponent(dispatcherStatusPanel); + + smallDriverCabPanel1.setName("smallDriverCabPanel1"); // NOI18N + jSplitPane1.setRightComponent(smallDriverCabPanel1); + + leftPanel.add(jSplitPane1, BorderLayout.CENTER); locoDisplaySP.setLeftComponent(leftPanel); @@ -1082,24 +973,14 @@ public void connect(boolean connect) { if (info != null && connected) { connectButton.setSelected(true); - controllerDescriptionLbl.setText(info.getProductName()); - controllerCatalogNumberLbl.setText(info.getArticleNumber()); - controllerSerialNumberLbl.setText(info.getSerialNumber()); - controllerHostNameLbl.setText(info.getHostname()); powerButton.setSelected(JCS.getJcsCommandStation().isPowerOn()); connectMI.setText("Disconnect"); } else { connectButton.setSelected(false); - controllerHostNameLbl.setText("Disconnected"); powerButton.setSelected(JCS.getJcsCommandStation().isPowerOn()); } } else { JCS.getJcsCommandStation().disconnect(); - controllerDescriptionLbl.setText("-"); - controllerCatalogNumberLbl.setText("-"); - controllerSerialNumberLbl.setText("-"); - controllerHostNameLbl.setText("Disconnected"); - connectMI.setText("Connect"); } } @@ -1264,8 +1145,6 @@ public void openFiles(List files) { @Override public void onDisconnect(DisconnectionEvent event) { JOptionPane.showMessageDialog(this, "CommandStation " + event.getSource() + " is disconnected.", "Disconnection error", JOptionPane.ERROR_MESSAGE); - - controllerHostNameLbl.setText("Disconnected"); connectMI.setText("Connect"); connectButton.setSelected(false); showVNCBtn.setEnabled(false); @@ -1309,41 +1188,25 @@ public void powerChanged(PowerEvent event) { private JMenuItem aboutMI; private JToggleButton autoPilotBtn; private JMenuItem autoPilotMI; - private JPanel bottomLeftPanel; private JPanel centerPanel; private CommandStationPanel commandStationPanel; private JToggleButton connectButton; private JMenuItem connectMI; - private JLabel controllerCatalogLbl; - private JLabel controllerCatalogNumberLbl; - private JLabel controllerDescriptionLbl; - private JLabel controllerHostLbl; - private JLabel controllerHostNameLbl; - private JLabel controllerLbl; - private JLabel controllerSerialLbl; - private JLabel controllerSerialNumberLbl; private JMenuItem deleteTileMI; private DispatcherStatusPanel dispatcherStatusPanel; private JMenuItem editLayout; private JMenu editMenu; private JMenu fileMenu; private Box.Filler filler1; - private Box.Filler filler10; private Box.Filler filler2; private Box.Filler filler3; private Box.Filler filler4; private Box.Filler filler5; - private Box.Filler filler6; - private Box.Filler filler7; private Box.Filler filler8; - private Box.Filler filler9; private JMenuItem flipTileHorizontallyMI; private JMenuItem flipTileVerticallyMI; private JMenu helpMenu; - private JPanel jPanel1; - private JPanel jPanel2; - private JPanel jPanel3; - private JPanel jPanel4; + private JSplitPane jSplitPane1; private JMenuBar jcsMenuBar; private JToolBar jcsToolBar; private KeyboardSensorPanel keyboardSensorMessagePanel; @@ -1371,6 +1234,7 @@ public void powerChanged(PowerEvent event) { private JMenuItem showRoutesMI; private JMenuItem showSensorMonitor; private JButton showVNCBtn; + private SmallDriverCabPanel smallDriverCabPanel1; private JButton startAllLocsBtn; private JMenuItem startAllLocsMI; private StatusPanel statusPanel; diff --git a/src/main/java/jcs/ui/table/DispatcherTablePanel.form b/src/main/java/jcs/ui/panel/DispatcherTablePanel.form similarity index 98% rename from src/main/java/jcs/ui/table/DispatcherTablePanel.form rename to src/main/java/jcs/ui/panel/DispatcherTablePanel.form index b4721e09..5001a4dd 100644 --- a/src/main/java/jcs/ui/table/DispatcherTablePanel.form +++ b/src/main/java/jcs/ui/panel/DispatcherTablePanel.form @@ -7,7 +7,7 @@ - + @@ -20,7 +20,7 @@ - + diff --git a/src/main/java/jcs/ui/table/DispatcherTablePanel.java b/src/main/java/jcs/ui/panel/DispatcherTablePanel.java similarity index 98% rename from src/main/java/jcs/ui/table/DispatcherTablePanel.java rename to src/main/java/jcs/ui/panel/DispatcherTablePanel.java index b9624cff..f531d403 100644 --- a/src/main/java/jcs/ui/table/DispatcherTablePanel.java +++ b/src/main/java/jcs/ui/panel/DispatcherTablePanel.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package jcs.ui.table; +package jcs.ui.panel; import com.twelvemonkeys.image.ImageUtil; import java.awt.Component; @@ -96,7 +96,7 @@ private void initComponents() { dispatcherSP = new javax.swing.JScrollPane(); dispatcherTable = new javax.swing.JTable(); - setPreferredSize(new java.awt.Dimension(300, 765)); + setPreferredSize(new java.awt.Dimension(300, 410)); setLayout(new java.awt.BorderLayout()); dispatcherSP.setViewportView(dispatcherTable); diff --git a/src/main/java/jcs/ui/table/LocomotiveTablePanel.form b/src/main/java/jcs/ui/panel/LocomotiveTablePanel.form similarity index 98% rename from src/main/java/jcs/ui/table/LocomotiveTablePanel.form rename to src/main/java/jcs/ui/panel/LocomotiveTablePanel.form index 1335d3f0..59c92a8f 100644 --- a/src/main/java/jcs/ui/table/LocomotiveTablePanel.form +++ b/src/main/java/jcs/ui/panel/LocomotiveTablePanel.form @@ -7,7 +7,7 @@ - + @@ -20,7 +20,7 @@ - + diff --git a/src/main/java/jcs/ui/table/LocomotiveTablePanel.java b/src/main/java/jcs/ui/panel/LocomotiveTablePanel.java similarity index 98% rename from src/main/java/jcs/ui/table/LocomotiveTablePanel.java rename to src/main/java/jcs/ui/panel/LocomotiveTablePanel.java index d4bf146d..9d52feed 100644 --- a/src/main/java/jcs/ui/table/LocomotiveTablePanel.java +++ b/src/main/java/jcs/ui/panel/LocomotiveTablePanel.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package jcs.ui.table; +package jcs.ui.panel; import com.twelvemonkeys.image.ImageUtil; import java.awt.Component; @@ -118,7 +118,7 @@ private void initComponents() { locomotiveSP = new javax.swing.JScrollPane(); locomotiveTable = new javax.swing.JTable(); - setPreferredSize(new java.awt.Dimension(300, 765)); + setPreferredSize(new java.awt.Dimension(300, 410)); setLayout(new java.awt.BorderLayout()); locomotiveSP.setViewportView(locomotiveTable); diff --git a/src/main/java/jcs/ui/SignalsPanel.form b/src/main/java/jcs/ui/panel/SignalsPanel.form similarity index 100% rename from src/main/java/jcs/ui/SignalsPanel.form rename to src/main/java/jcs/ui/panel/SignalsPanel.form diff --git a/src/main/java/jcs/ui/SignalsPanel.java b/src/main/java/jcs/ui/panel/SignalsPanel.java similarity index 78% rename from src/main/java/jcs/ui/SignalsPanel.java rename to src/main/java/jcs/ui/panel/SignalsPanel.java index 16220062..46edcd8c 100755 --- a/src/main/java/jcs/ui/SignalsPanel.java +++ b/src/main/java/jcs/ui/panel/SignalsPanel.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package jcs.ui; +package jcs.ui.panel; import java.awt.GridLayout; import java.util.Collections; @@ -78,21 +78,21 @@ public void refreshPanel() { * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") - // //GEN-BEGIN:initComponents - private void initComponents() { + // //GEN-BEGIN:initComponents + private void initComponents() { - setName("Form"); // NOI18N - setPreferredSize(new java.awt.Dimension(1024, 805)); - addKeyListener(new java.awt.event.KeyAdapter() { - public void keyPressed(java.awt.event.KeyEvent evt) { - formKeyPressed(evt); - } - public void keyTyped(java.awt.event.KeyEvent evt) { - formKeyTyped(evt); - } - }); - setLayout(new java.awt.GridLayout(1, 0)); - }// //GEN-END:initComponents + setName("Form"); // NOI18N + setPreferredSize(new java.awt.Dimension(1024, 805)); + addKeyListener(new java.awt.event.KeyAdapter() { + public void keyPressed(java.awt.event.KeyEvent evt) { + formKeyPressed(evt); + } + public void keyTyped(java.awt.event.KeyEvent evt) { + formKeyTyped(evt); + } + }); + setLayout(new java.awt.GridLayout(1, 0)); + }// //GEN-END:initComponents private void formKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_formKeyPressed Logger.debug("keyCode: " + evt.getKeyCode() + " paramString: " + evt.paramString() + "" + evt.getExtendedKeyCode()); @@ -102,6 +102,6 @@ private void formKeyTyped(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_formKe Logger.debug("keyCode: " + evt.getKeyCode() + " paramString: " + evt.paramString() + "" + evt.getExtendedKeyCode()); }//GEN-LAST:event_formKeyTyped - // Variables declaration - do not modify//GEN-BEGIN:variables - // End of variables declaration//GEN-END:variables + // Variables declaration - do not modify//GEN-BEGIN:variables + // End of variables declaration//GEN-END:variables } diff --git a/src/main/java/jcs/ui/panel/SmallDriverCabPanel.form b/src/main/java/jcs/ui/panel/SmallDriverCabPanel.form new file mode 100644 index 00000000..be45295b --- /dev/null +++ b/src/main/java/jcs/ui/panel/SmallDriverCabPanel.form @@ -0,0 +1,1666 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/jcs/ui/panel/SmallDriverCabPanel.java b/src/main/java/jcs/ui/panel/SmallDriverCabPanel.java new file mode 100644 index 00000000..09db090f --- /dev/null +++ b/src/main/java/jcs/ui/panel/SmallDriverCabPanel.java @@ -0,0 +1,1346 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.panel; + +import java.awt.event.ActionEvent; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import javax.swing.ImageIcon; +import javax.swing.JFrame; +import javax.swing.JToggleButton; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; +import javax.swing.event.ChangeListener; +import jcs.JCS; +import jcs.commandStation.events.LocomotiveDirectionEvent; +import jcs.commandStation.events.LocomotiveDirectionEventListener; +import jcs.commandStation.events.LocomotiveFunctionEvent; +import jcs.commandStation.events.LocomotiveSpeedEvent; +import jcs.commandStation.events.LocomotiveSpeedEventListener; +import jcs.commandStation.events.PowerEvent; +import jcs.commandStation.events.PowerEventListener; +import jcs.entities.FunctionBean; +import jcs.entities.LocomotiveBean; +import jcs.persistence.PersistenceFactory; +import org.tinylog.Logger; + +/** + * Small function Panel for use in the small driver Cab + */ +public class SmallDriverCabPanel extends javax.swing.JPanel implements LocomotiveDirectionEventListener, LocomotiveSpeedEventListener, PowerEventListener { + + private final Map buttons; + private LocomotiveBean locomotiveBean; + private final ExecutorService executor; + private boolean initButtons = false; + private boolean disableListener = false; + private boolean power; + + private boolean enableEvent = true; + + public SmallDriverCabPanel() { + buttons = new HashMap<>(); + executor = Executors.newCachedThreadPool(); + + initComponents(); + mapButtons(); + } + + private void mapButtons() { + buttons.put(0, f0TB); + buttons.put(1, f1TB); + buttons.put(2, f2TB); + buttons.put(3, f3TB); + buttons.put(4, f4TB); + buttons.put(5, f5TB); + buttons.put(6, f6TB); + buttons.put(7, f7TB); + buttons.put(8, f8TB); + buttons.put(9, f9TB); + buttons.put(10, f10TB); + buttons.put(11, f11TB); + buttons.put(12, f12TB); + buttons.put(13, f13TB); + buttons.put(14, f14TB); + buttons.put(15, f15TB); + + buttons.put(16, f16TB); + buttons.put(17, f17TB); + buttons.put(18, f18TB); + buttons.put(19, f19TB); + buttons.put(20, f20TB); + buttons.put(21, f21TB); + buttons.put(22, f22TB); + buttons.put(23, f23TB); + buttons.put(24, f24TB); + buttons.put(25, f25TB); + buttons.put(26, f26TB); + buttons.put(27, f27TB); + buttons.put(28, f28TB); + buttons.put(29, f29TB); + buttons.put(30, f30TB); + buttons.put(31, f31TB); + + setEnabled(false); + if (JCS.getJcsCommandStation() != null) { + //JCS.getJcsCommandStation().addLocomotiveFunctionEventListener(this); + } + } + + @Override + public void setEnabled(boolean enabled) { + super.setEnabled(enabled); + for (int i = 0; i < 32; i++) { + JToggleButton button = this.buttons.get(i); + button.setEnabled(enabled); + } + this.buttonsTP.setEnabled(enabled); + } + + //@Override + public void onFunctionChange(LocomotiveFunctionEvent event) { + if (this.locomotiveBean != null && this.locomotiveBean.getId().equals(event.getFunctionBean().getLocomotiveId())) { + FunctionBean fb = event.getFunctionBean(); + //this.buttons.get(fb.getNumber()).setSelected(fb.isOn()); + JToggleButton tbtn = this.buttons.get(fb.getNumber()); + + //Temp disable the event handling as this is an external event... + enableEvent = false; + tbtn.doClick(); + enableEvent = true; + + } else { + Logger.trace("Function button for LocomotiveId " + event.getFunctionBean().getLocomotiveId() + " and number " + event.getFunctionBean().getNumber() + " not found"); + } + } + + private void resetButtons() { + for (JToggleButton btn : this.buttons.values()) { + btn.setIcon(null); + btn.setSelectedIcon(null); + btn.setText(""); + btn.setEnabled(false); + + //btn.setForeground(new java.awt.Color(0, 0, 0)); + btn.setForeground(new java.awt.Color(204, 204, 204)); + btn.setBackground(new java.awt.Color(204, 204, 204)); + + btn.setSelected(false); + } + } + + public void setLocomotiveBean(LocomotiveBean locomotiveBean) { + resetButtons(); + initButtons = true; + if (PersistenceFactory.getService() != null && locomotiveBean != null) { + this.locomotiveBean = locomotiveBean; + Map functions = locomotiveBean.getFunctions(); + + Logger.trace("Loc: " + this.locomotiveBean.getName() + " has " + functions.size() + " functions"); + for (FunctionBean fb : functions.values()) { + Integer fnr = fb.getNumber(); + JToggleButton btn = this.buttons.get(fnr); + + //Logger.trace("Function: " + fb.getNumber() + " Type: " + fb.getFunctionType() + " Value: " + fb.getValue() + " isMomentary: " + fb.isMomentary()); + if (fb.getInActiveIconImage() != null) { + btn.setIcon(new ImageIcon(fb.getInActiveIconImage())); + } else { + btn.setText("F" + fb.getNumber()); + //Logger.trace("Missing Icon: " + fb.getInActiveIcon() + " Button Text: " + btn.getText()); + } + + if (fb.getActiveIconImage() != null) { + btn.setSelectedIcon(new ImageIcon(fb.getActiveIconImage())); + } else { + btn.setText("F" + fb.getNumber()); + //Logger.trace("Missing Icon: " + fb.getActiveIcon() + " Button Text: " + btn.getText()); + } + + btn.setActionCommand("F" + fb.getNumber()); + btn.setEnabled(true); + + boolean isOn = fb.getValue() == 1; + if (isOn) { + btn.doClick(); + } + //Logger.trace("Button " + btn.getActionCommand() + " selected: " + btn.isSelected()); + + } + this.buttonsTP.setEnabled(true); + } + initButtons = false; + } + + public LocomotiveBean getLocomotiveBean() { + return locomotiveBean; + } + + private void buttonActionPerformed(ActionEvent evt) { + JToggleButton src = (JToggleButton) evt.getSource(); + boolean value = src.isSelected(); + + if (src.getIcon() == null) { + if (value) { + src.setForeground(new java.awt.Color(0, 0, 0)); + src.setFont(new java.awt.Font("sansserif", 1, 13)); + } else { + src.setForeground(new java.awt.Color(204, 204, 204)); + src.setFont(new java.awt.Font("sansserif", 0, 13)); + } + } + + Logger.trace(evt.getActionCommand() + ": " + (value ? "On" : "Off")); + Integer functionNumber = Integer.decode(evt.getActionCommand().replace("F", "")); + + FunctionBean fb = this.locomotiveBean.getFunctionBean(functionNumber); + + if (!initButtons && enableEvent) { + Logger.trace("Function " + fb.getNumber() + " Value: " + fb.isOn() + " Momentary: " + fb.isMomentary()); + executor.execute(() -> changeFunction(value, functionNumber, locomotiveBean)); + } + } + + private void changeFunction(boolean newValue, Integer functionNumber, LocomotiveBean locomotiveBean) { + if (JCS.getJcsCommandStation() != null && this.locomotiveBean != null) { + FunctionBean fb = this.locomotiveBean.getFunctionBean(functionNumber); + Logger.trace("Function " + fb.getNumber() + " Value: " + fb.isOn() + " new Value: " + newValue + " Momentary: " + fb.isMomentary()); + + if (JCS.getJcsCommandStation() != null) { + JCS.getJcsCommandStation().changeLocomotiveFunction(newValue, functionNumber, locomotiveBean); + } + if (fb.isMomentary() && newValue) { + JToggleButton tb = this.buttons.get(fb.getNumber()); + tb.doClick(); + } + } + } + + /** + * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + jPanel1 = new javax.swing.JPanel(); + jPanel3 = new javax.swing.JPanel(); + speed1Button = new javax.swing.JButton(); + speed2Button = new javax.swing.JButton(); + speed3Button = new javax.swing.JButton(); + speed4Button = new javax.swing.JButton(); + jPanel4 = new javax.swing.JPanel(); + speedSlider = new javax.swing.JSlider(); + jPanel2 = new javax.swing.JPanel(); + buttonsTP = new javax.swing.JTabbedPane(); + f0f7Panel = new javax.swing.JPanel(); + f0TB = new javax.swing.JToggleButton(); + f1TB = new javax.swing.JToggleButton(); + f2TB = new javax.swing.JToggleButton(); + f3TB = new javax.swing.JToggleButton(); + f4TB = new javax.swing.JToggleButton(); + f5TB = new javax.swing.JToggleButton(); + f6TB = new javax.swing.JToggleButton(); + f7TB = new javax.swing.JToggleButton(); + f8f15Panel = new javax.swing.JPanel(); + f8TB = new javax.swing.JToggleButton(); + f9TB = new javax.swing.JToggleButton(); + f10TB = new javax.swing.JToggleButton(); + f11TB = new javax.swing.JToggleButton(); + f12TB = new javax.swing.JToggleButton(); + f13TB = new javax.swing.JToggleButton(); + f14TB = new javax.swing.JToggleButton(); + f15TB = new javax.swing.JToggleButton(); + f16f23Panel = new javax.swing.JPanel(); + f16TB = new javax.swing.JToggleButton(); + f17TB = new javax.swing.JToggleButton(); + f18TB = new javax.swing.JToggleButton(); + f19TB = new javax.swing.JToggleButton(); + f20TB = new javax.swing.JToggleButton(); + f21TB = new javax.swing.JToggleButton(); + f22TB = new javax.swing.JToggleButton(); + f23TB = new javax.swing.JToggleButton(); + f24f31Panel = new javax.swing.JPanel(); + f24TB = new javax.swing.JToggleButton(); + f25TB = new javax.swing.JToggleButton(); + f26TB = new javax.swing.JToggleButton(); + f27TB = new javax.swing.JToggleButton(); + f28TB = new javax.swing.JToggleButton(); + f29TB = new javax.swing.JToggleButton(); + f30TB = new javax.swing.JToggleButton(); + f31TB = new javax.swing.JToggleButton(); + southPanel = new javax.swing.JPanel(); + reverseButton = new javax.swing.JToggleButton(); + forwardButton = new javax.swing.JToggleButton(); + filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(30, 0), new java.awt.Dimension(30, 0), new java.awt.Dimension(30, 32767)); + stopButton = new javax.swing.JButton(); + + setMaximumSize(new java.awt.Dimension(200, 235)); + setMinimumSize(new java.awt.Dimension(200, 235)); + setName("Form"); // NOI18N + setPreferredSize(new java.awt.Dimension(300, 200)); + setLayout(new java.awt.BorderLayout()); + + jPanel1.setName("jPanel1"); // NOI18N + jPanel1.setPreferredSize(new java.awt.Dimension(80, 200)); + java.awt.FlowLayout flowLayout2 = new java.awt.FlowLayout(java.awt.FlowLayout.RIGHT, 1, 5); + flowLayout2.setAlignOnBaseline(true); + jPanel1.setLayout(flowLayout2); + + jPanel3.setName("jPanel3"); // NOI18N + jPanel3.setPreferredSize(new java.awt.Dimension(38, 200)); + jcs.ui.swing.layout.VerticalFlowLayout verticalFlowLayout1 = new jcs.ui.swing.layout.VerticalFlowLayout(); + verticalFlowLayout1.sethGap(1); + jPanel3.setLayout(verticalFlowLayout1); + + speed1Button.setText("I"); + speed1Button.setMargin(new java.awt.Insets(2, 2, 2, 2)); + speed1Button.setMinimumSize(new java.awt.Dimension(30, 30)); + speed1Button.setName("speed1Button"); // NOI18N + speed1Button.setPreferredSize(new java.awt.Dimension(30, 30)); + speed1Button.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + speed1ButtonActionPerformed(evt); + } + }); + jPanel3.add(speed1Button); + + speed2Button.setText("II"); + speed2Button.setMargin(new java.awt.Insets(2, 2, 2, 2)); + speed2Button.setMinimumSize(new java.awt.Dimension(30, 30)); + speed2Button.setName("speed2Button"); // NOI18N + speed2Button.setPreferredSize(new java.awt.Dimension(30, 30)); + speed2Button.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + speed2ButtonActionPerformed(evt); + } + }); + jPanel3.add(speed2Button); + + speed3Button.setText("III"); + speed3Button.setMargin(new java.awt.Insets(2, 2, 2, 2)); + speed3Button.setMinimumSize(new java.awt.Dimension(30, 30)); + speed3Button.setName("speed3Button"); // NOI18N + speed3Button.setPreferredSize(new java.awt.Dimension(30, 30)); + speed3Button.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + speed3ButtonActionPerformed(evt); + } + }); + jPanel3.add(speed3Button); + + speed4Button.setText("IIII"); + speed4Button.setMargin(new java.awt.Insets(2, 2, 2, 2)); + speed4Button.setMinimumSize(new java.awt.Dimension(30, 30)); + speed4Button.setName("speed4Button"); // NOI18N + speed4Button.setPreferredSize(new java.awt.Dimension(30, 30)); + speed4Button.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + speed4ButtonActionPerformed(evt); + } + }); + jPanel3.add(speed4Button); + + jPanel1.add(jPanel3); + + jPanel4.setMinimumSize(new java.awt.Dimension(40, 200)); + jPanel4.setName("jPanel4"); // NOI18N + jPanel4.setPreferredSize(new java.awt.Dimension(38, 200)); + java.awt.FlowLayout flowLayout3 = new java.awt.FlowLayout(java.awt.FlowLayout.CENTER, 1, 5); + flowLayout3.setAlignOnBaseline(true); + jPanel4.setLayout(flowLayout3); + + speedSlider.setOrientation(javax.swing.JSlider.VERTICAL); + speedSlider.setValue(0); + speedSlider.setName("speedSlider"); // NOI18N + speedSlider.setPreferredSize(new java.awt.Dimension(30, 180)); + jPanel4.add(speedSlider); + + jPanel1.add(jPanel4); + + add(jPanel1, java.awt.BorderLayout.EAST); + + jPanel2.setName("jPanel2"); // NOI18N + jPanel2.setPreferredSize(new java.awt.Dimension(220, 200)); + jPanel2.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT, 1, 5)); + + buttonsTP.setTabLayoutPolicy(javax.swing.JTabbedPane.SCROLL_TAB_LAYOUT); + buttonsTP.setTabPlacement(javax.swing.JTabbedPane.BOTTOM); + buttonsTP.setDebugGraphicsOptions(javax.swing.DebugGraphics.NONE_OPTION); + buttonsTP.setMaximumSize(new java.awt.Dimension(210, 140)); + buttonsTP.setMinimumSize(new java.awt.Dimension(210, 140)); + buttonsTP.setName("buttonsTP"); // NOI18N + buttonsTP.setPreferredSize(new java.awt.Dimension(210, 140)); + + f0f7Panel.setName("f0f7Panel"); // NOI18N + f0f7Panel.setPreferredSize(new java.awt.Dimension(165, 85)); + f0f7Panel.setLayout(new java.awt.GridLayout(2, 4, 1, 1)); + + f0TB.setBackground(new java.awt.Color(204, 204, 204)); + f0TB.setText("F0"); + f0TB.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)); + f0TB.setContentAreaFilled(false); + f0TB.setDoubleBuffered(true); + f0TB.setMaximumSize(new java.awt.Dimension(40, 40)); + f0TB.setMinimumSize(new java.awt.Dimension(40, 40)); + f0TB.setName("f0TB"); // NOI18N + f0TB.setPreferredSize(new java.awt.Dimension(40, 40)); + f0TB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + f0TBActionPerformed(evt); + } + }); + f0f7Panel.add(f0TB); + + f1TB.setText("F2"); + f1TB.setActionCommand("F1"); + f1TB.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)); + f1TB.setContentAreaFilled(false); + f1TB.setDoubleBuffered(true); + f1TB.setMaximumSize(new java.awt.Dimension(40, 40)); + f1TB.setMinimumSize(new java.awt.Dimension(40, 40)); + f1TB.setName("f1TB"); // NOI18N + f1TB.setOpaque(true); + f1TB.setPreferredSize(new java.awt.Dimension(40, 40)); + f1TB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + f1TBActionPerformed(evt); + } + }); + f0f7Panel.add(f1TB); + + f2TB.setBackground(new java.awt.Color(204, 204, 204)); + f2TB.setText("F2"); + f2TB.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)); + f2TB.setContentAreaFilled(false); + f2TB.setDoubleBuffered(true); + f2TB.setMaximumSize(new java.awt.Dimension(40, 40)); + f2TB.setMinimumSize(new java.awt.Dimension(40, 40)); + f2TB.setName("f2TB"); // NOI18N + f2TB.setOpaque(true); + f2TB.setPreferredSize(new java.awt.Dimension(40, 40)); + f2TB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + f2TBActionPerformed(evt); + } + }); + f0f7Panel.add(f2TB); + + f3TB.setBackground(new java.awt.Color(204, 204, 204)); + f3TB.setText("F3"); + f3TB.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)); + f3TB.setContentAreaFilled(false); + f3TB.setDoubleBuffered(true); + f3TB.setMaximumSize(new java.awt.Dimension(40, 40)); + f3TB.setMinimumSize(new java.awt.Dimension(40, 40)); + f3TB.setName("f3TB"); // NOI18N + f3TB.setOpaque(true); + f3TB.setPreferredSize(new java.awt.Dimension(40, 40)); + f3TB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + f3TBActionPerformed(evt); + } + }); + f0f7Panel.add(f3TB); + + f4TB.setBackground(new java.awt.Color(204, 204, 204)); + f4TB.setText("F4"); + f4TB.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)); + f4TB.setContentAreaFilled(false); + f4TB.setDoubleBuffered(true); + f4TB.setMaximumSize(new java.awt.Dimension(40, 40)); + f4TB.setMinimumSize(new java.awt.Dimension(40, 40)); + f4TB.setName("f4TB"); // NOI18N + f4TB.setPreferredSize(new java.awt.Dimension(40, 40)); + f4TB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + f4TBActionPerformed(evt); + } + }); + f0f7Panel.add(f4TB); + + f5TB.setBackground(new java.awt.Color(204, 204, 204)); + f5TB.setText("F5"); + f5TB.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)); + f5TB.setContentAreaFilled(false); + f5TB.setDoubleBuffered(true); + f5TB.setMaximumSize(new java.awt.Dimension(40, 40)); + f5TB.setMinimumSize(new java.awt.Dimension(40, 40)); + f5TB.setName("f5TB"); // NOI18N + f5TB.setPreferredSize(new java.awt.Dimension(40, 40)); + f5TB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + f5TBActionPerformed(evt); + } + }); + f0f7Panel.add(f5TB); + + f6TB.setBackground(new java.awt.Color(204, 204, 204)); + f6TB.setText("F6"); + f6TB.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)); + f6TB.setContentAreaFilled(false); + f6TB.setDoubleBuffered(true); + f6TB.setMaximumSize(new java.awt.Dimension(40, 40)); + f6TB.setMinimumSize(new java.awt.Dimension(40, 40)); + f6TB.setName("f6TB"); // NOI18N + f6TB.setPreferredSize(new java.awt.Dimension(40, 40)); + f6TB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + f6TBActionPerformed(evt); + } + }); + f0f7Panel.add(f6TB); + + f7TB.setBackground(new java.awt.Color(204, 204, 204)); + f7TB.setText("F7"); + f7TB.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)); + f7TB.setContentAreaFilled(false); + f7TB.setDoubleBuffered(true); + f7TB.setMaximumSize(new java.awt.Dimension(40, 40)); + f7TB.setMinimumSize(new java.awt.Dimension(40, 40)); + f7TB.setName("f7TB"); // NOI18N + f7TB.setPreferredSize(new java.awt.Dimension(40, 40)); + f7TB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + f7TBActionPerformed(evt); + } + }); + f0f7Panel.add(f7TB); + + buttonsTP.addTab("F0 - F7", f0f7Panel); + + f8f15Panel.setName("f8f15Panel"); // NOI18N + f8f15Panel.setPreferredSize(new java.awt.Dimension(165, 165)); + f8f15Panel.setLayout(new java.awt.GridLayout(2, 4, 1, 1)); + + f8TB.setBackground(new java.awt.Color(204, 204, 204)); + f8TB.setText("F8"); + f8TB.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)); + f8TB.setContentAreaFilled(false); + f8TB.setDoubleBuffered(true); + f8TB.setMaximumSize(new java.awt.Dimension(40, 40)); + f8TB.setMinimumSize(new java.awt.Dimension(40, 40)); + f8TB.setName("f8TB"); // NOI18N + f8TB.setPreferredSize(new java.awt.Dimension(40, 40)); + f8TB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + f8TBActionPerformed(evt); + } + }); + f8f15Panel.add(f8TB); + + f9TB.setBackground(new java.awt.Color(204, 204, 204)); + f9TB.setText("F9"); + f9TB.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)); + f9TB.setContentAreaFilled(false); + f9TB.setDoubleBuffered(true); + f9TB.setMaximumSize(new java.awt.Dimension(40, 40)); + f9TB.setMinimumSize(new java.awt.Dimension(40, 40)); + f9TB.setName("f9TB"); // NOI18N + f9TB.setPreferredSize(new java.awt.Dimension(40, 40)); + f9TB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + f9TBActionPerformed(evt); + } + }); + f8f15Panel.add(f9TB); + + f10TB.setBackground(new java.awt.Color(204, 204, 204)); + f10TB.setText("F10"); + f10TB.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)); + f10TB.setContentAreaFilled(false); + f10TB.setDoubleBuffered(true); + f10TB.setMargin(new java.awt.Insets(2, 2, 2, 2)); + f10TB.setMaximumSize(new java.awt.Dimension(40, 40)); + f10TB.setMinimumSize(new java.awt.Dimension(40, 40)); + f10TB.setName("f10TB"); // NOI18N + f10TB.setPreferredSize(new java.awt.Dimension(40, 40)); + f10TB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + f10TBActionPerformed(evt); + } + }); + f8f15Panel.add(f10TB); + + f11TB.setBackground(new java.awt.Color(204, 204, 204)); + f11TB.setText("F11"); + f11TB.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)); + f11TB.setContentAreaFilled(false); + f11TB.setDoubleBuffered(true); + f11TB.setMargin(new java.awt.Insets(2, 2, 2, 2)); + f11TB.setMaximumSize(new java.awt.Dimension(40, 40)); + f11TB.setMinimumSize(new java.awt.Dimension(40, 40)); + f11TB.setName("f11TB"); // NOI18N + f11TB.setPreferredSize(new java.awt.Dimension(40, 40)); + f11TB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + f11TBActionPerformed(evt); + } + }); + f8f15Panel.add(f11TB); + + f12TB.setBackground(new java.awt.Color(204, 204, 204)); + f12TB.setText("F12"); + f12TB.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)); + f12TB.setContentAreaFilled(false); + f12TB.setDoubleBuffered(true); + f12TB.setMargin(new java.awt.Insets(2, 2, 2, 2)); + f12TB.setMaximumSize(new java.awt.Dimension(40, 40)); + f12TB.setMinimumSize(new java.awt.Dimension(40, 40)); + f12TB.setName("f12TB"); // NOI18N + f12TB.setPreferredSize(new java.awt.Dimension(40, 40)); + f12TB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + f12TBActionPerformed(evt); + } + }); + f8f15Panel.add(f12TB); + + f13TB.setBackground(new java.awt.Color(204, 204, 204)); + f13TB.setText("F13"); + f13TB.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)); + f13TB.setContentAreaFilled(false); + f13TB.setDoubleBuffered(true); + f13TB.setMargin(new java.awt.Insets(2, 2, 2, 2)); + f13TB.setMaximumSize(new java.awt.Dimension(40, 40)); + f13TB.setMinimumSize(new java.awt.Dimension(40, 40)); + f13TB.setName("f13TB"); // NOI18N + f13TB.setPreferredSize(new java.awt.Dimension(40, 40)); + f13TB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + f13TBActionPerformed(evt); + } + }); + f8f15Panel.add(f13TB); + + f14TB.setBackground(new java.awt.Color(204, 204, 204)); + f14TB.setText("F14"); + f14TB.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)); + f14TB.setContentAreaFilled(false); + f14TB.setDoubleBuffered(true); + f14TB.setMargin(new java.awt.Insets(2, 2, 2, 2)); + f14TB.setMaximumSize(new java.awt.Dimension(40, 40)); + f14TB.setMinimumSize(new java.awt.Dimension(40, 40)); + f14TB.setName("f14TB"); // NOI18N + f14TB.setPreferredSize(new java.awt.Dimension(40, 40)); + f14TB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + f14TBActionPerformed(evt); + } + }); + f8f15Panel.add(f14TB); + + f15TB.setBackground(new java.awt.Color(204, 204, 204)); + f15TB.setText("F15"); + f15TB.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)); + f15TB.setContentAreaFilled(false); + f15TB.setDoubleBuffered(true); + f15TB.setMargin(new java.awt.Insets(2, 2, 2, 2)); + f15TB.setMaximumSize(new java.awt.Dimension(40, 40)); + f15TB.setMinimumSize(new java.awt.Dimension(40, 40)); + f15TB.setName("f15TB"); // NOI18N + f15TB.setPreferredSize(new java.awt.Dimension(40, 40)); + f15TB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + f15TBActionPerformed(evt); + } + }); + f8f15Panel.add(f15TB); + + buttonsTP.addTab("F16 - F23", f8f15Panel); + + f16f23Panel.setName("f16f23Panel"); // NOI18N + f16f23Panel.setLayout(new java.awt.GridLayout(2, 4, 1, 1)); + + f16TB.setBackground(new java.awt.Color(204, 204, 204)); + f16TB.setText("F16"); + f16TB.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)); + f16TB.setContentAreaFilled(false); + f16TB.setDoubleBuffered(true); + f16TB.setMargin(new java.awt.Insets(2, 2, 2, 2)); + f16TB.setMaximumSize(new java.awt.Dimension(40, 40)); + f16TB.setMinimumSize(new java.awt.Dimension(40, 40)); + f16TB.setName("f16TB"); // NOI18N + f16TB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + f16TBActionPerformed(evt); + } + }); + f16f23Panel.add(f16TB); + + f17TB.setBackground(new java.awt.Color(204, 204, 204)); + f17TB.setText("F17"); + f17TB.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)); + f17TB.setContentAreaFilled(false); + f17TB.setDoubleBuffered(true); + f17TB.setMargin(new java.awt.Insets(2, 2, 2, 2)); + f17TB.setMaximumSize(new java.awt.Dimension(40, 40)); + f17TB.setMinimumSize(new java.awt.Dimension(40, 40)); + f17TB.setName("f17TB"); // NOI18N + f17TB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + f17TBActionPerformed(evt); + } + }); + f16f23Panel.add(f17TB); + + f18TB.setBackground(new java.awt.Color(204, 204, 204)); + f18TB.setText("F18"); + f18TB.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)); + f18TB.setContentAreaFilled(false); + f18TB.setDoubleBuffered(true); + f18TB.setMargin(new java.awt.Insets(2, 2, 2, 2)); + f18TB.setMaximumSize(new java.awt.Dimension(40, 40)); + f18TB.setMinimumSize(new java.awt.Dimension(40, 40)); + f18TB.setName("f18TB"); // NOI18N + f18TB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + f18TBActionPerformed(evt); + } + }); + f16f23Panel.add(f18TB); + + f19TB.setBackground(new java.awt.Color(204, 204, 204)); + f19TB.setText("F19"); + f19TB.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)); + f19TB.setContentAreaFilled(false); + f19TB.setDoubleBuffered(true); + f19TB.setMargin(new java.awt.Insets(2, 2, 2, 2)); + f19TB.setMaximumSize(new java.awt.Dimension(40, 40)); + f19TB.setMinimumSize(new java.awt.Dimension(40, 40)); + f19TB.setName("f19TB"); // NOI18N + f19TB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + f19TBActionPerformed(evt); + } + }); + f16f23Panel.add(f19TB); + + f20TB.setBackground(new java.awt.Color(204, 204, 204)); + f20TB.setText("F20"); + f20TB.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)); + f20TB.setContentAreaFilled(false); + f20TB.setDoubleBuffered(true); + f20TB.setMargin(new java.awt.Insets(2, 2, 2, 2)); + f20TB.setMaximumSize(new java.awt.Dimension(40, 40)); + f20TB.setMinimumSize(new java.awt.Dimension(40, 40)); + f20TB.setName("f20TB"); // NOI18N + f20TB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + f20TBActionPerformed(evt); + } + }); + f16f23Panel.add(f20TB); + + f21TB.setBackground(new java.awt.Color(204, 204, 204)); + f21TB.setText("F21"); + f21TB.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)); + f21TB.setContentAreaFilled(false); + f21TB.setDoubleBuffered(true); + f21TB.setMargin(new java.awt.Insets(2, 2, 2, 2)); + f21TB.setMaximumSize(new java.awt.Dimension(40, 40)); + f21TB.setMinimumSize(new java.awt.Dimension(40, 40)); + f21TB.setName("f21TB"); // NOI18N + f21TB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + f21TBActionPerformed(evt); + } + }); + f16f23Panel.add(f21TB); + + f22TB.setBackground(new java.awt.Color(204, 204, 204)); + f22TB.setText("F22"); + f22TB.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)); + f22TB.setContentAreaFilled(false); + f22TB.setDoubleBuffered(true); + f22TB.setMargin(new java.awt.Insets(2, 2, 2, 2)); + f22TB.setMaximumSize(new java.awt.Dimension(40, 40)); + f22TB.setMinimumSize(new java.awt.Dimension(40, 40)); + f22TB.setName("f22TB"); // NOI18N + f22TB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + f22TBActionPerformed(evt); + } + }); + f16f23Panel.add(f22TB); + + f23TB.setBackground(new java.awt.Color(204, 204, 204)); + f23TB.setText("F23"); + f23TB.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)); + f23TB.setContentAreaFilled(false); + f23TB.setDoubleBuffered(true); + f23TB.setMargin(new java.awt.Insets(2, 2, 2, 2)); + f23TB.setMaximumSize(new java.awt.Dimension(40, 40)); + f23TB.setMinimumSize(new java.awt.Dimension(40, 40)); + f23TB.setName("f23TB"); // NOI18N + f23TB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + f23TBActionPerformed(evt); + } + }); + f16f23Panel.add(f23TB); + + buttonsTP.addTab("F8 - F15", f16f23Panel); + + f24f31Panel.setName("f24f31Panel"); // NOI18N + f24f31Panel.setLayout(new java.awt.GridLayout(2, 4, 1, 1)); + + f24TB.setBackground(new java.awt.Color(204, 204, 204)); + f24TB.setText("F24"); + f24TB.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)); + f24TB.setContentAreaFilled(false); + f24TB.setDoubleBuffered(true); + f24TB.setMargin(new java.awt.Insets(2, 2, 2, 2)); + f24TB.setMaximumSize(new java.awt.Dimension(40, 40)); + f24TB.setMinimumSize(new java.awt.Dimension(40, 40)); + f24TB.setName("f24TB"); // NOI18N + f24TB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + f24TBActionPerformed(evt); + } + }); + f24f31Panel.add(f24TB); + + f25TB.setBackground(new java.awt.Color(204, 204, 204)); + f25TB.setText("F25"); + f25TB.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)); + f25TB.setContentAreaFilled(false); + f25TB.setDoubleBuffered(true); + f25TB.setMargin(new java.awt.Insets(2, 2, 2, 2)); + f25TB.setMaximumSize(new java.awt.Dimension(40, 40)); + f25TB.setMinimumSize(new java.awt.Dimension(40, 40)); + f25TB.setName("f25TB"); // NOI18N + f25TB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + f25TBActionPerformed(evt); + } + }); + f24f31Panel.add(f25TB); + + f26TB.setBackground(new java.awt.Color(204, 204, 204)); + f26TB.setText("F26"); + f26TB.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)); + f26TB.setContentAreaFilled(false); + f26TB.setDoubleBuffered(true); + f26TB.setMargin(new java.awt.Insets(2, 2, 2, 2)); + f26TB.setMaximumSize(new java.awt.Dimension(40, 40)); + f26TB.setMinimumSize(new java.awt.Dimension(40, 40)); + f26TB.setName("f26TB"); // NOI18N + f26TB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + f26TBActionPerformed(evt); + } + }); + f24f31Panel.add(f26TB); + + f27TB.setBackground(new java.awt.Color(204, 204, 204)); + f27TB.setText("F27"); + f27TB.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)); + f27TB.setContentAreaFilled(false); + f27TB.setDoubleBuffered(true); + f27TB.setMargin(new java.awt.Insets(2, 2, 2, 2)); + f27TB.setMaximumSize(new java.awt.Dimension(40, 40)); + f27TB.setMinimumSize(new java.awt.Dimension(40, 40)); + f27TB.setName("f27TB"); // NOI18N + f27TB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + f27TBActionPerformed(evt); + } + }); + f24f31Panel.add(f27TB); + + f28TB.setBackground(new java.awt.Color(204, 204, 204)); + f28TB.setText("F28"); + f28TB.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)); + f28TB.setContentAreaFilled(false); + f28TB.setDoubleBuffered(true); + f28TB.setMargin(new java.awt.Insets(2, 2, 2, 2)); + f28TB.setMaximumSize(new java.awt.Dimension(40, 40)); + f28TB.setMinimumSize(new java.awt.Dimension(40, 40)); + f28TB.setName("f28TB"); // NOI18N + f28TB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + f28TBActionPerformed(evt); + } + }); + f24f31Panel.add(f28TB); + + f29TB.setBackground(new java.awt.Color(204, 204, 204)); + f29TB.setText("F29"); + f29TB.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)); + f29TB.setContentAreaFilled(false); + f29TB.setDoubleBuffered(true); + f29TB.setMargin(new java.awt.Insets(2, 2, 2, 2)); + f29TB.setMaximumSize(new java.awt.Dimension(40, 40)); + f29TB.setMinimumSize(new java.awt.Dimension(40, 40)); + f29TB.setName("f29TB"); // NOI18N + f29TB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + f29TBActionPerformed(evt); + } + }); + f24f31Panel.add(f29TB); + + f30TB.setBackground(new java.awt.Color(204, 204, 204)); + f30TB.setText("F30"); + f30TB.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)); + f30TB.setContentAreaFilled(false); + f30TB.setDoubleBuffered(true); + f30TB.setMargin(new java.awt.Insets(2, 2, 2, 2)); + f30TB.setMaximumSize(new java.awt.Dimension(40, 40)); + f30TB.setMinimumSize(new java.awt.Dimension(40, 40)); + f30TB.setName("f30TB"); // NOI18N + f30TB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + f30TBActionPerformed(evt); + } + }); + f24f31Panel.add(f30TB); + + f31TB.setBackground(new java.awt.Color(204, 204, 204)); + f31TB.setText("F31"); + f31TB.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)); + f31TB.setContentAreaFilled(false); + f31TB.setDoubleBuffered(true); + f31TB.setMargin(new java.awt.Insets(2, 2, 2, 2)); + f31TB.setMaximumSize(new java.awt.Dimension(40, 40)); + f31TB.setMinimumSize(new java.awt.Dimension(40, 40)); + f31TB.setName("f31TB"); // NOI18N + f31TB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + f31TBActionPerformed(evt); + } + }); + f24f31Panel.add(f31TB); + + buttonsTP.addTab("F24 - F31", f24f31Panel); + + jPanel2.add(buttonsTP); + + southPanel.setMinimumSize(new java.awt.Dimension(300, 50)); + southPanel.setName("southPanel"); // NOI18N + southPanel.setPreferredSize(new java.awt.Dimension(300, 50)); + java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); + flowLayout1.setAlignOnBaseline(true); + southPanel.setLayout(flowLayout1); + + reverseButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/media/left-24.png"))); // NOI18N + reverseButton.setActionCommand("Backwards"); + reverseButton.setName("reverseButton"); // NOI18N + reverseButton.setSelectedIcon(new javax.swing.ImageIcon(getClass().getResource("/media/left-Y-24.png"))); // NOI18N + reverseButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + reverseButtonActionPerformed(evt); + } + }); + southPanel.add(reverseButton); + + forwardButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/media/right-24.png"))); // NOI18N + forwardButton.setSelected(true); + forwardButton.setActionCommand("Forwards"); + forwardButton.setName("forwardButton"); // NOI18N + forwardButton.setSelectedIcon(new javax.swing.ImageIcon(getClass().getResource("/media/right-Y-24.png"))); // NOI18N + forwardButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + forwardButtonActionPerformed(evt); + } + }); + southPanel.add(forwardButton); + + filler1.setName("filler1"); // NOI18N + southPanel.add(filler1); + + stopButton.setText("Stop"); + stopButton.setMinimumSize(new java.awt.Dimension(75, 30)); + stopButton.setName("stopButton"); // NOI18N + stopButton.setPreferredSize(new java.awt.Dimension(75, 30)); + stopButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + stopButtonActionPerformed(evt); + } + }); + southPanel.add(stopButton); + + jPanel2.add(southPanel); + + add(jPanel2, java.awt.BorderLayout.CENTER); + }// //GEN-END:initComponents + + private void f12TBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_f12TBActionPerformed + buttonActionPerformed(evt); + }//GEN-LAST:event_f12TBActionPerformed + + private void f16TBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_f16TBActionPerformed + buttonActionPerformed(evt); + }//GEN-LAST:event_f16TBActionPerformed + + private void f28TBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_f28TBActionPerformed + buttonActionPerformed(evt); + }//GEN-LAST:event_f28TBActionPerformed + + private void f0TBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_f0TBActionPerformed + buttonActionPerformed(evt); + }//GEN-LAST:event_f0TBActionPerformed + + private void f1TBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_f1TBActionPerformed + buttonActionPerformed(evt); + }//GEN-LAST:event_f1TBActionPerformed + + private void f2TBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_f2TBActionPerformed + buttonActionPerformed(evt); + }//GEN-LAST:event_f2TBActionPerformed + + private void f3TBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_f3TBActionPerformed + buttonActionPerformed(evt); + }//GEN-LAST:event_f3TBActionPerformed + + private void f4TBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_f4TBActionPerformed + buttonActionPerformed(evt); + }//GEN-LAST:event_f4TBActionPerformed + + private void f5TBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_f5TBActionPerformed + buttonActionPerformed(evt); + }//GEN-LAST:event_f5TBActionPerformed + + private void f6TBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_f6TBActionPerformed + buttonActionPerformed(evt); + }//GEN-LAST:event_f6TBActionPerformed + + private void f7TBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_f7TBActionPerformed + buttonActionPerformed(evt); + }//GEN-LAST:event_f7TBActionPerformed + + private void f8TBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_f8TBActionPerformed + buttonActionPerformed(evt); + }//GEN-LAST:event_f8TBActionPerformed + + private void f9TBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_f9TBActionPerformed + buttonActionPerformed(evt); + }//GEN-LAST:event_f9TBActionPerformed + + private void f10TBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_f10TBActionPerformed + buttonActionPerformed(evt); + }//GEN-LAST:event_f10TBActionPerformed + + private void f11TBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_f11TBActionPerformed + buttonActionPerformed(evt); + }//GEN-LAST:event_f11TBActionPerformed + + private void f13TBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_f13TBActionPerformed + buttonActionPerformed(evt); + }//GEN-LAST:event_f13TBActionPerformed + + private void f14TBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_f14TBActionPerformed + buttonActionPerformed(evt); + }//GEN-LAST:event_f14TBActionPerformed + + private void f15TBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_f15TBActionPerformed + buttonActionPerformed(evt); + }//GEN-LAST:event_f15TBActionPerformed + + private void f17TBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_f17TBActionPerformed + buttonActionPerformed(evt); + }//GEN-LAST:event_f17TBActionPerformed + + private void f18TBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_f18TBActionPerformed + buttonActionPerformed(evt); + }//GEN-LAST:event_f18TBActionPerformed + + private void f19TBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_f19TBActionPerformed + buttonActionPerformed(evt); + }//GEN-LAST:event_f19TBActionPerformed + + private void f20TBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_f20TBActionPerformed + buttonActionPerformed(evt); + }//GEN-LAST:event_f20TBActionPerformed + + private void f21TBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_f21TBActionPerformed + buttonActionPerformed(evt); + }//GEN-LAST:event_f21TBActionPerformed + + private void f22TBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_f22TBActionPerformed + buttonActionPerformed(evt); + }//GEN-LAST:event_f22TBActionPerformed + + private void f23TBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_f23TBActionPerformed + buttonActionPerformed(evt); + }//GEN-LAST:event_f23TBActionPerformed + + private void f24TBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_f24TBActionPerformed + buttonActionPerformed(evt); + }//GEN-LAST:event_f24TBActionPerformed + + private void f25TBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_f25TBActionPerformed + buttonActionPerformed(evt); + }//GEN-LAST:event_f25TBActionPerformed + + private void f26TBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_f26TBActionPerformed + buttonActionPerformed(evt); + }//GEN-LAST:event_f26TBActionPerformed + + private void f27TBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_f27TBActionPerformed + buttonActionPerformed(evt); + }//GEN-LAST:event_f27TBActionPerformed + + private void f29TBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_f29TBActionPerformed + buttonActionPerformed(evt); + }//GEN-LAST:event_f29TBActionPerformed + + private void f30TBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_f30TBActionPerformed + buttonActionPerformed(evt); + }//GEN-LAST:event_f30TBActionPerformed + + private void f31TBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_f31TBActionPerformed + buttonActionPerformed(evt); + }//GEN-LAST:event_f31TBActionPerformed + + private void speed1ButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_speed1ButtonActionPerformed + if (this.locomotiveBean != null) { + int tachoMax = locomotiveBean.getTachoMax(); + tachoMax = tachoMax / 5; // 20 % + this.speedSlider.setValue(tachoMax); + } else { + Logger.trace(evt.getActionCommand()); + } + }//GEN-LAST:event_speed1ButtonActionPerformed + + private void speed2ButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_speed2ButtonActionPerformed + if (this.locomotiveBean != null) { + int tachoMax = locomotiveBean.getTachoMax(); + tachoMax = (tachoMax / 5) * 2; // 40 % + this.speedSlider.setValue(tachoMax); + } else { + Logger.trace(evt.getActionCommand()); + } + }//GEN-LAST:event_speed2ButtonActionPerformed + + private void speed3ButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_speed3ButtonActionPerformed + if (this.locomotiveBean != null) { + int tachoMax = locomotiveBean.getTachoMax(); + tachoMax = (tachoMax / 5) * 3; // 60 % + this.speedSlider.setValue(tachoMax); + } else { + Logger.trace(evt.getActionCommand()); + } + }//GEN-LAST:event_speed3ButtonActionPerformed + + private void speed4ButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_speed4ButtonActionPerformed + if (this.locomotiveBean != null) { + int tachoMax = locomotiveBean.getTachoMax(); + tachoMax = (tachoMax / 5) * 4; // 80 % + this.speedSlider.setValue(tachoMax); + } else { + Logger.trace(evt.getActionCommand()); + } + }//GEN-LAST:event_speed4ButtonActionPerformed + + private void reverseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_reverseButtonActionPerformed + if (!disableListener) { + changeDirection(LocomotiveBean.Direction.get(evt.getActionCommand())); + } + }//GEN-LAST:event_reverseButtonActionPerformed + + private void forwardButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_forwardButtonActionPerformed + if (!disableListener) { + changeDirection(LocomotiveBean.Direction.get(evt.getActionCommand())); + } + }//GEN-LAST:event_forwardButtonActionPerformed + + private void stopButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_stopButtonActionPerformed + this.speedSlider.setValue(0); + if (this.locomotiveBean == null) { + Logger.trace(evt.getActionCommand()); + } + }//GEN-LAST:event_stopButtonActionPerformed + + private void changeDirection(LocomotiveBean.Direction direction) { + changeDirection(direction, this.locomotiveBean); + } + + private void changeDirection(LocomotiveBean.Direction newDirection, LocomotiveBean locomotiveBean) { + if (JCS.getJcsCommandStation() != null && locomotiveBean != null && locomotiveBean.getId() != null) { + Logger.trace("Changing direction of " + locomotiveBean + " to: " + newDirection); + JCS.getJcsCommandStation().changeLocomotiveDirection(newDirection, locomotiveBean); + } + +// if (this.directionListener != null && locomotiveBean != null) { +// LocomotiveDirectionEvent dme = new LocomotiveDirectionEvent(locomotiveBean); +// this.directionListener.onDirectionChange(dme); +// } + } + + @Override + public void onDirectionChange(LocomotiveDirectionEvent event) { + LocomotiveBean lb = event.getLocomotiveBean(); + Logger.trace("Evt: id: " + lb.getId() + " Addr: " + lb.getAddress() + " cid: " + lb.getCommandStationId() + " dir: " + lb.getDirection()); + + if (event.isEventFor(locomotiveBean)) { + Logger.trace(lb.getName() + " direction changed from " + this.locomotiveBean.getDirection() + " to " + lb.getDirection()); + + //locomotiveBean.setRichtung(lb.getRichtung()); + locomotiveBean.setDirection(lb.getDirection()); + + disableListener = true; + if (LocomotiveBean.Direction.BACKWARDS.equals(lb.getDirection())) { + this.reverseButton.setSelected(true); + } else { + this.forwardButton.setSelected(true); + } + disableListener = false; +// if (this.directionListener != null) { +// this.directionListener.onDirectionChange(event); +// } + } + } + + @Override + public void onSpeedChange(LocomotiveSpeedEvent event) { + LocomotiveBean lb = event.getLocomotiveBean(); + + if (event.isEventFor(locomotiveBean)) { + Logger.trace(lb.getName() + " Speed changed from " + this.locomotiveBean.getVelocity() + " to " + lb.getVelocity()); + + locomotiveBean.setVelocity(lb.getVelocity()); + + int velocity = locomotiveBean.getVelocity(); + double max = locomotiveBean.getTachoMax(); + int sliderValue = (int) Math.round(max / 1000 * velocity); + + //set the slider value without triggering a change event + ChangeListener[] changeListeners = this.speedSlider.getChangeListeners(); + for (ChangeListener changeListener : changeListeners) { + this.speedSlider.removeChangeListener(changeListener); + } + + this.speedSlider.setValue(sliderValue); + + //max = this.speedGauge.getMaxValue(); + double gaugeValue = Math.round(max / 1000 * velocity); + //this.speedGauge.setValue(gaugeValue); +// this.speedGauge.setValueAnimated(gaugeValue); + +// this.speedGauge.setUserLedOn(this.power); +// this.speedGauge.setLedBlinking(!this.power); + for (ChangeListener changeListener : changeListeners) { + this.speedSlider.addChangeListener(changeListener); + } + + } + } + + @Override + public void onPowerChange(PowerEvent event) { + if (this.locomotiveBean != null) { + this.power = event.isPower(); + + //this.speedGauge.setUserLedOn(this.power); + //this.speedGauge.setLedBlinking(!this.power); + Logger.trace("Power is " + this.power); + } + } + + public static void main(String args[]) { + try { + UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { + Logger.error("Can't set the LookAndFeel: " + ex); + } + java.awt.EventQueue.invokeLater(() -> { + + SmallDriverCabPanel testPanel = new SmallDriverCabPanel(); + JFrame testFrame = new JFrame("FunctionsPanel Tester"); + + testFrame.add(testPanel); + + testFrame.addWindowListener(new java.awt.event.WindowAdapter() { + @Override + public void windowClosing(java.awt.event.WindowEvent e) { + System.exit(0); + } + }); + testFrame.pack(); + testFrame.setLocationRelativeTo(null); + + if (JCS.getJcsCommandStation() != null) { + + //LocomotiveBean loc = PersistenceFactory.getService().getLocomotive(49189L); + LocomotiveBean loc = PersistenceFactory.getService().getLocomotive(1001L); + Logger.debug(loc); + + testPanel.setLocomotiveBean(loc); + + } + + testFrame.setVisible(true); + }); + } + + + // Variables declaration - do not modify//GEN-BEGIN:variables + javax.swing.JTabbedPane buttonsTP; + javax.swing.JToggleButton f0TB; + javax.swing.JPanel f0f7Panel; + javax.swing.JToggleButton f10TB; + javax.swing.JToggleButton f11TB; + javax.swing.JToggleButton f12TB; + javax.swing.JToggleButton f13TB; + javax.swing.JToggleButton f14TB; + javax.swing.JToggleButton f15TB; + javax.swing.JToggleButton f16TB; + javax.swing.JPanel f16f23Panel; + javax.swing.JToggleButton f17TB; + javax.swing.JToggleButton f18TB; + javax.swing.JToggleButton f19TB; + javax.swing.JToggleButton f1TB; + javax.swing.JToggleButton f20TB; + javax.swing.JToggleButton f21TB; + javax.swing.JToggleButton f22TB; + javax.swing.JToggleButton f23TB; + javax.swing.JToggleButton f24TB; + javax.swing.JPanel f24f31Panel; + javax.swing.JToggleButton f25TB; + javax.swing.JToggleButton f26TB; + javax.swing.JToggleButton f27TB; + javax.swing.JToggleButton f28TB; + javax.swing.JToggleButton f29TB; + javax.swing.JToggleButton f2TB; + javax.swing.JToggleButton f30TB; + javax.swing.JToggleButton f31TB; + javax.swing.JToggleButton f3TB; + javax.swing.JToggleButton f4TB; + javax.swing.JToggleButton f5TB; + javax.swing.JToggleButton f6TB; + javax.swing.JToggleButton f7TB; + javax.swing.JToggleButton f8TB; + javax.swing.JPanel f8f15Panel; + javax.swing.JToggleButton f9TB; + javax.swing.Box.Filler filler1; + javax.swing.JToggleButton forwardButton; + javax.swing.JPanel jPanel1; + javax.swing.JPanel jPanel2; + javax.swing.JPanel jPanel3; + javax.swing.JPanel jPanel4; + javax.swing.JToggleButton reverseButton; + javax.swing.JPanel southPanel; + javax.swing.JButton speed1Button; + javax.swing.JButton speed2Button; + javax.swing.JButton speed3Button; + javax.swing.JButton speed4Button; + javax.swing.JSlider speedSlider; + javax.swing.JButton stopButton; + // End of variables declaration//GEN-END:variables +} diff --git a/src/main/java/jcs/ui/TurnoutsPanel.form b/src/main/java/jcs/ui/panel/TurnoutsPanel.form similarity index 100% rename from src/main/java/jcs/ui/TurnoutsPanel.form rename to src/main/java/jcs/ui/panel/TurnoutsPanel.form diff --git a/src/main/java/jcs/ui/TurnoutsPanel.java b/src/main/java/jcs/ui/panel/TurnoutsPanel.java similarity index 81% rename from src/main/java/jcs/ui/TurnoutsPanel.java rename to src/main/java/jcs/ui/panel/TurnoutsPanel.java index f0aa31c6..a2729e5e 100755 --- a/src/main/java/jcs/ui/TurnoutsPanel.java +++ b/src/main/java/jcs/ui/panel/TurnoutsPanel.java @@ -16,7 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ -package jcs.ui; +package jcs.ui.panel; import java.awt.GridLayout; import java.net.URL; @@ -28,6 +28,7 @@ import jcs.JCS; import jcs.entities.AccessoryBean; import jcs.persistence.PersistenceFactory; +import jcs.ui.KeyboardSensorPanel; import jcs.ui.widgets.TurnoutRowPanel; import org.tinylog.Logger; @@ -84,25 +85,25 @@ public void refreshPanel() { * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") - // //GEN-BEGIN:initComponents - private void initComponents() { - - setPreferredSize(new java.awt.Dimension(1024, 805)); - - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); - this.setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 400, Short.MAX_VALUE) - ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 300, Short.MAX_VALUE) - ); - }// //GEN-END:initComponents - - // Variables declaration - do not modify//GEN-BEGIN:variables - // End of variables declaration//GEN-END:variables + // //GEN-BEGIN:initComponents + private void initComponents() { + + setPreferredSize(new java.awt.Dimension(1024, 805)); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 400, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 300, Short.MAX_VALUE) + ); + }// //GEN-END:initComponents + + // Variables declaration - do not modify//GEN-BEGIN:variables + // End of variables declaration//GEN-END:variables //Testing public static void main(String args[]) { diff --git a/src/main/java/jcs/ui/swing/layout/HBox.java b/src/main/java/jcs/ui/swing/layout/HBox.java deleted file mode 100644 index d99b9418..00000000 --- a/src/main/java/jcs/ui/swing/layout/HBox.java +++ /dev/null @@ -1,160 +0,0 @@ -/* -* Copyright 2018 Frederik Wiers -* -* Permission is hereby granted, free of charge, to any person obtaining a -* copy of this software and associated documentation files (the -* "Software"), to deal in the Software without restriction, including -* without limitation the rights to use, copy, modify, merge, publish, -* distribute, sublicense, and/or sell copies of the Software, and to -* permit persons to whom the Software is furnished to do so, subject to -* the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -package jcs.ui.swing.layout; - -import java.awt.Component; -import java.awt.Dimension; -import java.awt.Rectangle; - -import javax.swing.JComponent; -import javax.swing.Scrollable; - -/** - * A container that lays out components horizontally. This container can be placed inside a scroller. Use the appropriate - * constructor methods to layout components left to right, right to left or in the middle. Note that this container can be placed - * inside another container. E.g. to have a button at the left and the right, do something like: {@code HBox line = new HBox();} - *
{@code HBox left = new HBox();} - *
{@code left.add(Button);} - *
{@code HBox right = new HBox(HBox.OPPOSITELINEAXIS);} - *
{@code right.add(Button);} - *
{@code line.add(left);} - *
{@code line.add(right);} - *
{@code form.add(line);} - * - * @author Fred - * - */ -public class HBox extends JComponent implements Scrollable { - - private static final long serialVersionUID = 7841775222423395208L; - - /** - * See {@link HVLayout#LEADING} - */ - public static final int LEADING = HVLayout.LEADING; // 10 - /** - * See {@link HVLayout#TRAILING} - */ - public static final int TRAILING = HVLayout.TRAILING; // 11 - /** - * See {@link HVLayout#CENTER} - */ - public static final int CENTER = HVLayout.CENTER; // 0 - - public HBox() { - this(null, LEADING); - } - - public HBox(HVSize props) { - this(props, LEADING); - } - - public HBox(int orientation) { - this(null, orientation); - } - - /** - * Constructor to layout components horizontally. - * - * @param props If null, {@link HVSize#getDefault()} is used. - * @param orientation Either {@link #LEADING} (normal reading direction), {@link #CENTER} (layout in the middle) or - * {@link #TRAILING} (reverse reading direction). - */ - public HBox(HVSize props, int orientation) { - super(); - super.setLayout(new HLayout(props, orientation)); - } - - @Override - public HLayout getLayout() { - return (HLayout) super.getLayout(); - } - - public void setHvConf(HVSize props) { - getLayout().setHvprops(props); - } - - public HVSize getHvConf() { - return getLayout().getHvprops(); - } - - /** - * To accomodate a scroller. - */ - @Override - public Dimension getPreferredScrollableViewportSize() { - return this.getPreferredSize(); - } - - /** - * To accomodate a scroller. - */ - @Override - public int getScrollableUnitIncrement(final Rectangle arg0, final int arg1, final int arg2) { - return getHvConf().getLineHeightNoDepth(); - } - - /** - * To accomodate a scroller. - */ - @Override - public int getScrollableBlockIncrement(final Rectangle arg0, final int arg1, - final int arg2) { - return getHvConf().getLineHeightNoDepth(); - } - - /** - * To accomodate a scroller. - */ - @Override - public boolean getScrollableTracksViewportWidth() { - if (this.getParent().getWidth() > this.getMinimumSize().width) { - return true; - } - return false; - } - - /** - * To accomodate a scroller. - */ - @Override - public boolean getScrollableTracksViewportHeight() { - if (this.getParent().getHeight() > this.getMinimumSize().height) { - return true; - } - return false; - } - - /** - * This (overloaded) convenience method allows adding components in the middle of a list of components (at the place indicated by - * index). - * - * @param index if -1 component is added at he end of the components-list. - * @see java.awt.Container#add(java.awt.Component, Object, int) - */ - @Override - public Component add(final Component comp, final int index) { - super.add(comp, Integer.valueOf(index), index); - return comp; - } -} diff --git a/src/main/java/jcs/ui/swing/layout/VBox.java b/src/main/java/jcs/ui/swing/layout/VBox.java deleted file mode 100644 index 72532f58..00000000 --- a/src/main/java/jcs/ui/swing/layout/VBox.java +++ /dev/null @@ -1,147 +0,0 @@ -/* -* Copyright 2018 Frederik Wiers -* -* Permission is hereby granted, free of charge, to any person obtaining a -* copy of this software and associated documentation files (the -* "Software"), to deal in the Software without restriction, including -* without limitation the rights to use, copy, modify, merge, publish, -* distribute, sublicense, and/or sell copies of the Software, and to -* permit persons to whom the Software is furnished to do so, subject to -* the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -package jcs.ui.swing.layout; - -import java.awt.Component; -import java.awt.Dimension; -import java.awt.Insets; -import java.awt.Rectangle; - -import javax.swing.JComponent; -import javax.swing.Scrollable; -import javax.swing.border.EmptyBorder; - -/** - * A container that lays out components vertically (top to bottom). This container can be placed inside a scroller. - */ -public class VBox extends JComponent implements Scrollable { - - private static final long serialVersionUID = -5778892883397662105L; - - /** - * Constructs a container that that lays out components from top to bottom, has no border and uses the - * {@link HVSize#getDefault()}. - */ - public VBox() { - this(null, null); - } - - /** - * Constructs a container that that lays out components from top to bottom, has no border. - */ - public VBox(HVSize props) { - this(props, null); - } - - public VBox(Insets borderInsets) { - this(null, borderInsets); - } - - /** - * Constructs a container that that lays out components from top to bottom. - * - * @param borderInsets if not null then an empty border with the given insets is set. - */ - public VBox(HVSize props, Insets borderInsets) { - super(); - super.setLayout(new VLayout(props)); - if (borderInsets != null) { - setBorder(new EmptyBorder(borderInsets)); - } - } - - @Override - public VLayout getLayout() { - return (VLayout) super.getLayout(); - } - - public void setHvprops(HVSize props) { - getLayout().setHvprops(props); - } - - public HVSize getHvprops() { - return getLayout().getHvprops(); - } - - /** - * To accomodate a scroller - */ - @Override - public Dimension getPreferredScrollableViewportSize() { - return this.getPreferredSize(); - } - - /** - * To accomodate a scroller - */ - @Override - public int getScrollableUnitIncrement(final Rectangle arg0, final int arg1, - final int arg2) { - return getHvprops().getLineHeightNoDepth(); - } - - /** - * To accomodate a scroller - */ - @Override - public int getScrollableBlockIncrement(final Rectangle arg0, final int arg1, - final int arg2) { - return getHvprops().getLineHeightNoDepth(); - } - - /** - * To accomodate a scroller - */ - @Override - public boolean getScrollableTracksViewportWidth() { - if (this.getParent().getWidth() > this.getMinimumSize().width) { - return true; - } - return false; - } - - /** - * To accomodate a scroller - */ - @Override - public boolean getScrollableTracksViewportHeight() { - if (this.getParent().getHeight() > this.getMinimumSize().height) { - return true; - } - return false; - } - - /** - * This (overloaded) convenience method allows adding components in the middle of a list of components (at the place indicated by - * index). - * - * @param index if -1 component is added at he end of the components-list. - * @see java.awt.Container#add(java.awt.Component, Object, int) - */ - @Override - public Component add(final Component comp, final int index) { - super.add(comp, Integer.valueOf(index), index); - return comp; - } - -} From 32616436f525ed3ae16906fd12bab3ea44c1081c Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Tue, 8 Apr 2025 16:43:36 +0200 Subject: [PATCH 42/70] Added checkstyle plugin --- nbactions.xml | 9 +++++++- pom.xml | 21 +++++++++++++++++++ src/main/java/jcs/ui/DriverCabFrame.java | 13 +++++++----- .../jcs/ui/settings/CommandStationDialog.form | 2 +- .../jcs/ui/settings/CommandStationDialog.java | 2 +- 5 files changed, 39 insertions(+), 8 deletions(-) diff --git a/nbactions.xml b/nbactions.xml index c2d9de65..11d28733 100644 --- a/nbactions.xml +++ b/nbactions.xml @@ -81,4 +81,11 @@ test - \ No newline at end of file + + CUSTOM-checkstyle:check + checkstyle:check + + checkstyle:check + + + diff --git a/pom.xml b/pom.xml index d7a8a16d..5be16159 100644 --- a/pom.xml +++ b/pom.xml @@ -352,6 +352,27 @@ + + org.apache.maven.plugins + maven-checkstyle-plugin + 3.6.0 + + + com.puppycrawl.tools + checkstyle + 10.23.0 + + + + + auto + compile + + compile + + + + io.github.fvarrui javapackager diff --git a/src/main/java/jcs/ui/DriverCabFrame.java b/src/main/java/jcs/ui/DriverCabFrame.java index b0601797..ab937d9f 100644 --- a/src/main/java/jcs/ui/DriverCabFrame.java +++ b/src/main/java/jcs/ui/DriverCabFrame.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 frans. + * Copyright 2023 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,6 +29,7 @@ import javax.imageio.ImageIO; import javax.swing.DefaultComboBoxModel; import javax.swing.ImageIcon; +import javax.swing.JFrame; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import jcs.JCS; @@ -43,10 +44,10 @@ import org.tinylog.Logger; /** + * Frame to use when you want to simply drive a Locomotive on the track. * - * @author frans */ -public class DriverCabFrame extends javax.swing.JFrame implements LocomotiveDirectionEventListener { +public class DriverCabFrame extends JFrame implements LocomotiveDirectionEventListener { private static final long serialVersionUID = 6139691226868043462L; @@ -310,7 +311,8 @@ public static void main(String args[]) { if (plaf != null) { UIManager.setLookAndFeel(plaf); } - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { + } + catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { Logger.error(ex); } @@ -329,7 +331,8 @@ public static void main(String args[]) { try { BufferedImage img = ImageIO.read(DriverCabFrame.class.getResource(frameImageUrl)); taskbar.setIconImage(img); - } catch (IOException | UnsupportedOperationException | SecurityException ex) { + } + catch (IOException | UnsupportedOperationException | SecurityException ex) { Logger.warn("Error: " + ex.getMessage()); } } diff --git a/src/main/java/jcs/ui/settings/CommandStationDialog.form b/src/main/java/jcs/ui/settings/CommandStationDialog.form index 72767561..374c9a31 100644 --- a/src/main/java/jcs/ui/settings/CommandStationDialog.form +++ b/src/main/java/jcs/ui/settings/CommandStationDialog.form @@ -132,4 +132,4 @@ - \ No newline at end of file + diff --git a/src/main/java/jcs/ui/settings/CommandStationDialog.java b/src/main/java/jcs/ui/settings/CommandStationDialog.java index e9aa527e..d0889b59 100644 --- a/src/main/java/jcs/ui/settings/CommandStationDialog.java +++ b/src/main/java/jcs/ui/settings/CommandStationDialog.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 frans. + * Copyright 2023 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From 36c20abf2d8b2cfc53ee83c47d497ce1496f72ef Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Tue, 8 Apr 2025 16:47:36 +0200 Subject: [PATCH 43/70] Fix build --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 5be16159..03447ce4 100644 --- a/pom.xml +++ b/pom.xml @@ -365,10 +365,10 @@ - auto - compile + checkstyle + checkstyle - compile + checkstyle From 6bb6e7eca24ce9dce0647ac9f014df2dc834e20a Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Sat, 12 Apr 2025 15:11:30 +0200 Subject: [PATCH 44/70] Adding the Smal cab driver Attention point velocity is not kept? --- .../commandStation/JCSCommandStationImpl.java | 91 +++++-- .../java/jcs/ui/DispatcherStatusPanel.java | 25 +- src/main/java/jcs/ui/JCSFrame.java | 9 +- .../jcs/ui/panel/DispatcherTablePanel.java | 43 ++- .../jcs/ui/panel/LocomotiveTablePanel.java | 89 +++---- .../jcs/ui/panel/SmallDriverCabPanel.form | 22 +- .../jcs/ui/panel/SmallDriverCabPanel.java | 248 +++++++++++------- .../model/LocomotiveDispatcherTableModel.java | 1 + .../LocomotiveSelectionChangedListener.java | 25 ++ 9 files changed, 358 insertions(+), 195 deletions(-) create mode 100644 src/main/java/jcs/ui/util/LocomotiveSelectionChangedListener.java diff --git a/src/main/java/jcs/commandStation/JCSCommandStationImpl.java b/src/main/java/jcs/commandStation/JCSCommandStationImpl.java index 9037f844..bca305f1 100755 --- a/src/main/java/jcs/commandStation/JCSCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/JCSCommandStationImpl.java @@ -32,6 +32,8 @@ import java.util.Set; import java.util.Timer; import java.util.TimerTask; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.stream.Collectors; import javax.imageio.ImageIO; import jcs.commandStation.events.AccessoryEvent; @@ -72,10 +74,10 @@ public class JCSCommandStationImpl implements JCSCommandStation { private Map accessoryControllers; private Map feedbackControllers; - private final List anonymousSensorListeners; + private final List sensorListeners; private final List accessoryEventListeners; - private final List LocomotiveFunctionEventListeners; + private final List locomotiveFunctionEventListeners; private final List locomotiveDirectionEventListeners; private final List locomotiveSpeedEventListeners; @@ -85,17 +87,27 @@ public class JCSCommandStationImpl implements JCSCommandStation { private final Set supportedProtocols; private CommandStationBean commandStation; + private final ExecutorService executor; + + private static final String AWT_THREAD = "AWT-EventQueue-0"; + + /** + * Wrapper around the "real" CommandStation implementation.
+ * Operations to commandStations should not be performed in the EventDispatch thread.
+ * Operations to commandStations are performed in a worker thread to avoid blocking the EventDispatch thread.
+ */ public JCSCommandStationImpl() { this("true".equalsIgnoreCase(System.getProperty("skip.controller.autoconnect", "true"))); } private JCSCommandStationImpl(boolean autoConnectController) { + executor = Executors.newCachedThreadPool(); accessoryControllers = new HashMap<>(); feedbackControllers = new HashMap<>(); - anonymousSensorListeners = new LinkedList<>(); + sensorListeners = new LinkedList<>(); accessoryEventListeners = new LinkedList<>(); - LocomotiveFunctionEventListeners = new LinkedList<>(); + locomotiveFunctionEventListeners = new LinkedList<>(); locomotiveDirectionEventListeners = new LinkedList<>(); locomotiveSpeedEventListeners = new LinkedList<>(); measurementEventListeners = new LinkedList<>(); @@ -296,11 +308,11 @@ public void disconnect() { } //Enable command station switching so - this.decoderController = null; - this.accessoryControllers.clear(); - this.feedbackControllers.clear(); + decoderController = null; + accessoryControllers.clear(); + feedbackControllers.clear(); - this.commandStation = null; + commandStation = null; ControllerFactory.reset(); } @@ -422,8 +434,10 @@ public String getCommandStationArticleNumber() { @Override public void switchPower(boolean on) { //Logger.trace("Switch Power " + (on ? "On" : "Off")); - if (decoderController != null) { + if (decoderController != null && !AWT_THREAD.equals(Thread.currentThread().getName())) { decoderController.power(on); + } else { + executor.execute(() -> decoderController.power(on)); } } @@ -450,12 +464,14 @@ public void changeLocomotiveDirection(Direction newDirection, LocomotiveBean loc address = locomotive.getId().intValue(); } } - if (decoderController != null) { - //Set the velocity to zero before changing the direction - //Run this in a worker thread... - + if (decoderController != null && !AWT_THREAD.equals(Thread.currentThread().getName())) { decoderController.changeVelocity(address, 0, locomotive.getDirection()); decoderController.changeDirection(address, newDirection); + } else { + executor.execute(() -> { + decoderController.changeVelocity(address, 0, locomotive.getDirection()); + decoderController.changeDirection(address, newDirection); + }); } } @@ -472,8 +488,11 @@ public void changeLocomotiveSpeed(Integer newVelocity, LocomotiveBean locomotive address = locomotive.getId().intValue(); } } - if (decoderController != null) { + + if (decoderController != null && !AWT_THREAD.equals(Thread.currentThread().getName())) { decoderController.changeVelocity(address, newVelocity, locomotive.getDirection()); + } else { + executor.execute(() -> decoderController.changeVelocity(address, newVelocity, locomotive.getDirection())); } } @@ -490,8 +509,10 @@ public void changeLocomotiveFunction(Boolean newValue, Integer functionNumber, L address = locomotive.getId().intValue(); } } - if (decoderController != null) { + if (decoderController != null && !AWT_THREAD.equals(Thread.currentThread().getName())) { decoderController.changeFunctionValue(address, functionNumber, newValue); + } else { + executor.execute(() -> decoderController.changeFunctionValue(address, functionNumber, newValue)); } } @@ -522,45 +543,57 @@ public void switchAccessory(AccessoryBean accessory, AccessoryValue value) { } } - Logger.trace("Change accessory with address: " + address + ", " + accessory.getName() + " to " + val.getValue()); - for (AccessoryController ac : accessoryControllers.values()) { - ac.switchAccessory(address, protocol.getValue(), val, switchTime); + Logger.trace("Changing accessory with address: " + address + ", " + accessory.getName() + " to " + val.getValue()); + changeAccessory(address, protocol.getValue(), val, switchTime); + } + + private void changeAccessory(final Integer address, final String protocol, final AccessoryValue value, final Integer switchTime) { + if (!AWT_THREAD.equals(Thread.currentThread().getName())) { + for (AccessoryController ac : accessoryControllers.values()) { + ac.switchAccessory(address, protocol, value, switchTime); + } + } else { + executor.execute(() -> { + for (AccessoryController ac : accessoryControllers.values()) { + ac.switchAccessory(address, protocol, value, switchTime); + } + }); } } @Override public void addSensorEventListener(SensorEventListener listener) { - this.anonymousSensorListeners.add(listener); + sensorListeners.add(listener); } @Override public void removeSensorEventListener(SensorEventListener listener) { - this.anonymousSensorListeners.remove(listener); + sensorListeners.remove(listener); } @Override public void addAccessoryEventListener(AccessoryEventListener listener) { - this.accessoryEventListeners.add(listener); + accessoryEventListeners.add(listener); } @Override public void removeAccessoryEventListener(AccessoryEventListener listener) { - this.accessoryEventListeners.remove(listener); + accessoryEventListeners.remove(listener); } @Override public void addLocomotiveFunctionEventListener(LocomotiveFunctionEventListener listener) { - this.LocomotiveFunctionEventListeners.add(listener); + locomotiveFunctionEventListeners.add(listener); } @Override public void removeLocomotiveFunctionEventListener(LocomotiveFunctionEventListener listener) { - this.LocomotiveFunctionEventListeners.remove(listener); + locomotiveFunctionEventListeners.remove(listener); } @Override public void addLocomotiveDirectionEventListener(LocomotiveDirectionEventListener listener) { - this.locomotiveDirectionEventListeners.add(listener); + locomotiveDirectionEventListeners.add(listener); } @Override @@ -570,12 +603,12 @@ public void removeLocomotiveDirectionEventListener(LocomotiveDirectionEventListe @Override public void addLocomotiveSpeedEventListener(LocomotiveSpeedEventListener listener) { - this.locomotiveSpeedEventListeners.add(listener); + locomotiveSpeedEventListeners.add(listener); } @Override public void removeLocomotiveSpeedEventListener(LocomotiveSpeedEventListener listener) { - this.locomotiveSpeedEventListeners.remove(listener); + locomotiveSpeedEventListeners.remove(listener); } @Override @@ -687,7 +720,7 @@ public void onSensorChange(SensorEvent event) { } //Avoid concurrent modification exceptions - List snapshot = new ArrayList<>(commandStation.anonymousSensorListeners); + List snapshot = new ArrayList<>(commandStation.sensorListeners); for (SensorEventListener sl : snapshot) { if (sl != null) { @@ -787,7 +820,7 @@ public void onFunctionChange(LocomotiveFunctionEvent functionEvent) { PersistenceFactory.getService().persist(dbfb); functionEvent.setFunctionBean(dbfb); } - for (LocomotiveFunctionEventListener fl : trackService.LocomotiveFunctionEventListeners) { + for (LocomotiveFunctionEventListener fl : trackService.locomotiveFunctionEventListeners) { fl.onFunctionChange(functionEvent); } } diff --git a/src/main/java/jcs/ui/DispatcherStatusPanel.java b/src/main/java/jcs/ui/DispatcherStatusPanel.java index 9df38962..ffa01da7 100644 --- a/src/main/java/jcs/ui/DispatcherStatusPanel.java +++ b/src/main/java/jcs/ui/DispatcherStatusPanel.java @@ -18,34 +18,45 @@ import javax.swing.JPanel; import jcs.commandStation.events.RefreshEvent; import jcs.commandStation.events.RefreshEventListener; +import jcs.ui.util.LocomotiveSelectionChangedListener; /** * */ public class DispatcherStatusPanel extends JPanel implements RefreshEventListener { - /** - * Creates new form DispatcherStatusPanel - */ + private static final long serialVersionUID = 6158244271104499799L; + public DispatcherStatusPanel() { initComponents(); } public void showDispatcherTab() { - this.tabsPane.setSelectedIndex(1); + tabsPane.setSelectedIndex(1); } public void showLocomotiveTab() { - this.tabsPane.setSelectedIndex(0); + tabsPane.setSelectedIndex(0); } public void refresh() { - this.locomotiveTablePanel.refresh(); + locomotiveTablePanel.refresh(); } @Override public void onChange(RefreshEvent event) { - this.locomotiveTablePanel.onChange(event); + locomotiveTablePanel.onChange(event); + } + + public void addLocomotiveSelectionChangeListener(LocomotiveSelectionChangedListener listener) { + locomotiveTablePanel.addLocomotiveSelectionChangeListener(listener); + dispatcherTablePanel.addLocomotiveSelectionChangeListener(listener); + + } + + public void removeLocomotiveSelectionChangeListener(LocomotiveSelectionChangedListener listener) { + locomotiveTablePanel.removeLocomotiveSelectionChangeListener(listener); + dispatcherTablePanel.removeLocomotiveSelectionChangeListener(listener); } /** diff --git a/src/main/java/jcs/ui/JCSFrame.java b/src/main/java/jcs/ui/JCSFrame.java index 3012e305..e819661d 100755 --- a/src/main/java/jcs/ui/JCSFrame.java +++ b/src/main/java/jcs/ui/JCSFrame.java @@ -120,19 +120,22 @@ public JCSFrame() { //avoid overlap of the red/orange/green buttons and the window title //jcsToolBar.add(Box.createHorizontalStrut(70), 0); } - - initJCS(); } + initJCS(); initKeyStrokes(); } private void initJCS() { if (PersistenceFactory.getService() != null) { - setTitle(this.getTitleString()); + setTitle(getTitleString()); if (JCS.getJcsCommandStation().isConnected()) { setControllerProperties(); } + + //Connect the pannels togetehr for the locomotive selection + dispatcherStatusPanel.addLocomotiveSelectionChangeListener(smallDriverCabPanel1); + //Show the default panel showOverviewPanel(); editMode = false; diff --git a/src/main/java/jcs/ui/panel/DispatcherTablePanel.java b/src/main/java/jcs/ui/panel/DispatcherTablePanel.java index f531d403..4783f934 100644 --- a/src/main/java/jcs/ui/panel/DispatcherTablePanel.java +++ b/src/main/java/jcs/ui/panel/DispatcherTablePanel.java @@ -19,10 +19,12 @@ import java.awt.Component; import java.awt.Image; import java.awt.image.BufferedImage; +import java.util.ArrayList; import java.util.List; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JLabel; +import javax.swing.JPanel; import javax.swing.JTable; import javax.swing.SwingUtilities; import javax.swing.event.RowSorterEvent; @@ -33,24 +35,28 @@ import jcs.commandStation.autopilot.state.Dispatcher; import jcs.entities.LocomotiveBean; import jcs.ui.DriverCabDialog; +import jcs.ui.util.LocomotiveSelectionChangedListener; import org.tinylog.Logger; /** * - * @author frans */ -public class DispatcherTablePanel extends javax.swing.JPanel implements AutoPilotStatusListener { +public class DispatcherTablePanel extends JPanel implements AutoPilotStatusListener { + + private static final long serialVersionUID = -7052304625809395213L; + + private final List locomotiveSelectionChangedListeners; - /** - * Creates new form LocomotiveTablePanel - */ public DispatcherTablePanel() { + locomotiveSelectionChangedListeners = new ArrayList<>(); initComponents(); - this.dispatcherTable.setDefaultRenderer(Image.class, new LocIconRenderer()); - this.dispatcherTable.getRowSorter().addRowSorterListener((RowSorterEvent e) -> { + dispatcherTable.setDefaultRenderer(Image.class, new LocIconRenderer()); + + dispatcherTable.getRowSorter().addRowSorterListener((RowSorterEvent e) -> { //Logger.trace(e.getType() + "," + e.getSource().getSortKeys());// Sorting changed }); + initModel(); } @@ -68,6 +74,8 @@ public void statusChanged(boolean running) { private class LocIconRenderer extends DefaultTableCellRenderer { + private static final long serialVersionUID = -2650118175935042594L; + @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); @@ -117,17 +125,36 @@ public void mouseReleased(java.awt.event.MouseEvent evt) { }// //GEN-END:initComponents private void dispatcherTableMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_dispatcherTableMouseReleased - int row = this.dispatcherTable.getSelectedRow(); + int row = dispatcherTable.getSelectedRow(); Dispatcher dispatcher = locomotiveDispatcherTableModel.getBeanAt(row); if (row >= 0 && dispatcher != null) { Logger.trace("Selected " + dispatcher.getName() + " " + evt.getClickCount()); + if (evt.getClickCount() == 2) { showDriverCabDialog(dispatcher.getLocomotiveBean()); } + fireSelectionChangedListeners(dispatcher); } }//GEN-LAST:event_dispatcherTableMouseReleased + private void fireSelectionChangedListeners(Dispatcher dispatcher) { + if (dispatcher.getLocomotiveBean().getId() != null) { + Long locomotiveId = dispatcher.getLocomotiveBean().getId(); + for (LocomotiveSelectionChangedListener listener : locomotiveSelectionChangedListeners) { + listener.selectionChanged(locomotiveId); + } + } + } + + public void addLocomotiveSelectionChangeListener(LocomotiveSelectionChangedListener listener) { + locomotiveSelectionChangedListeners.add(listener); + } + + public void removeLocomotiveSelectionChangeListener(LocomotiveSelectionChangedListener listener) { + locomotiveSelectionChangedListeners.remove(listener); + } + @Override public void setVisible(boolean aFlag) { super.setVisible(aFlag); diff --git a/src/main/java/jcs/ui/panel/LocomotiveTablePanel.java b/src/main/java/jcs/ui/panel/LocomotiveTablePanel.java index 9d52feed..7d557f6a 100644 --- a/src/main/java/jcs/ui/panel/LocomotiveTablePanel.java +++ b/src/main/java/jcs/ui/panel/LocomotiveTablePanel.java @@ -19,14 +19,14 @@ import java.awt.Component; import java.awt.Image; import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.List; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTable; import javax.swing.SwingUtilities; -import javax.swing.UIManager; -import javax.swing.UnsupportedLookAndFeelException; import javax.swing.event.RowSorterEvent; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.TableRowSorter; @@ -36,24 +36,24 @@ import jcs.persistence.PersistenceFactory; import jcs.ui.DriverCabDialog; import jcs.ui.table.model.LocomotiveBeanTableModel; +import jcs.ui.util.LocomotiveSelectionChangedListener; import org.tinylog.Logger; /** * - * @author frans */ public class LocomotiveTablePanel extends JPanel implements RefreshEventListener { - /** - * Creates new form LocomotiveTablePanel - */ + private static final long serialVersionUID = 1387464111237136414L; + + private final List locomotiveSelectionChangedListeners; + public LocomotiveTablePanel() { - locomotiveBeanTableModel = new LocomotiveBeanTableModel(); + locomotiveSelectionChangedListeners = new ArrayList<>(); + locomotiveBeanTableModel = new LocomotiveBeanTableModel(); initComponents(); - locomotiveTable.setDefaultRenderer(Image.class, new LocIconRenderer()); - locomotiveTable.getRowSorter().addRowSorterListener((RowSorterEvent e) -> { //Logger.trace(e.getType() + "," + e.getSource().getSortKeys());// Sorting changed }); @@ -63,17 +63,7 @@ public LocomotiveTablePanel() { private void initModel() { if (PersistenceFactory.getService() != null) { -// List activeLocos = new ArrayList<>(); -// List allLocos = PersistenceFactory.getService().getLocomotives(); -// for (LocomotiveBean loco : allLocos) { -// if (loco.isShow()) { -// activeLocos.add(loco); -// } -// } -// -// Logger.trace("In total there are " + allLocos.size() + " Locomotives of which there are " + activeLocos.size() + " shown"); -// locomotiveBeanTableModel.setBeans(activeLocos); - locomotiveBeanTableModel.refresh(); + refresh(); } } @@ -90,6 +80,8 @@ public void refresh() { private class LocIconRenderer extends DefaultTableCellRenderer { + private static final long serialVersionUID = 6174920035602771500L; + @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); @@ -139,15 +131,35 @@ public void mouseReleased(java.awt.event.MouseEvent evt) { }// //GEN-END:initComponents private void locomotiveTableMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_locomotiveTableMouseReleased - int row = this.locomotiveTable.getSelectedRow(); + int row = locomotiveTable.getSelectedRow(); LocomotiveBean loc = locomotiveBeanTableModel.getBeanAt(row); - Logger.trace("Selected " + loc.getName() + " " + evt.getClickCount()); + //Logger.trace("Selected " + loc.getName() + " " + evt.getClickCount()); if (evt.getClickCount() == 2) { showDriverCabDialog(loc); } + + fireSelectionChangedListeners(loc); }//GEN-LAST:event_locomotiveTableMouseReleased + private void fireSelectionChangedListeners(LocomotiveBean locomotive) { + if (locomotive.getId() != null) { + Long locomotiveId = locomotive.getId(); + Logger.trace("Notify "+locomotiveSelectionChangedListeners.size()+" of selection change to locomotiveId: "+locomotiveId); + for (LocomotiveSelectionChangedListener listener : locomotiveSelectionChangedListeners) { + listener.selectionChanged(locomotiveId); + } + } + } + + public void addLocomotiveSelectionChangeListener(LocomotiveSelectionChangedListener listener) { + locomotiveSelectionChangedListeners.add(listener); + } + + public void removeLocomotiveSelectionChangeListener(LocomotiveSelectionChangedListener listener) { + locomotiveSelectionChangedListeners.remove(listener); + } + private java.awt.Frame getParentFrame() { JFrame frame = (JFrame) SwingUtilities.getRoot(this); return frame; @@ -171,37 +183,4 @@ private void showDriverCabDialog(LocomotiveBean locomotiveBean) { private javax.swing.JTable locomotiveTable; // End of variables declaration//GEN-END:variables - public static void main(String args[]) { - try { - String plaf = System.getProperty("jcs.plaf", "com.formdev.flatlaf.FlatLightLaf"); - if (plaf != null) { - UIManager.setLookAndFeel(plaf); - } else { - UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - } - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { - Logger.error(ex); - } - - java.awt.EventQueue.invokeLater(() -> { - - LocomotiveTablePanel testPanel = new LocomotiveTablePanel(); - JFrame testFrame = new JFrame("LocomotiveTablePanel Tester"); - - testFrame.add(testPanel); - - testFrame.addWindowListener(new java.awt.event.WindowAdapter() { - @Override - public void windowClosing(java.awt.event.WindowEvent e) { - System.exit(0); - } - }); - testFrame.pack(); - testFrame.setLocationRelativeTo(null); - - //testPanel.loadLocomotives(); - testPanel.locomotiveBeanTableModel.refresh(); - testFrame.setVisible(true); - }); - } } diff --git a/src/main/java/jcs/ui/panel/SmallDriverCabPanel.form b/src/main/java/jcs/ui/panel/SmallDriverCabPanel.form index be45295b..82d6c754 100644 --- a/src/main/java/jcs/ui/panel/SmallDriverCabPanel.form +++ b/src/main/java/jcs/ui/panel/SmallDriverCabPanel.form @@ -1,17 +1,24 @@
+ + + + - + - + + + + @@ -251,6 +258,9 @@ + + + @@ -1473,12 +1483,15 @@ - + + + + @@ -1494,6 +1507,9 @@ + + + diff --git a/src/main/java/jcs/ui/panel/SmallDriverCabPanel.java b/src/main/java/jcs/ui/panel/SmallDriverCabPanel.java index 09db090f..326c775a 100644 --- a/src/main/java/jcs/ui/panel/SmallDriverCabPanel.java +++ b/src/main/java/jcs/ui/panel/SmallDriverCabPanel.java @@ -15,13 +15,13 @@ */ package jcs.ui.panel; +import java.awt.Color; import java.awt.event.ActionEvent; import java.util.HashMap; import java.util.Map; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import javax.swing.ImageIcon; import javax.swing.JFrame; +import javax.swing.JSlider; import javax.swing.JToggleButton; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; @@ -37,16 +37,17 @@ import jcs.entities.FunctionBean; import jcs.entities.LocomotiveBean; import jcs.persistence.PersistenceFactory; +import jcs.ui.util.LocomotiveSelectionChangedListener; import org.tinylog.Logger; /** * Small function Panel for use in the small driver Cab */ -public class SmallDriverCabPanel extends javax.swing.JPanel implements LocomotiveDirectionEventListener, LocomotiveSpeedEventListener, PowerEventListener { +public class SmallDriverCabPanel extends javax.swing.JPanel implements LocomotiveSelectionChangedListener, LocomotiveDirectionEventListener, LocomotiveSpeedEventListener, PowerEventListener { private final Map buttons; private LocomotiveBean locomotiveBean; - private final ExecutorService executor; + //private final ExecutorService executor; private boolean initButtons = false; private boolean disableListener = false; private boolean power; @@ -55,7 +56,7 @@ public class SmallDriverCabPanel extends javax.swing.JPanel implements Locomotiv public SmallDriverCabPanel() { buttons = new HashMap<>(); - executor = Executors.newCachedThreadPool(); + //executor = Executors.newCachedThreadPool(); initComponents(); mapButtons(); @@ -114,10 +115,10 @@ public void setEnabled(boolean enabled) { //@Override public void onFunctionChange(LocomotiveFunctionEvent event) { - if (this.locomotiveBean != null && this.locomotiveBean.getId().equals(event.getFunctionBean().getLocomotiveId())) { + if (locomotiveBean != null && locomotiveBean.getId().equals(event.getFunctionBean().getLocomotiveId())) { FunctionBean fb = event.getFunctionBean(); //this.buttons.get(fb.getNumber()).setSelected(fb.isOn()); - JToggleButton tbtn = this.buttons.get(fb.getNumber()); + JToggleButton tbtn = buttons.get(fb.getNumber()); //Temp disable the event handling as this is an external event... enableEvent = false; @@ -130,60 +131,104 @@ public void onFunctionChange(LocomotiveFunctionEvent event) { } private void resetButtons() { - for (JToggleButton btn : this.buttons.values()) { + for (JToggleButton btn : buttons.values()) { btn.setIcon(null); btn.setSelectedIcon(null); btn.setText(""); btn.setEnabled(false); //btn.setForeground(new java.awt.Color(0, 0, 0)); - btn.setForeground(new java.awt.Color(204, 204, 204)); - btn.setBackground(new java.awt.Color(204, 204, 204)); + btn.setForeground(new Color(204, 204, 204)); + btn.setBackground(new Color(204, 204, 204)); btn.setSelected(false); } } - public void setLocomotiveBean(LocomotiveBean locomotiveBean) { - resetButtons(); - initButtons = true; - if (PersistenceFactory.getService() != null && locomotiveBean != null) { - this.locomotiveBean = locomotiveBean; - Map functions = locomotiveBean.getFunctions(); - - Logger.trace("Loc: " + this.locomotiveBean.getName() + " has " + functions.size() + " functions"); - for (FunctionBean fb : functions.values()) { - Integer fnr = fb.getNumber(); - JToggleButton btn = this.buttons.get(fnr); - - //Logger.trace("Function: " + fb.getNumber() + " Type: " + fb.getFunctionType() + " Value: " + fb.getValue() + " isMomentary: " + fb.isMomentary()); - if (fb.getInActiveIconImage() != null) { - btn.setIcon(new ImageIcon(fb.getInActiveIconImage())); - } else { - btn.setText("F" + fb.getNumber()); - //Logger.trace("Missing Icon: " + fb.getInActiveIcon() + " Button Text: " + btn.getText()); - } + @Override + public void selectionChanged(Long locomotiveId) { + boolean selectionChanged; + if (locomotiveBean == null && locomotiveId != null) { + selectionChanged = true; + } else if (locomotiveId != null && locomotiveBean != null && !locomotiveId.equals(locomotiveBean.getId())) { + Logger.trace("LocomotiveId is changing from : " + locomotiveBean.getId() + " to " + locomotiveId); + selectionChanged = true; + } else { + selectionChanged = false; + Logger.trace("Selection NOT changed. Current selection: " + locomotiveBean.getId()); + } - if (fb.getActiveIconImage() != null) { - btn.setSelectedIcon(new ImageIcon(fb.getActiveIconImage())); - } else { - btn.setText("F" + fb.getNumber()); - //Logger.trace("Missing Icon: " + fb.getActiveIcon() + " Button Text: " + btn.getText()); - } + if (selectionChanged) { + Logger.trace("Change selection to LocomotiveId: " + locomotiveId); + //Disable listeners! + disableListener = true; - btn.setActionCommand("F" + fb.getNumber()); - btn.setEnabled(true); + resetButtons(); + initButtons = true; + if (PersistenceFactory.getService() != null) { + //Get the locomotive from the persistent layer + locomotiveBean = PersistenceFactory.getService().getLocomotive(locomotiveId); - boolean isOn = fb.getValue() == 1; - if (isOn) { - btn.doClick(); + double max = 100; + if (locomotiveBean.getTachoMax() != null) { + max = locomotiveBean.getTachoMax(); } - //Logger.trace("Button " + btn.getActionCommand() + " selected: " + btn.isSelected()); - + speedSlider.setMaximum((int) max); + + //Calc speed + int velocity = locomotiveBean.getVelocity(); + int sliderValue = (int) Math.round(max / 1000 * velocity); + speedSlider.setValue(sliderValue); + + forwardButton.setSelected(LocomotiveBean.Direction.FORWARDS == locomotiveBean.getDirection()); + reverseButton.setSelected(LocomotiveBean.Direction.BACKWARDS == locomotiveBean.getDirection()); + + Map functions = locomotiveBean.getFunctions(); + + Logger.trace("Loc: " + locomotiveBean.getName() + " has " + functions.size() + " functions"); + for (FunctionBean fb : functions.values()) { + Integer fnr = fb.getNumber(); + JToggleButton btn = this.buttons.get(fnr); + + //Logger.trace("Function: " + fb.getNumber() + " Type: " + fb.getFunctionType() + " Value: " + fb.getValue() + " isMomentary: " + fb.isMomentary()); + if (fb.getInActiveIconImage() != null) { + btn.setIcon(new ImageIcon(fb.getInActiveIconImage())); + } else { + btn.setText("F" + fb.getNumber()); + //Logger.trace("Missing Icon: " + fb.getInActiveIcon() + " Button Text: " + btn.getText()); + } + + if (fb.getActiveIconImage() != null) { + btn.setSelectedIcon(new ImageIcon(fb.getActiveIconImage())); + } else { + btn.setText("F" + fb.getNumber()); + //Logger.trace("Missing Icon: " + fb.getActiveIcon() + " Button Text: " + btn.getText()); + } + + btn.setActionCommand("F" + fb.getNumber()); + btn.setEnabled(true); + + boolean isOn = fb.getValue() == 1; + if (isOn) { + btn.doClick(); + } + //Logger.trace("Button " + btn.getActionCommand() + " selected: " + btn.isSelected()); + } + buttonsTP.setEnabled(true); } - this.buttonsTP.setEnabled(true); + initButtons = false; + disableListener = false; } - initButtons = false; + } + + /** + * + * Sets the LocomotiveBean for this panel. This will update the buttons with the correct icons and states. + * + * @param locomotiveBean + */ + public void setLocomotiveBean(LocomotiveBean locomotive) { + selectionChanged(locomotive.getId()); } public LocomotiveBean getLocomotiveBean() { @@ -207,24 +252,25 @@ private void buttonActionPerformed(ActionEvent evt) { Logger.trace(evt.getActionCommand() + ": " + (value ? "On" : "Off")); Integer functionNumber = Integer.decode(evt.getActionCommand().replace("F", "")); - FunctionBean fb = this.locomotiveBean.getFunctionBean(functionNumber); + FunctionBean fb = locomotiveBean.getFunctionBean(functionNumber); if (!initButtons && enableEvent) { Logger.trace("Function " + fb.getNumber() + " Value: " + fb.isOn() + " Momentary: " + fb.isMomentary()); - executor.execute(() -> changeFunction(value, functionNumber, locomotiveBean)); + //executor.execute(() -> changeFunction(value, functionNumber, locomotiveBean)); + changeFunction(value, functionNumber, locomotiveBean); } } private void changeFunction(boolean newValue, Integer functionNumber, LocomotiveBean locomotiveBean) { - if (JCS.getJcsCommandStation() != null && this.locomotiveBean != null) { - FunctionBean fb = this.locomotiveBean.getFunctionBean(functionNumber); + if (JCS.getJcsCommandStation() != null && locomotiveBean != null) { + FunctionBean fb = locomotiveBean.getFunctionBean(functionNumber); Logger.trace("Function " + fb.getNumber() + " Value: " + fb.isOn() + " new Value: " + newValue + " Momentary: " + fb.isMomentary()); if (JCS.getJcsCommandStation() != null) { JCS.getJcsCommandStation().changeLocomotiveFunction(newValue, functionNumber, locomotiveBean); } if (fb.isMomentary() && newValue) { - JToggleButton tb = this.buttons.get(fb.getNumber()); + JToggleButton tb = buttons.get(fb.getNumber()); tb.doClick(); } } @@ -237,6 +283,7 @@ private void changeFunction(boolean newValue, Integer functionNumber, Locomotive // //GEN-BEGIN:initComponents private void initComponents() { + directionBG = new javax.swing.ButtonGroup(); jPanel1 = new javax.swing.JPanel(); jPanel3 = new javax.swing.JPanel(); speed1Button = new javax.swing.JButton(); @@ -289,10 +336,11 @@ private void initComponents() { filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(30, 0), new java.awt.Dimension(30, 0), new java.awt.Dimension(30, 32767)); stopButton = new javax.swing.JButton(); - setMaximumSize(new java.awt.Dimension(200, 235)); - setMinimumSize(new java.awt.Dimension(200, 235)); + setMaximumSize(new java.awt.Dimension(300, 200)); + setMinimumSize(new java.awt.Dimension(300, 200)); setName("Form"); // NOI18N setPreferredSize(new java.awt.Dimension(300, 200)); + setSize(new java.awt.Dimension(300, 200)); setLayout(new java.awt.BorderLayout()); jPanel1.setName("jPanel1"); // NOI18N @@ -368,6 +416,11 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { speedSlider.setValue(0); speedSlider.setName("speedSlider"); // NOI18N speedSlider.setPreferredSize(new java.awt.Dimension(30, 180)); + speedSlider.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + speedSliderStateChanged(evt); + } + }); jPanel4.add(speedSlider); jPanel1.add(jPanel4); @@ -933,11 +986,12 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { southPanel.setMinimumSize(new java.awt.Dimension(300, 50)); southPanel.setName("southPanel"); // NOI18N - southPanel.setPreferredSize(new java.awt.Dimension(300, 50)); + southPanel.setPreferredSize(new java.awt.Dimension(298, 50)); java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); flowLayout1.setAlignOnBaseline(true); southPanel.setLayout(flowLayout1); + directionBG.add(reverseButton); reverseButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/media/left-24.png"))); // NOI18N reverseButton.setActionCommand("Backwards"); reverseButton.setName("reverseButton"); // NOI18N @@ -949,6 +1003,7 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { }); southPanel.add(reverseButton); + directionBG.add(forwardButton); forwardButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/media/right-24.png"))); // NOI18N forwardButton.setSelected(true); forwardButton.setActionCommand("Forwards"); @@ -1109,40 +1164,40 @@ private void f31TBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:e }//GEN-LAST:event_f31TBActionPerformed private void speed1ButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_speed1ButtonActionPerformed - if (this.locomotiveBean != null) { + if (locomotiveBean != null) { int tachoMax = locomotiveBean.getTachoMax(); tachoMax = tachoMax / 5; // 20 % - this.speedSlider.setValue(tachoMax); + speedSlider.setValue(tachoMax); } else { Logger.trace(evt.getActionCommand()); } }//GEN-LAST:event_speed1ButtonActionPerformed private void speed2ButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_speed2ButtonActionPerformed - if (this.locomotiveBean != null) { + if (locomotiveBean != null) { int tachoMax = locomotiveBean.getTachoMax(); tachoMax = (tachoMax / 5) * 2; // 40 % - this.speedSlider.setValue(tachoMax); + speedSlider.setValue(tachoMax); } else { Logger.trace(evt.getActionCommand()); } }//GEN-LAST:event_speed2ButtonActionPerformed private void speed3ButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_speed3ButtonActionPerformed - if (this.locomotiveBean != null) { + if (locomotiveBean != null) { int tachoMax = locomotiveBean.getTachoMax(); tachoMax = (tachoMax / 5) * 3; // 60 % - this.speedSlider.setValue(tachoMax); + speedSlider.setValue(tachoMax); } else { Logger.trace(evt.getActionCommand()); } }//GEN-LAST:event_speed3ButtonActionPerformed private void speed4ButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_speed4ButtonActionPerformed - if (this.locomotiveBean != null) { + if (locomotiveBean != null) { int tachoMax = locomotiveBean.getTachoMax(); tachoMax = (tachoMax / 5) * 4; // 80 % - this.speedSlider.setValue(tachoMax); + speedSlider.setValue(tachoMax); } else { Logger.trace(evt.getActionCommand()); } @@ -1161,12 +1216,34 @@ private void forwardButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN }//GEN-LAST:event_forwardButtonActionPerformed private void stopButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_stopButtonActionPerformed - this.speedSlider.setValue(0); - if (this.locomotiveBean == null) { + speedSlider.setValue(0); + if (locomotiveBean == null) { Logger.trace(evt.getActionCommand()); } }//GEN-LAST:event_stopButtonActionPerformed + private void speedSliderStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_speedSliderStateChanged + JSlider slider = (JSlider) evt.getSource(); + if (!slider.getValueIsAdjusting()) { + + if (!disableListener && locomotiveBean != null) { + int max = locomotiveBean.getTachoMax(); + double value = slider.getValue(); + //Velocity is always between 0 and 1000 + int velocity = (int) Math.round(value / max * 1000); + //executor.execute(() -> changeVelocity(velocity, locomotiveBean)); + changeVelocity(velocity, locomotiveBean); + } + } + }//GEN-LAST:event_speedSliderStateChanged + + private void changeVelocity(int newVelocity, LocomotiveBean locomotiveBean) { + if (JCS.getJcsCommandStation() != null && locomotiveBean != null && locomotiveBean.getId() != null) { + Logger.trace("Changing speeed of " + locomotiveBean + " to: " + newVelocity); + JCS.getJcsCommandStation().changeLocomotiveSpeed(newVelocity, locomotiveBean); + } + } + private void changeDirection(LocomotiveBean.Direction direction) { changeDirection(direction, this.locomotiveBean); } @@ -1189,21 +1266,15 @@ public void onDirectionChange(LocomotiveDirectionEvent event) { Logger.trace("Evt: id: " + lb.getId() + " Addr: " + lb.getAddress() + " cid: " + lb.getCommandStationId() + " dir: " + lb.getDirection()); if (event.isEventFor(locomotiveBean)) { - Logger.trace(lb.getName() + " direction changed from " + this.locomotiveBean.getDirection() + " to " + lb.getDirection()); + Logger.trace(lb.getName() + " direction changed from " + locomotiveBean.getDirection() + " to " + lb.getDirection()); - //locomotiveBean.setRichtung(lb.getRichtung()); locomotiveBean.setDirection(lb.getDirection()); + //Disable the direction buttons so that the change does not retrigger the commandstation disableListener = true; - if (LocomotiveBean.Direction.BACKWARDS.equals(lb.getDirection())) { - this.reverseButton.setSelected(true); - } else { - this.forwardButton.setSelected(true); - } + reverseButton.setSelected(LocomotiveBean.Direction.BACKWARDS == lb.getDirection()); + forwardButton.setSelected(LocomotiveBean.Direction.FORWARDS == lb.getDirection()); disableListener = false; -// if (this.directionListener != null) { -// this.directionListener.onDirectionChange(event); -// } } } @@ -1244,12 +1315,9 @@ public void onSpeedChange(LocomotiveSpeedEvent event) { @Override public void onPowerChange(PowerEvent event) { - if (this.locomotiveBean != null) { - this.power = event.isPower(); - - //this.speedGauge.setUserLedOn(this.power); - //this.speedGauge.setLedBlinking(!this.power); - Logger.trace("Power is " + this.power); + if (locomotiveBean != null) { + power = event.isPower(); + Logger.trace("Power is " + (power ? "On" : "Off")); } } @@ -1259,32 +1327,31 @@ public static void main(String args[]) { } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { Logger.error("Can't set the LookAndFeel: " + ex); } - java.awt.EventQueue.invokeLater(() -> { - - SmallDriverCabPanel testPanel = new SmallDriverCabPanel(); - JFrame testFrame = new JFrame("FunctionsPanel Tester"); - - testFrame.add(testPanel); + JFrame testFrame = new JFrame("SmallDriverCapPanel Tester"); + java.awt.EventQueue.invokeLater(() -> { testFrame.addWindowListener(new java.awt.event.WindowAdapter() { @Override public void windowClosing(java.awt.event.WindowEvent e) { System.exit(0); } }); - testFrame.pack(); - testFrame.setLocationRelativeTo(null); - if (JCS.getJcsCommandStation() != null) { + SmallDriverCabPanel testPanel = new SmallDriverCabPanel(); + + testFrame.add(testPanel); - //LocomotiveBean loc = PersistenceFactory.getService().getLocomotive(49189L); - LocomotiveBean loc = PersistenceFactory.getService().getLocomotive(1001L); + if (JCS.getJcsCommandStation() != null) { + LocomotiveBean loc = PersistenceFactory.getService().getLocomotive(16417L); + //LocomotiveBean loc = PersistenceFactory.getService().getLocomotive(1001L); Logger.debug(loc); testPanel.setLocomotiveBean(loc); - } + testFrame.pack(); + testFrame.setLocationRelativeTo(null); + testFrame.setVisible(true); }); } @@ -1292,6 +1359,7 @@ public void windowClosing(java.awt.event.WindowEvent e) { // Variables declaration - do not modify//GEN-BEGIN:variables javax.swing.JTabbedPane buttonsTP; + javax.swing.ButtonGroup directionBG; javax.swing.JToggleButton f0TB; javax.swing.JPanel f0f7Panel; javax.swing.JToggleButton f10TB; diff --git a/src/main/java/jcs/ui/table/model/LocomotiveDispatcherTableModel.java b/src/main/java/jcs/ui/table/model/LocomotiveDispatcherTableModel.java index 111dcbf9..c033c917 100644 --- a/src/main/java/jcs/ui/table/model/LocomotiveDispatcherTableModel.java +++ b/src/main/java/jcs/ui/table/model/LocomotiveDispatcherTableModel.java @@ -28,6 +28,7 @@ public class LocomotiveDispatcherTableModel extends AbstractBeanTableModel implements StateEventListener { private static final String[] DISPLAY_COLUMNS = new String[]{"image", "name", "state", "speed"}; + private static final long serialVersionUID = 5321472215655025458L; public LocomotiveDispatcherTableModel() { super(Dispatcher.class, DISPLAY_COLUMNS); diff --git a/src/main/java/jcs/ui/util/LocomotiveSelectionChangedListener.java b/src/main/java/jcs/ui/util/LocomotiveSelectionChangedListener.java new file mode 100644 index 00000000..f3fb3033 --- /dev/null +++ b/src/main/java/jcs/ui/util/LocomotiveSelectionChangedListener.java @@ -0,0 +1,25 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.util; + +/** + * + */ +public interface LocomotiveSelectionChangedListener { + + void selectionChanged(Long locomotiveId); + +} From 37697f936828e3eb44b9aeefafa9c3f4190a35fc Mon Sep 17 00:00:00 2001 From: Frans Jacobs <41232225+fransjacobs@users.noreply.github.com> Date: Sun, 13 Apr 2025 20:27:04 +0200 Subject: [PATCH 45/70] Fix null pointer --- src/main/java/jcs/commandStation/JCSCommandStationImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/jcs/commandStation/JCSCommandStationImpl.java b/src/main/java/jcs/commandStation/JCSCommandStationImpl.java index bca305f1..d56baf42 100755 --- a/src/main/java/jcs/commandStation/JCSCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/JCSCommandStationImpl.java @@ -436,7 +436,7 @@ public void switchPower(boolean on) { //Logger.trace("Switch Power " + (on ? "On" : "Off")); if (decoderController != null && !AWT_THREAD.equals(Thread.currentThread().getName())) { decoderController.power(on); - } else { + } else if (decoderController != null) { executor.execute(() -> decoderController.power(on)); } } From e7c8e0619511488d1e4d7f1d028dcf12290a8165 Mon Sep 17 00:00:00 2001 From: Frans Jacobs <41232225+fransjacobs@users.noreply.github.com> Date: Wed, 23 Apr 2025 21:11:11 +0200 Subject: [PATCH 46/70] SmallLocoPanel now really works together with Marklin --- .../commandStation/JCSCommandStationImpl.java | 53 +++- .../marklin/cs/MarklinCentralStationImpl.java | 8 +- .../marklin/cs/can/CanMessage.java | 2 +- .../marklin/cs/net/CSTCPConnection.java | 2 +- src/main/java/jcs/ui/JCSFrame.form | 11 +- src/main/java/jcs/ui/JCSFrame.java | 31 +- .../jcs/ui/panel/LocomotiveTablePanel.java | 2 +- .../jcs/ui/panel/SmallDriverCabPanel.form | 292 +++++++++++++----- .../jcs/ui/panel/SmallDriverCabPanel.java | 147 ++++++--- 9 files changed, 387 insertions(+), 161 deletions(-) diff --git a/src/main/java/jcs/commandStation/JCSCommandStationImpl.java b/src/main/java/jcs/commandStation/JCSCommandStationImpl.java index d56baf42..0fb4e688 100755 --- a/src/main/java/jcs/commandStation/JCSCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/JCSCommandStationImpl.java @@ -455,15 +455,21 @@ public void changeLocomotiveDirection(Direction newDirection, LocomotiveBean loc Logger.debug("Changing direction to " + newDirection + " for: " + locomotive.getName() + " id: " + locomotive.getId()); int address; - if (supportedProtocols.size() == 1) { - address = locomotive.getAddress(); + if ("marklin.cs".equals(locomotive.getCommandStationId()) || "esu-ecos".equals(locomotive.getCommandStationId())) { + address = locomotive.getId().intValue(); } else { - if (locomotive.getUid() != null) { - address = locomotive.getUid().intValue(); + //TODO: check this probably not needed anymore + if (supportedProtocols.size() == 1) { + address = locomotive.getAddress(); } else { - address = locomotive.getId().intValue(); + if (locomotive.getUid() != null) { + address = locomotive.getUid().intValue(); + } else { + address = locomotive.getId().intValue(); + } } } + if (decoderController != null && !AWT_THREAD.equals(Thread.currentThread().getName())) { decoderController.changeVelocity(address, 0, locomotive.getDirection()); decoderController.changeDirection(address, newDirection); @@ -478,14 +484,20 @@ public void changeLocomotiveDirection(Direction newDirection, LocomotiveBean loc @Override public void changeLocomotiveSpeed(Integer newVelocity, LocomotiveBean locomotive) { Logger.trace("Changing velocity to " + newVelocity + " for " + locomotive.getName()); + int address; - if (supportedProtocols.size() == 1) { - address = locomotive.getAddress(); + if ("marklin.cs".equals(locomotive.getCommandStationId()) || "esu-ecos".equals(locomotive.getCommandStationId())) { + address = locomotive.getId().intValue(); } else { - if (locomotive.getUid() != null) { - address = locomotive.getUid().intValue(); + //TODO: check this probably not needed anymore + if (supportedProtocols.size() == 1) { + address = locomotive.getAddress(); } else { - address = locomotive.getId().intValue(); + if (locomotive.getUid() != null) { + address = locomotive.getUid().intValue(); + } else { + address = locomotive.getId().intValue(); + } } } @@ -500,13 +512,18 @@ public void changeLocomotiveSpeed(Integer newVelocity, LocomotiveBean locomotive public void changeLocomotiveFunction(Boolean newValue, Integer functionNumber, LocomotiveBean locomotive) { Logger.trace("Changing Function " + functionNumber + " to " + (newValue ? "on" : "off") + " on " + locomotive.getName()); int address; - if (this.supportedProtocols.size() == 1) { - address = locomotive.getAddress(); + if ("marklin.cs".equals(locomotive.getCommandStationId()) || "esu-ecos".equals(locomotive.getCommandStationId())) { + address = locomotive.getId().intValue(); } else { - if (locomotive.getUid() != null) { - address = locomotive.getUid().intValue(); + //TODO: check this probably not needed anymore + if (supportedProtocols.size() == 1) { + address = locomotive.getAddress(); } else { - address = locomotive.getId().intValue(); + if (locomotive.getUid() != null) { + address = locomotive.getUid().intValue(); + } else { + address = locomotive.getId().intValue(); + } } } if (decoderController != null && !AWT_THREAD.equals(Thread.currentThread().getName())) { @@ -925,7 +942,11 @@ public void onSpeedChange(LocomotiveSpeedEvent speedEvent) { } } } else { - Logger.trace("No loc found for " + lb.toLogString()); + if ("marklin.cs".equals(lb.getCommandStationId()) || "esu-ecos".equals(lb.getCommandStationId())) { + Logger.trace("No loc with id " + lb.getId() + ", " + lb.getCommandStationId()); + } else { + Logger.trace("No loc found for " + lb.toLogString()); + } } } } diff --git a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java index 177963c6..bdac0ee3 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java +++ b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java @@ -583,9 +583,10 @@ public void changeVelocity(int locUid, int speed, Direction direction) { if (power && connected) { //VelocityChange 0x00 0x09 0x03 0x26 0x06 0x00 0x00 0x40 0x0c 0x00 0x30 0x00 0x00 //16396 - CanMessage message = CanMessageFactory.setLocSpeed(locUid, speed, this.csUid); - Logger.trace("Ch Velocity: "+message); + CanMessage message = CanMessageFactory.setLocSpeed(locUid, speed, csUid); + Logger.trace("Ch Velocity for uid: "+locUid+" -> "+message); message = sendMessage(message); + LocomotiveSpeedEvent vme = LocomotiveVelocityMessage.parse(message); notifyLocomotiveSpeedEventListeners(vme); @@ -594,10 +595,9 @@ public void changeVelocity(int locUid, int speed, Direction direction) { //When in Auto mode try to simulate the first sensor the locomotive is suppose to hit. if (AutoPilot.isAutoModeActive() && speed > 0) { //simulateDriving(locUid, speed, direction); - this.simulator.simulateDriving(locUid, speed, direction); + simulator.simulateDriving(locUid, speed, direction); } } - } } diff --git a/src/main/java/jcs/commandStation/marklin/cs/can/CanMessage.java b/src/main/java/jcs/commandStation/marklin/cs/can/CanMessage.java index 533c9ead..fff2fab0 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/can/CanMessage.java +++ b/src/main/java/jcs/commandStation/marklin/cs/can/CanMessage.java @@ -374,7 +374,7 @@ public boolean isResponseComplete() { @Override public String toString() { - return ByteUtil.toHexString(this.getMessage()); + return ByteUtil.toHexString(getMessage()); } public int getNumberOfMeasurementValues() { diff --git a/src/main/java/jcs/commandStation/marklin/cs/net/CSTCPConnection.java b/src/main/java/jcs/commandStation/marklin/cs/net/CSTCPConnection.java index 1dc50456..ff23b27c 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/net/CSTCPConnection.java +++ b/src/main/java/jcs/commandStation/marklin/cs/net/CSTCPConnection.java @@ -205,7 +205,7 @@ public synchronized CanMessage sendCanMessage(CanMessage message) { } //Capture messages for now to be able to develop the virtual mode - Logger.trace("#TX: " + message + " is response " + message.isResponseMessage()); + Logger.trace("#TX: " + message + (message.isResponseMessage() ? " response msg" : "")); if (!message.isResponseMessage()) { if (message.getResponses().size() > 1) { List responses = message.getResponses(); diff --git a/src/main/java/jcs/ui/JCSFrame.form b/src/main/java/jcs/ui/JCSFrame.form index 0296dc07..6906cabb 100755 --- a/src/main/java/jcs/ui/JCSFrame.form +++ b/src/main/java/jcs/ui/JCSFrame.form @@ -1084,12 +1084,12 @@ - + - + @@ -1102,9 +1102,6 @@ - - - @@ -1112,9 +1109,9 @@ - + - + diff --git a/src/main/java/jcs/ui/JCSFrame.java b/src/main/java/jcs/ui/JCSFrame.java index e819661d..f4ed9f97 100755 --- a/src/main/java/jcs/ui/JCSFrame.java +++ b/src/main/java/jcs/ui/JCSFrame.java @@ -37,12 +37,10 @@ import javax.swing.Action; import javax.swing.BorderFactory; import javax.swing.Box; -import javax.swing.BoxLayout; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JCheckBoxMenuItem; import javax.swing.JFrame; -import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; @@ -133,8 +131,8 @@ private void initJCS() { setControllerProperties(); } - //Connect the pannels togetehr for the locomotive selection - dispatcherStatusPanel.addLocomotiveSelectionChangeListener(smallDriverCabPanel1); + //Connect the panels so that they are notified with the locomotive selection + dispatcherStatusPanel.addLocomotiveSelectionChangeListener(smallDriverCabPanel); //Show the default panel showOverviewPanel(); @@ -338,9 +336,9 @@ private void initComponents() { commandStationPanel = new CommandStationPanel(); vncPanel = new VNCPanel(); leftPanel = new JPanel(); - jSplitPane1 = new JSplitPane(); + locoSplitPane = new JSplitPane(); dispatcherStatusPanel = new DispatcherStatusPanel(); - smallDriverCabPanel1 = new SmallDriverCabPanel(); + smallDriverCabPanel = new SmallDriverCabPanel(); jcsMenuBar = new JMenuBar(); fileMenu = new JMenu(); quitMI = new JMenuItem(); @@ -645,19 +643,18 @@ public void actionPerformed(ActionEvent evt) { leftPanel.setPreferredSize(new Dimension(225, 772)); leftPanel.setLayout(new BorderLayout(1, 1)); - jSplitPane1.setDividerLocation(500); - jSplitPane1.setOrientation(JSplitPane.VERTICAL_SPLIT); - jSplitPane1.setToolTipText(""); - jSplitPane1.setName("jSplitPane1"); // NOI18N + locoSplitPane.setDividerLocation(500); + locoSplitPane.setOrientation(JSplitPane.VERTICAL_SPLIT); + locoSplitPane.setToolTipText(""); + locoSplitPane.setName("locoSplitPane"); // NOI18N dispatcherStatusPanel.setName("dispatcherStatusPanel"); // NOI18N - dispatcherStatusPanel.setPreferredSize(new Dimension(300, 450)); - jSplitPane1.setLeftComponent(dispatcherStatusPanel); + locoSplitPane.setLeftComponent(dispatcherStatusPanel); - smallDriverCabPanel1.setName("smallDriverCabPanel1"); // NOI18N - jSplitPane1.setRightComponent(smallDriverCabPanel1); + smallDriverCabPanel.setName("smallDriverCabPanel"); // NOI18N + locoSplitPane.setRightComponent(smallDriverCabPanel); - leftPanel.add(jSplitPane1, BorderLayout.CENTER); + leftPanel.add(locoSplitPane, BorderLayout.CENTER); locoDisplaySP.setLeftComponent(leftPanel); @@ -1209,13 +1206,13 @@ public void powerChanged(PowerEvent event) { private JMenuItem flipTileHorizontallyMI; private JMenuItem flipTileVerticallyMI; private JMenu helpMenu; - private JSplitPane jSplitPane1; private JMenuBar jcsMenuBar; private JToolBar jcsToolBar; private KeyboardSensorPanel keyboardSensorMessagePanel; private LayoutPanel layoutPanel; private JPanel leftPanel; private JSplitPane locoDisplaySP; + private JSplitPane locoSplitPane; private JPanel mainPanel; private LayoutPanel overviewPanel; private JToggleButton powerButton; @@ -1237,7 +1234,7 @@ public void powerChanged(PowerEvent event) { private JMenuItem showRoutesMI; private JMenuItem showSensorMonitor; private JButton showVNCBtn; - private SmallDriverCabPanel smallDriverCabPanel1; + private SmallDriverCabPanel smallDriverCabPanel; private JButton startAllLocsBtn; private JMenuItem startAllLocsMI; private StatusPanel statusPanel; diff --git a/src/main/java/jcs/ui/panel/LocomotiveTablePanel.java b/src/main/java/jcs/ui/panel/LocomotiveTablePanel.java index 7d557f6a..7d8725f6 100644 --- a/src/main/java/jcs/ui/panel/LocomotiveTablePanel.java +++ b/src/main/java/jcs/ui/panel/LocomotiveTablePanel.java @@ -40,7 +40,7 @@ import org.tinylog.Logger; /** - * + * Panel to show locomotives in tabular format */ public class LocomotiveTablePanel extends JPanel implements RefreshEventListener { diff --git a/src/main/java/jcs/ui/panel/SmallDriverCabPanel.form b/src/main/java/jcs/ui/panel/SmallDriverCabPanel.form index 82d6c754..ee13e0a3 100644 --- a/src/main/java/jcs/ui/panel/SmallDriverCabPanel.form +++ b/src/main/java/jcs/ui/panel/SmallDriverCabPanel.form @@ -6,6 +6,11 @@ + + + + + @@ -16,9 +21,6 @@ - - - @@ -30,14 +32,161 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -131,7 +280,7 @@ - + @@ -140,16 +289,16 @@ - + - + - + @@ -157,7 +306,7 @@ - + @@ -169,16 +318,16 @@ - + - + - + @@ -189,12 +338,12 @@ - + - + @@ -205,12 +354,12 @@ - + - + @@ -221,12 +370,12 @@ - + - + @@ -265,24 +414,24 @@ - + - + - + - + @@ -291,21 +440,21 @@ - + - - - + + + - + - + @@ -313,7 +462,7 @@ - + @@ -325,16 +474,16 @@ - + - + - + @@ -349,24 +498,24 @@ - + - + - + - + @@ -375,21 +524,21 @@ - + - - - + + + - + - + @@ -397,11 +546,11 @@ - - + + - + @@ -409,32 +558,35 @@ - + - + - + - + - + - + - + + + + @@ -1559,14 +1711,14 @@ - + - + @@ -1575,19 +1727,19 @@ - + - + - + - + @@ -1595,7 +1747,7 @@ - + @@ -1607,16 +1759,16 @@ - + - + - + @@ -1627,12 +1779,12 @@ - + - + @@ -1643,12 +1795,12 @@ - + - + @@ -1659,12 +1811,12 @@ - + - + diff --git a/src/main/java/jcs/ui/panel/SmallDriverCabPanel.java b/src/main/java/jcs/ui/panel/SmallDriverCabPanel.java index 326c775a..3f1ad795 100644 --- a/src/main/java/jcs/ui/panel/SmallDriverCabPanel.java +++ b/src/main/java/jcs/ui/panel/SmallDriverCabPanel.java @@ -15,25 +15,30 @@ */ package jcs.ui.panel; +import com.twelvemonkeys.image.ImageUtil; import java.awt.Color; +import java.awt.Image; import java.awt.event.ActionEvent; +import java.awt.image.BufferedImage; import java.util.HashMap; import java.util.Map; import javax.swing.ImageIcon; import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; import javax.swing.JSlider; import javax.swing.JToggleButton; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import javax.swing.event.ChangeListener; import jcs.JCS; +import jcs.commandStation.JCSCommandStation; import jcs.commandStation.events.LocomotiveDirectionEvent; import jcs.commandStation.events.LocomotiveDirectionEventListener; import jcs.commandStation.events.LocomotiveFunctionEvent; +import jcs.commandStation.events.LocomotiveFunctionEventListener; import jcs.commandStation.events.LocomotiveSpeedEvent; import jcs.commandStation.events.LocomotiveSpeedEventListener; -import jcs.commandStation.events.PowerEvent; -import jcs.commandStation.events.PowerEventListener; import jcs.entities.FunctionBean; import jcs.entities.LocomotiveBean; import jcs.persistence.PersistenceFactory; @@ -43,16 +48,17 @@ /** * Small function Panel for use in the small driver Cab */ -public class SmallDriverCabPanel extends javax.swing.JPanel implements LocomotiveSelectionChangedListener, LocomotiveDirectionEventListener, LocomotiveSpeedEventListener, PowerEventListener { +public class SmallDriverCabPanel extends JPanel implements LocomotiveSelectionChangedListener, + LocomotiveDirectionEventListener, LocomotiveFunctionEventListener, LocomotiveSpeedEventListener { private final Map buttons; private LocomotiveBean locomotiveBean; - //private final ExecutorService executor; private boolean initButtons = false; private boolean disableListener = false; private boolean power; private boolean enableEvent = true; + //private final ExecutorService executor; public SmallDriverCabPanel() { buttons = new HashMap<>(); @@ -110,7 +116,7 @@ public void setEnabled(boolean enabled) { JToggleButton button = this.buttons.get(i); button.setEnabled(enabled); } - this.buttonsTP.setEnabled(enabled); + buttonsTP.setEnabled(enabled); } //@Override @@ -162,6 +168,12 @@ public void selectionChanged(Long locomotiveId) { Logger.trace("Change selection to LocomotiveId: " + locomotiveId); //Disable listeners! disableListener = true; + if (JCS.getJcsCommandStation() != null) { + JCSCommandStation cs = JCS.getJcsCommandStation(); + cs.removeLocomotiveDirectionEventListener(this); + cs.removeLocomotiveFunctionEventListener(this); + cs.removeLocomotiveSpeedEventListener(this); + } resetButtons(); initButtons = true; @@ -169,6 +181,9 @@ public void selectionChanged(Long locomotiveId) { //Get the locomotive from the persistent layer locomotiveBean = PersistenceFactory.getService().getLocomotive(locomotiveId); + nameLbl.setText(locomotiveBean.getName()); + setLocomotiveImage(locomotiveBean.getLocIcon()); + double max = 100; if (locomotiveBean.getTachoMax() != null) { max = locomotiveBean.getTachoMax(); @@ -216,16 +231,38 @@ public void selectionChanged(Long locomotiveId) { } buttonsTP.setEnabled(true); } + + if (JCS.getJcsCommandStation() != null) { + JCSCommandStation cs = JCS.getJcsCommandStation(); + cs.addLocomotiveDirectionEventListener(this); + cs.addLocomotiveFunctionEventListener(this); + cs.addLocomotiveSpeedEventListener(this); + } + initButtons = false; disableListener = false; } } + private void setLocomotiveImage(Image img) { + if (img != null) { + int size = 40; + float aspect = (float) img.getHeight(null) / (float) img.getWidth(null); + img = img.getScaledInstance(size, (int) (size * aspect), Image.SCALE_SMOOTH); + BufferedImage bi = ImageUtil.toBuffered(img); + iconLbl.setIcon(new ImageIcon(bi)); + iconLbl.setHorizontalAlignment(JLabel.CENTER); + iconLbl.setText(""); + } else { + iconLbl.setText(""); + } + } + /** * * Sets the LocomotiveBean for this panel. This will update the buttons with the correct icons and states. * - * @param locomotiveBean + * @param locomotive */ public void setLocomotiveBean(LocomotiveBean locomotive) { selectionChanged(locomotive.getId()); @@ -284,7 +321,11 @@ private void changeFunction(boolean newValue, Integer functionNumber, Locomotive private void initComponents() { directionBG = new javax.swing.ButtonGroup(); - jPanel1 = new javax.swing.JPanel(); + northPanel = new javax.swing.JPanel(); + iconLbl = new javax.swing.JLabel(); + filler2 = new javax.swing.Box.Filler(new java.awt.Dimension(20, 0), new java.awt.Dimension(20, 0), new java.awt.Dimension(20, 32767)); + nameLbl = new javax.swing.JLabel(); + rightPanel = new javax.swing.JPanel(); jPanel3 = new javax.swing.JPanel(); speed1Button = new javax.swing.JButton(); speed2Button = new javax.swing.JButton(); @@ -292,7 +333,7 @@ private void initComponents() { speed4Button = new javax.swing.JButton(); jPanel4 = new javax.swing.JPanel(); speedSlider = new javax.swing.JSlider(); - jPanel2 = new javax.swing.JPanel(); + centerPanel = new javax.swing.JPanel(); buttonsTP = new javax.swing.JTabbedPane(); f0f7Panel = new javax.swing.JPanel(); f0TB = new javax.swing.JToggleButton(); @@ -336,18 +377,36 @@ private void initComponents() { filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(30, 0), new java.awt.Dimension(30, 0), new java.awt.Dimension(30, 32767)); stopButton = new javax.swing.JButton(); + setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 1, 1)); setMaximumSize(new java.awt.Dimension(300, 200)); setMinimumSize(new java.awt.Dimension(300, 200)); setName("Form"); // NOI18N setPreferredSize(new java.awt.Dimension(300, 200)); - setSize(new java.awt.Dimension(300, 200)); setLayout(new java.awt.BorderLayout()); - jPanel1.setName("jPanel1"); // NOI18N - jPanel1.setPreferredSize(new java.awt.Dimension(80, 200)); + northPanel.setName("northPanel"); // NOI18N + northPanel.setPreferredSize(new java.awt.Dimension(300, 30)); + java.awt.FlowLayout flowLayout4 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); + flowLayout4.setAlignOnBaseline(true); + northPanel.setLayout(flowLayout4); + + iconLbl.setName("iconLbl"); // NOI18N + northPanel.add(iconLbl); + + filler2.setName("filler2"); // NOI18N + northPanel.add(filler2); + + nameLbl.setFont(new java.awt.Font("sansserif", 1, 13)); // NOI18N + nameLbl.setName("nameLbl"); // NOI18N + northPanel.add(nameLbl); + + add(northPanel, java.awt.BorderLayout.NORTH); + + rightPanel.setName("rightPanel"); // NOI18N + rightPanel.setPreferredSize(new java.awt.Dimension(80, 200)); java.awt.FlowLayout flowLayout2 = new java.awt.FlowLayout(java.awt.FlowLayout.RIGHT, 1, 5); flowLayout2.setAlignOnBaseline(true); - jPanel1.setLayout(flowLayout2); + rightPanel.setLayout(flowLayout2); jPanel3.setName("jPanel3"); // NOI18N jPanel3.setPreferredSize(new java.awt.Dimension(38, 200)); @@ -403,7 +462,7 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { }); jPanel3.add(speed4Button); - jPanel1.add(jPanel3); + rightPanel.add(jPanel3); jPanel4.setMinimumSize(new java.awt.Dimension(40, 200)); jPanel4.setName("jPanel4"); // NOI18N @@ -423,13 +482,14 @@ public void stateChanged(javax.swing.event.ChangeEvent evt) { }); jPanel4.add(speedSlider); - jPanel1.add(jPanel4); + rightPanel.add(jPanel4); - add(jPanel1, java.awt.BorderLayout.EAST); + add(rightPanel, java.awt.BorderLayout.EAST); - jPanel2.setName("jPanel2"); // NOI18N - jPanel2.setPreferredSize(new java.awt.Dimension(220, 200)); - jPanel2.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT, 1, 5)); + centerPanel.setMinimumSize(new java.awt.Dimension(220, 200)); + centerPanel.setName("centerPanel"); // NOI18N + centerPanel.setPreferredSize(new java.awt.Dimension(220, 200)); + centerPanel.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT, 1, 5)); buttonsTP.setTabLayoutPolicy(javax.swing.JTabbedPane.SCROLL_TAB_LAYOUT); buttonsTP.setTabPlacement(javax.swing.JTabbedPane.BOTTOM); @@ -982,7 +1042,7 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { buttonsTP.addTab("F24 - F31", f24f31Panel); - jPanel2.add(buttonsTP); + centerPanel.add(buttonsTP); southPanel.setMinimumSize(new java.awt.Dimension(300, 50)); southPanel.setName("southPanel"); // NOI18N @@ -1030,9 +1090,9 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { }); southPanel.add(stopButton); - jPanel2.add(southPanel); + centerPanel.add(southPanel); - add(jPanel2, java.awt.BorderLayout.CENTER); + add(centerPanel, java.awt.BorderLayout.CENTER); }// //GEN-END:initComponents private void f12TBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_f12TBActionPerformed @@ -1225,13 +1285,15 @@ private void stopButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FI private void speedSliderStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_speedSliderStateChanged JSlider slider = (JSlider) evt.getSource(); if (!slider.getValueIsAdjusting()) { - + Logger.trace("Change speed of "); if (!disableListener && locomotiveBean != null) { - int max = locomotiveBean.getTachoMax(); + int max = locomotiveBean.getTachoMax(); double value = slider.getValue(); //Velocity is always between 0 and 1000 int velocity = (int) Math.round(value / max * 1000); //executor.execute(() -> changeVelocity(velocity, locomotiveBean)); + Logger.trace("Changing speed to "+velocity+" for "+locomotiveBean.getId()); + changeVelocity(velocity, locomotiveBean); } } @@ -1260,6 +1322,11 @@ private void changeDirection(LocomotiveBean.Direction newDirection, LocomotiveBe // } } + /** + * Called when the direction is changed from external source + * + * @param event + */ @Override public void onDirectionChange(LocomotiveDirectionEvent event) { LocomotiveBean lb = event.getLocomotiveBean(); @@ -1287,40 +1354,28 @@ public void onSpeedChange(LocomotiveSpeedEvent event) { locomotiveBean.setVelocity(lb.getVelocity()); + disableListener = true; + int velocity = locomotiveBean.getVelocity(); double max = locomotiveBean.getTachoMax(); int sliderValue = (int) Math.round(max / 1000 * velocity); //set the slider value without triggering a change event - ChangeListener[] changeListeners = this.speedSlider.getChangeListeners(); + ChangeListener[] changeListeners = speedSlider.getChangeListeners(); for (ChangeListener changeListener : changeListeners) { - this.speedSlider.removeChangeListener(changeListener); + speedSlider.removeChangeListener(changeListener); } - this.speedSlider.setValue(sliderValue); + speedSlider.setValue(sliderValue); - //max = this.speedGauge.getMaxValue(); - double gaugeValue = Math.round(max / 1000 * velocity); - //this.speedGauge.setValue(gaugeValue); -// this.speedGauge.setValueAnimated(gaugeValue); - -// this.speedGauge.setUserLedOn(this.power); -// this.speedGauge.setLedBlinking(!this.power); + disableListener = false; for (ChangeListener changeListener : changeListeners) { - this.speedSlider.addChangeListener(changeListener); + speedSlider.addChangeListener(changeListener); } } } - @Override - public void onPowerChange(PowerEvent event) { - if (locomotiveBean != null) { - power = event.isPower(); - Logger.trace("Power is " + (power ? "On" : "Off")); - } - } - public static void main(String args[]) { try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); @@ -1359,6 +1414,7 @@ public void windowClosing(java.awt.event.WindowEvent e) { // Variables declaration - do not modify//GEN-BEGIN:variables javax.swing.JTabbedPane buttonsTP; + javax.swing.JPanel centerPanel; javax.swing.ButtonGroup directionBG; javax.swing.JToggleButton f0TB; javax.swing.JPanel f0f7Panel; @@ -1397,12 +1453,15 @@ public void windowClosing(java.awt.event.WindowEvent e) { javax.swing.JPanel f8f15Panel; javax.swing.JToggleButton f9TB; javax.swing.Box.Filler filler1; + javax.swing.Box.Filler filler2; javax.swing.JToggleButton forwardButton; - javax.swing.JPanel jPanel1; - javax.swing.JPanel jPanel2; + javax.swing.JLabel iconLbl; javax.swing.JPanel jPanel3; javax.swing.JPanel jPanel4; + javax.swing.JLabel nameLbl; + javax.swing.JPanel northPanel; javax.swing.JToggleButton reverseButton; + javax.swing.JPanel rightPanel; javax.swing.JPanel southPanel; javax.swing.JButton speed1Button; javax.swing.JButton speed2Button; From fc5c58985732dccf54355a83c772e11204a22966 Mon Sep 17 00:00:00 2001 From: Frans Jacobs <41232225+fransjacobs@users.noreply.github.com> Date: Fri, 2 May 2025 23:53:37 +0200 Subject: [PATCH 47/70] Refactor Marklin messageparsing --- .../commandStation/entities/DeviceBean.java | 23 +- .../entities/MeasurementBean.java | 53 +++ .../marklin/cs/MarklinCentralStationImpl.java | 294 +++++++++--- .../marklin/cs/can/CanMessage.java | 18 + .../marklin/cs/can/device/CanDevice.java | 360 +++++++++++++++ .../marklin/cs/can/device/ConfigChannel.java | 282 ++++++++++++ .../cs/can/device/MeasuringChannel.java | 345 ++++++++++++++ .../marklin/cs/can/parser/CanDevices.java | 420 ++++++++++++++++++ .../marklin/cs/can/parser/CanDevicesTest.java | Bin 0 -> 13962 bytes 9 files changed, 1726 insertions(+), 69 deletions(-) create mode 100644 src/main/java/jcs/commandStation/entities/MeasurementBean.java create mode 100644 src/main/java/jcs/commandStation/marklin/cs/can/device/CanDevice.java create mode 100644 src/main/java/jcs/commandStation/marklin/cs/can/device/ConfigChannel.java create mode 100644 src/main/java/jcs/commandStation/marklin/cs/can/device/MeasuringChannel.java create mode 100644 src/main/java/jcs/commandStation/marklin/cs/can/parser/CanDevices.java create mode 100644 src/test/java/jcs/commandStation/marklin/cs/can/parser/CanDevicesTest.java diff --git a/src/main/java/jcs/commandStation/entities/DeviceBean.java b/src/main/java/jcs/commandStation/entities/DeviceBean.java index c9175150..bdd1ccb1 100644 --- a/src/main/java/jcs/commandStation/entities/DeviceBean.java +++ b/src/main/java/jcs/commandStation/entities/DeviceBean.java @@ -52,6 +52,8 @@ public class DeviceBean { private String articleNumber; private String serial; private Integer queryInteval; + private Integer measureChannels; + private Integer configChannels; private String version; private Boolean present; @@ -297,19 +299,27 @@ private void buildFromMessage(CanMessage message) { System.arraycopy(data, 6, deva, 0, deva.length); int uidAsInt = resp.getDeviceUidNumberFromMessage(); - - this.uid = "0x" + Integer.toHexString(uidAsInt); + uid = "0x" + Integer.toHexString(uidAsInt); //this.uid = resp.getDeviceUidNumberFromMessage(); //TODO: Version is not same displayed in the CS - this.version = "" + CanMessage.toInt(vera); + version = "" + CanMessage.toInt(vera); //TODO: in case of a Link S88 it is offset by 1 so device ID + 1 int identifierAsInt = CanMessage.toInt(deva); - this.identifier = "0x" + Integer.toHexString(identifierAsInt); + identifier = "0x" + Integer.toHexString(identifierAsInt); //this.identifier = CanMessage.toInt(deva); } } + +//Requesting more info for uid: 0x53385c41 +//#TX: 0x00 0x3a 0x7b 0x79 0x05 0x53 0x38 0x5c 0x41 0x00 0x00 0x00 0x00 index is 0 device description +//#RX 0: 0x00 0x3b 0x03 0x01 0x08 0x00 0x0c 0x00 0x00 0x00 0x00 0x24 0x41 char meetwaarde in device 0x00 0x0c aanta config channels0x00 0x00 U32 serie nr 0x24 0x41 +//#RX 1: 0x00 0x3b 0x03 0x02 0x08 0x36 0x30 0x38 0x38 0x33 0x00 0x00 0x00 +//#RX 2: 0x00 0x3b 0x03 0x03 0x08 0x4c 0x69 0x6e 0x6b 0x20 0x53 0x38 0x38 +//#RX 3: 0x00 0x3b 0x03 0x04 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 +//#RX 4: 0x00 0x3b 0x3f 0x3c 0x06 0x53 0x38 0x5c 0x41 0x00 0x04 0x00 0x00 + public void updateFromMessage(CanMessage message) { //Filter the responses @@ -319,11 +329,6 @@ public void updateFromMessage(CanMessage message) { responses.add(resp); } } - -// Logger.trace(message); -// for (CanMessage r : responses) { -// Logger.trace(r); -// } if (!responses.isEmpty()) { //The last response has the total response messages CanMessage last = responses.get(responses.size() - 1); diff --git a/src/main/java/jcs/commandStation/entities/MeasurementBean.java b/src/main/java/jcs/commandStation/entities/MeasurementBean.java new file mode 100644 index 00000000..76c3c7c7 --- /dev/null +++ b/src/main/java/jcs/commandStation/entities/MeasurementBean.java @@ -0,0 +1,53 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.commandStation.entities; + +import java.util.Date; + +/** + * Object to hold measured values + */ +public class MeasurementBean { + + private String name; + private Double value; + private String unit; + private Date measurementTime; + + private String selection; + private String config; + private Double endValue; + private Integer colorYellow; + private Integer colorGreen; + private Integer colorMax; + private Integer colorRed; + private Integer index; + private Boolean present; + private Integer min; + private Integer max; + private Integer number; + private Boolean ready; + private Integer rangeYellow; + private Integer rangeGreen; + private Integer rangeMax; + private Integer rangeRed; + private Integer scale; + private Double startValue; + private Integer type; + private Integer previousValue; + private Double humanValue; + +} diff --git a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java index bdac0ee3..4e198566 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java +++ b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java @@ -15,12 +15,15 @@ */ package jcs.commandStation.marklin.cs; +import jcs.commandStation.marklin.cs.can.device.CanDevice; import jcs.commandStation.marklin.cs.can.parser.FeedbackEventMessage; import java.awt.Image; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; import java.util.concurrent.Executors; import java.util.concurrent.TransferQueue; import java.util.stream.Collectors; @@ -72,6 +75,7 @@ import jcs.commandStation.autopilot.DriveSimulator; import jcs.commandStation.events.DisconnectionEvent; import jcs.commandStation.events.DisconnectionEventListener; +import jcs.commandStation.marklin.cs.can.parser.CanDevices; import jcs.commandStation.marklin.cs.can.parser.LocomotiveEmergencyStopMessage; import jcs.entities.LocomotiveBean; import jcs.entities.LocomotiveBean.Direction; @@ -99,6 +103,10 @@ public class MarklinCentralStationImpl extends AbstractController implements Dec private DriveSimulator simulator; + private Long canBootLoaderLastCallMillis; + private WatchdogTask watchdogTask; + private Timer watchDogTimer; + public MarklinCentralStationImpl(CommandStationBean commandStationBean) { this(commandStationBean, false); } @@ -158,14 +166,11 @@ public final synchronized boolean connect() { } CSConnection csConnection = CSConnectionFactory.getConnection(virtual); - if (csConnection != null) { - csConnection.addDisconnectionEventListener(this); - } connection = csConnection; if (connection != null) { - //Wait, if needed until the receiver thread has started + //Wait until the receiver thread has started long now = System.currentTimeMillis(); long timeout = now + 1000L; @@ -178,6 +183,8 @@ public final synchronized boolean connect() { } if (connected) { + canBootLoaderLastCallMillis = System.currentTimeMillis(); + //The eventMessageHandler Thread is in charge to handle all event messages which are send from the CS to JCS eventMessageHandler = new EventMessageHandler(connection); eventMessageHandler.start(); @@ -209,6 +216,8 @@ public final synchronized boolean connect() { Logger.warn("No main Device found yet..."); } + csConnection.addDisconnectionEventListener(this); + startWatchdog(); power = isPower(); JCS.logProgress("Power is " + (power ? "On" : "Off")); @@ -220,9 +229,9 @@ public final synchronized boolean connect() { } } - if (isCS3()) { - getMembers(); - } +// if (isCS3()) { +// getMembers(); +// } if (isVirtual()) { simulator = new DriveSimulator(); Logger.info("Marklin Central Station Virtual Mode Enabled!"); @@ -277,13 +286,13 @@ private void getAppDevicesCs3() { } String an = d.getArticleNumber(); if ("60213".equals(an) || "60214".equals(an) || "60215".equals(an) || "60126".equals(an) || "60226".equals(an)) { - this.csUid = d.getUidAsInt(); - this.mainDevice = d; + csUid = d.getUidAsInt(); + mainDevice = d; Logger.trace("MainDevice: " + d.getName()); } if ("60883".equals(an)) { - this.feedbackDevice = d; + feedbackDevice = d; Logger.trace("FeedbackDevice: " + d.getName()); } @@ -389,44 +398,38 @@ public void onDisconnect(DisconnectionEvent event) { } } +//#TX: 0x00 0x30 0x07 0x69 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 -> Member ping +//#RX 0: 0x00 0x31 0x37 0x7e 0x08 0x63 0x73 0x45 0x8d 0x02 0x05 0xff 0xff -> Response member CS2-GUI (Master) sw 0x02 0x05 id: 0x63 0x73 0x45 0x8d +//#RX 1: 0x00 0x31 0x7b 0x79 0x08 0x53 0x38 0x5c 0x41 0x01 0x01 0x00 0x40 -> ? sw 0x01 0x01 id: 0x53 0x38 0x5c 0x41 +//#RX 2: 0x00 0x31 0x03 0x26 0x08 0x63 0x73 0x45 0x8c 0x0c 0x71 0x00 0x50 -> ? sw 0x0c 0x71 id: 0x63 0x73 0x45 0x8c void getMembers() { CanMessage msg = CanMessageFactory.getMembersPing(); connection.sendCanMessage(msg); - if (debug) { - Logger.trace(msg); - for (CanMessage r : msg.getResponses()) { - Logger.trace(r); - } - } - for (CanMessage r : msg.getResponses()) { DeviceBean d = new DeviceBean(r); if (!devices.containsKey(d.getUidAsInt())) { devices.put(d.getUidAsInt(), d); } - if (debug) { - Logger.trace("Found uid: " + d.getUid() + " deviceId: " + d.getIdentifier() + " Device Type: " + d.getDevice()); - } - } - if (debug) { - Logger.trace("Found " + this.devices.size() + " devices"); + Logger.trace("Found uid: " + d.getUid() + " deviceId: " + d.getIdentifier() + " Device Type: " + d.getDevice()); } + Logger.trace("Found " + devices.size() + " devices"); + while (mainDevice == null) { - for (DeviceBean d : this.getDevices()) { + for (DeviceBean d : getDevices()) { if (!d.isDataComplete()) { if (debug) { Logger.trace("Requesting more info for uid: " + d.getUid()); } CanMessage updateMessage = sendMessage(CanMessageFactory.statusDataConfig(d.getUidAsInt(), 0)); - if (debug) { - Logger.trace(updateMessage); - for (CanMessage r : updateMessage.getResponses()) { - Logger.trace(r); - } + //if (debug) { + Logger.trace(updateMessage); + for (CanMessage r : updateMessage.getResponses()) { + Logger.trace(r); } + //} d.updateFromMessage(updateMessage); if (debug) { if (d.isDataComplete()) { @@ -438,7 +441,7 @@ void getMembers() { } } - for (DeviceBean d : this.getDevices()) { + for (DeviceBean d : getDevices()) { if (d.isDataComplete() && ("60213".equals(d.getArticleNumber()) || "60214".equals(d.getArticleNumber()) || "60215".equals(d.getArticleNumber()) || "60126".equals(d.getArticleNumber()) || "60226".equals(d.getArticleNumber()))) { csUid = d.getUidAsInt(); mainDevice = d; @@ -460,6 +463,130 @@ void getMembers() { } } + //Map devices; + void memberPing() { + Map members = new HashMap<>(); + CanMessage msg = CanMessageFactory.getMembersPing(); + connection.sendCanMessage(msg); + + List canDevices = CanDevices.parse(msg); + for (CanDevice d : canDevices) { + if (!members.containsKey(d.getUidInt())) { + members.put(d.getUidInt(), d); + } + } + + for (CanDevice device : canDevices) { + Logger.trace("Device: " + device); + } + + //Lets get some info about these members + //for (CanDevice d : members.values()) { + for (CanDevice device : canDevices) { + //if ("0x6373458c".equals(device.getUid())) { + if ("0x53385c41".equals(device.getUid())) { + //if (!d.isDataComplete()) { + Logger.trace("Query Device data for uid: " + device.getUid()); + + CanMessage updateMessage = sendMessage(CanMessageFactory.statusDataConfig(device.getUidInt(), 0)); + CanDevices.parse(device, updateMessage); + + Logger.trace("Device: " + device); + + int measurementChannels; + if (device.getMeasureChannelCount() == null) { + measurementChannels = 0; + } else { + measurementChannels = device.getMeasureChannelCount(); + } + int configChannels; + if (device.getConfigChannelCount() == null) { + configChannels = 0; + } else { + configChannels = device.getConfigChannelCount(); + } + + Logger.trace("Device " + device.getName() + " has " + measurementChannels + " Measurement Channels and " + configChannels + " Config Channels"); + int channels = measurementChannels + configChannels; + if (channels > 0) { + for (int index = 1; index <= channels; index++) { + updateMessage = sendMessage(CanMessageFactory.statusDataConfig(device.getUidInt(), index)); + CanDevices.parse(device, updateMessage); + } + } + } + } +// // d.updateFromMessage(updateMessage); +// +// Logger.trace("Updated with device info: " + d); +// +// if (d.getMeasureChannels() != null && d.getMeasureChannels() > 0) { +// Logger.trace(d.getMeasureChannels() + " Measurement Channels"); +// //Query the measurement channels +// int max = d.getMeasureChannels(); +// for (int ch = 1; ch <= max; ch++) { +// Logger.trace("Query measurment channels for device " + d.getName() + " and measure channel " + ch); +// updateMessage = sendMessage(CanMessageFactory.statusDataConfig(d.getUidAsInt(), ch)); +// d.updateFromMessage(updateMessage); +// +// Logger.trace("# Updated after ch " + ch + " " + d); +// +// } +// Logger.trace("Updated " + d); +// } +// +// if (d.getConfigChannels() != null && d.getConfigChannels() > 0 && 1==2) { +// Logger.trace(d.getConfigChannels() + " Config Channels"); +// //Get the channels +// int max = d.getConfigChannels(); +// for (int ch = 1; ch < max; ch++) { +// Logger.trace("Requesting more info for uid: " + d.getUid() + " and config channel " + ch); +// +// updateMessage = sendMessage(CanMessageFactory.statusDataConfig(d.getUidAsInt(), ch)); +// if (updateMessage.hasValidResponse()) { +// d.updateFromMessage(updateMessage); +// } else { +// break; +// } +// } +// Logger.trace("Updated " + d); +// //} +// +// if (d.isDataComplete()) { +// Logger.trace("#Updated: " + d); +// } else { +// Logger.trace("No data received for Device uid: " + d.getUid()); +// } +// +// } else { +// Logger.trace("Data complete for " + d); +// +// } +// } +// } + +// for (DeviceBean d : getDevices()) { +// if (d.isDataComplete() && ("60213".equals(d.getArticleNumber()) || "60214".equals(d.getArticleNumber()) || "60215".equals(d.getArticleNumber()) || "60126".equals(d.getArticleNumber()) || "60226".equals(d.getArticleNumber()))) { +// csUid = d.getUidAsInt(); +// mainDevice = d; +// if (debug) { +// Logger.trace("Main Device: " + d); +// } +// if (System.getProperty("cs.article") == null) { +// System.setProperty("cs.article", mainDevice.getArticleNumber()); +// System.setProperty("cs.serial", mainDevice.getSerial()); +// System.setProperty("cs.name", mainDevice.getName()); +// System.setProperty("cs.cs3", (isCS3() ? "true" : "false")); +// } +// } else { +// if (debug) { +// Logger.trace(d); +// } +// } +// +// } + } + private void updateDevice(final CanMessage message) { if (CanMessage.PING_RESP == message.getCommand()) { int uid = message.getDeviceUidNumberFromMessage(); @@ -494,11 +621,11 @@ private void updateDevice(final CanMessage message) { //Lets send a ping again getMembers(); } else { - if (mainDevice != null && this.mainDevice.isDataComplete()) { + if (mainDevice != null && mainDevice.isDataComplete()) { if (System.getProperty("cs.article") == null) { - System.setProperty("cs.article", this.mainDevice.getArticleNumber()); - System.setProperty("cs.serial", this.mainDevice.getSerial()); - System.setProperty("cs.name", this.mainDevice.getName()); + System.setProperty("cs.article", mainDevice.getArticleNumber()); + System.setProperty("cs.serial", mainDevice.getSerial()); + System.setProperty("cs.name", mainDevice.getName()); System.setProperty("cs.cs3", (isCS3() ? "true" : "false")); if (debug) { Logger.trace("CS " + (isCS3() ? "3" : "2") + " Device: " + device); @@ -517,9 +644,9 @@ public boolean isSupportTrackMeasurements() { @Override public synchronized Map getTrackMeasurements() { Logger.trace("Perform measurement..."); - if (this.connected && this.mainDevice != null) { + if (connected && mainDevice != null) { //main device - int nrOfChannels = this.mainDevice.getAnalogChannels().size(); + int nrOfChannels = mainDevice.getAnalogChannels().size(); ChannelDataParser parser = new ChannelDataParser(); @@ -543,7 +670,7 @@ public synchronized Map getTrackMeasurements() { } } } - return this.analogChannels; + return analogChannels; } /** @@ -584,9 +711,9 @@ public void changeVelocity(int locUid, int speed, Direction direction) { //VelocityChange 0x00 0x09 0x03 0x26 0x06 0x00 0x00 0x40 0x0c 0x00 0x30 0x00 0x00 //16396 CanMessage message = CanMessageFactory.setLocSpeed(locUid, speed, csUid); - Logger.trace("Ch Velocity for uid: "+locUid+" -> "+message); + Logger.trace("Ch Velocity for uid: " + locUid + " -> " + message); message = sendMessage(message); - + LocomotiveSpeedEvent vme = LocomotiveVelocityMessage.parse(message); notifyLocomotiveSpeedEventListeners(vme); @@ -795,7 +922,7 @@ private void notifyLocomotiveSpeedEventListeners(final LocomotiveSpeedEvent spee } } - //TODO Watchdog and measurements als a kind of data table... + //TODO measurements als a kind of data table... /** * Handle Event Message, which are unsolicited messages from the CS. */ @@ -860,7 +987,7 @@ public void run() { case CanMessage.STATUS_CONFIG -> { if (CanMessage.JCS_UID == uid && CanMessage.DLC_5 == dlc) { Logger.trace("StatusConfig RQ: " + eventMessage); - sentJCSInformationMessage(); + //sentJCSInformationMessage(); } } case CanMessage.STATUS_CONFIG_RESP -> { @@ -887,7 +1014,7 @@ public void run() { } } case CanMessage.SYSTEM_COMMAND -> { - Logger.trace("SystemConfigCommand RX: " + eventMessage); + //Logger.trace("SystemConfigCommand RX: " + eventMessage); } case CanMessage.SYSTEM_COMMAND_RESP -> { switch (subcmd) { @@ -929,7 +1056,7 @@ public void run() { } case CanMessage.LOC_VELOCITY_RESP -> { Logger.trace("VelocityChange " + eventMessage); - + notifyLocomotiveSpeedEventListeners(LocomotiveVelocityMessage.parse(eventMessage)); } case CanMessage.LOC_DIRECTION -> { @@ -946,13 +1073,11 @@ public void run() { case CanMessage.LOC_FUNCTION_RESP -> { notifyLocomotiveFunctionEventListeners(LocomotiveFunctionEventParser.parseMessage(eventMessage)); } + case CanMessage.BOOTLOADER_CAN -> { + //Update the last time millis. Used for the watchdog timer. + canBootLoaderLastCallMillis = System.currentTimeMillis(); + } default -> { - if (CanMessage.BOOTLOADER_CAN != 0x36) { - //Do not log the bootloader message. it is not used in JCS. - if (debug) { - Logger.trace("# " + eventMessage); - } - } } } @@ -962,7 +1087,51 @@ public void run() { } Logger.debug("Stop Event handling"); + } + } + private void startWatchdog() { + long checkInterval = Long.parseLong(System.getProperty("connection.watchdog.interval", "10")); + checkInterval = checkInterval * 1000; + + if (checkInterval > 0 && !virtual) { + watchdogTask = new WatchdogTask(this); + watchDogTimer = new Timer("WatchDogTimer"); + watchDogTimer.schedule(watchdogTask, 0, checkInterval); + Logger.debug("Started Watchdog Timer with an interval of " + checkInterval + "ms"); + } else { + Logger.debug("Skipping Watchdog Timer"); + } + } + + private class WatchdogTask extends TimerTask { + + private final MarklinCentralStationImpl commandStation; + private final long checkInterval; + + WatchdogTask(MarklinCentralStationImpl commandStation) { + this.commandStation = commandStation; + checkInterval = Long.parseLong(System.getProperty("connection.watchdog.interval", "10")) * 1000; + } + + @Override + public void run() { + if (commandStation.isConnected() && !virtual) { + Long now = System.currentTimeMillis(); + long diff = now - commandStation.canBootLoaderLastCallMillis; + boolean connectionLost = checkInterval < diff; + + if (connectionLost) { + Logger.trace("The last CANBootLoader request is received more than " + (checkInterval / 1000) + "s ago!"); + DisconnectionEvent de = new DisconnectionEvent("Marklin Central Station"); + commandStation.onDisconnect(de); + } + } else { + //Try to reconnect + if (!virtual && "true".equalsIgnoreCase(System.getProperty("controller.autoconnect", "true"))) { + commandStation.connect(); + } + } } } @@ -988,26 +1157,30 @@ public static void main(String[] a) { csb.setProtocols("DCC,MFX,MM"); csb.setDefault(true); csb.setEnabled(true); - csb.setVirtual(true); + csb.setVirtual(false); MarklinCentralStationImpl cs = new MarklinCentralStationImpl(csb, false); + cs.debug = true; + Logger.debug((cs.connect() ? "Connected" : "NOT Connected")); if (cs.isConnected()) { - Logger.debug("Power is " + (cs.isPower() ? "ON" : "Off")); - cs.power(false); - Logger.debug("Power is " + (cs.isPower() ? "ON" : "Off")); - cs.power(true); - - Logger.debug("Switch Accessory 2 to Red"); - //cs.switchAccessory(2, AccessoryValue.RED, 250); - - Logger.debug("Switch Accessory 2 to Green"); +// Logger.debug("Power is " + (cs.isPower() ? "ON" : "Off")); +// cs.power(false); +// Logger.debug("Power is " + (cs.isPower() ? "ON" : "Off")); +// cs.power(true); +// +// Logger.debug("Switch Accessory 2 to Red"); +// //cs.switchAccessory(2, AccessoryValue.RED, 250); +// +// Logger.debug("Switch Accessory 2 to Green"); //cs.switchAccessory(2, AccessoryValue.GREEN, 250); //cs.getLocomotivesViaCAN(); //cs.getAccessoriesViaCan(); //cs.pause(2000); + //cs.getMembers(); + cs.memberPing(); //Logger.trace("getStatusDataConfig CS3"); //cs.getStatusDataConfigCS3(); //cs.pause(2000); @@ -1099,7 +1272,8 @@ public static void main(String[] a) { // for (LocomotiveBean loc : locs) { // Logger.trace(loc); // } - cs.pause(40000); + //cs.pause(40000); + cs.pause(20000); cs.disconnect(); // cs.pause(100L); Logger.debug("DONE"); diff --git a/src/main/java/jcs/commandStation/marklin/cs/can/CanMessage.java b/src/main/java/jcs/commandStation/marklin/cs/can/CanMessage.java index fff2fab0..b70d8898 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/can/CanMessage.java +++ b/src/main/java/jcs/commandStation/marklin/cs/can/CanMessage.java @@ -91,10 +91,27 @@ public static final int toInt(byte[] value) { return val; } + public static int getStringLength(byte[] data) { + //A string is terminated with 0x00. Return the lengt before the termination + for (int l = 0; l < data.length; l++) { + if (data[l] == 0) { + //found terminator + return l; + } + } + return data.length; + } + public static String toString(byte[] data) { return new String(data); } + public static String toString(byte[] data, int length) { + byte[] stringData = new byte[length]; + System.arraycopy(data, 0, stringData, 0, stringData.length); + return new String(stringData); + } + public static final byte toByte(int value) { byte[] bts = to2Bytes(value); return bts[1]; @@ -440,6 +457,7 @@ public static final byte[] generateHash(int gfpUid) { * 0x00 0x00 0x07 0x69 0x04 0x00 0x00 0x00 0x00 0x00 0xab 0x00 0xfc * * @param message a CAN message with content as in the given String + * @return */ public static CanMessage parse(String message) { return parse(message, false); diff --git a/src/main/java/jcs/commandStation/marklin/cs/can/device/CanDevice.java b/src/main/java/jcs/commandStation/marklin/cs/can/device/CanDevice.java new file mode 100644 index 00000000..639b4eec --- /dev/null +++ b/src/main/java/jcs/commandStation/marklin/cs/can/device/CanDevice.java @@ -0,0 +1,360 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.commandStation.marklin.cs.can.device; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import jcs.commandStation.marklin.cs.can.CanMessage; +import org.json.JSONArray; +import org.json.JSONObject; + +/** + * A CanDevice is a Device inside or connected to the Marklin Central Station
+ * Example devices are:
+ * - Central Station self
+ * - GFP (Gleis Format Prozessor)
+ * - Link S88
+ */ +public class CanDevice { + + public static final String MAIN = "MAIN"; + public static final String PROG = "PROG"; + public static final String VOLT = "VOLT"; + public static final String TEMP = "TEMP"; + + public static final String BUS0 = "Auswertung 1 - 16"; + public static final String BUS1 = "Bus 1 (RJ45-1)"; + public static final String BUS2 = "Bus 2 (RJ45-2)"; + public static final String BUS3 = "Bus 3 (6-Polig)"; + +// Absender Geräte UID +// SW-Versionsnummer +// Gerätekennung +// Anzahl der Messwerte im Gerät. +// Anzahl der Konfigurationskanäle +// frei. +// Seriennummer CS2. +// 8 Byte Artikelnummer. +// Gerätebezeichnung, \0 Terminiert + private String uid; + private String version; + private String identifier; + private Integer measureChannelCount; + private Integer configChannelCount; + private String serial; + private String articleNumber; + private String name; + +// private String typeName; +// private String type; +// private Integer queryInteval; +// private Boolean present; +// private Integer available; +// private String config; +// private Boolean ready; +// private String path; +// private Boolean mounted; +// private final List channels; + private final Map measuringChannels; + private final Map configChannels; + + public CanDevice() { + this((String) null); + } + + /** + * Constructor for CS 3 JSON + * + * @param json + */ + public CanDevice(String json) { + measuringChannels = new HashMap<>(); + configChannels = new HashMap<>(); + if (json != null) { + parse(json); + } + } + + /** + * Constructor for CAN + * + * @param message + */ + public CanDevice(CanMessage message) { + measuringChannels = new HashMap<>(); + configChannels = new HashMap<>(); + } + + public String getUid() { + return uid; + } + + public void setUid(String uid) { + this.uid = uid; + } + + public Integer getUidInt() { + String ui = uid.replace("0x", ""); + return Integer.parseUnsignedInt(ui, 16); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getIdentifier() { + return identifier; + } + + public void setIdentifier(String identifier) { + this.identifier = identifier; + } + + public Integer getIdentifierInt() { + String id = identifier.replace("0x", ""); + return Integer.parseUnsignedInt(id, 16); + } + + public String getArticleNumber() { + return articleNumber; + } + + public void setArticleNumber(String articleNumber) { + this.articleNumber = articleNumber; + } + + public String getSerial() { + return serial; + } + + public void setSerial(String serial) { + this.serial = serial; + } + + public Integer getMeasureChannelCount() { + return measureChannelCount; + } + + public void setMeasureChannelCount(Integer measureChannelCount) { + this.measureChannelCount = measureChannelCount; + } + + public Integer getConfigChannelCount() { + return configChannelCount; + } + + public void setConfigChannelCount(Integer configChannelCount) { + this.configChannelCount = configChannelCount; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + private void parse(String json) { + if (json == null) { + return; + } + JSONObject device = new JSONObject(json); + + this.uid = device.optString("_uid"); + this.name = device.optString("_name"); + //this.typeName = device.optString("_typname"); + this.identifier = device.optString("_kennung"); + //this.type = device.optString("_typ"); + this.articleNumber = device.optString("_artikelnr"); + this.serial = device.optString("_seriennr"); + //this.queryInteval = device.optInt("_queryInterval"); + + JSONObject versionObj = device.optJSONObject("_version"); + if (versionObj != null) { + String major = versionObj.optString("major"); + String minor = versionObj.optString("minor"); + this.version = (major != null ? major : "") + (major != null ? "." : "") + (minor != null ? minor : ""); + } + + JSONArray channelsJA = device.optJSONArray("_kanal"); + if (channelsJA != null) { + for (int i = 0; i < channelsJA.length(); i++) { + JSONObject kanal = channelsJA.getJSONObject(i); + + MeasuringChannel cb = new MeasuringChannel(kanal.toString()); + this.measuringChannels.put(cb.getNumber(), cb); + } + } + } + + public String getDeviceType() { + return switch (getIdentifierInt()) { + case 0x0000 -> + "GFP"; + case 0x0010 -> + "Gleisbox 60112 und 60113"; + case 0x0020 -> + "Connect 6021 Art-Nr.60128"; + case 0x0030 -> + "MS 2 60653, Txxxxx"; + case 0x0040 -> + "Link-S88"; + case 0x0050 -> + "CS2/3-GFP"; + case 0xffe0 -> + "Wireless Devices"; + case 0xffff -> + "CS2/3-GUI (Master)"; + default -> + "Unknown " + name; + }; + } + + public MeasuringChannel getMeasuringChannel(Integer number) { + return measuringChannels.get(number); + } + + public void addMeasuringChannel(MeasuringChannel measuringChannel) { + measuringChannels.put(measuringChannel.getNumber(), measuringChannel); + } + + public void addConfigChannel(ConfigChannel configChannel) { + configChannels.put(configChannel.getNumber(), configChannel); + } + + public ConfigChannel getConfigChannel(Integer number) { + return configChannels.get(number); + } + +// public int getBusLength(Integer busNr) { +// if (this.isFeedbackDevice()) { +// CSChannel cb = this.sensorBuses.get(busNr); +// if (cb != null) { +// if (busNr == 0) { +// return 1; +// } else { +// return cb.getValue(); +// } +// } else { +// return 0; +// } +// } else { +// return -1; +// } +// } +// public Integer getLinkS88ContactIdOffset(int busNr) { +// return (busNr - 1) * 1000; +// } +// public boolean isFeedbackDevice() { +// return "Link S88".equals(typeName); +// } + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("CanDevice{"); + if (uid != null) { + sb.append("uid=").append(uid); + } + if (name != null) { + sb.append(", name=").append(name); + } + if (identifier != null) { + sb.append(", identifier=").append(identifier); + } + if (articleNumber != null) { + sb.append(", articleNumber=").append(articleNumber); + } + if (serial != null) { + sb.append(", serial=").append(serial); + } + if (measureChannelCount != null) { + sb.append(", measureChannelCount=").append(measureChannelCount); + } + if (configChannelCount != null) { + sb.append(", configChannelCount=").append(configChannelCount); + } + if (version != null) { + sb.append(", version=").append(version); + } + sb.append("}"); + return sb.toString(); + } + + @Override + public int hashCode() { + int hash = 7; + hash = 79 * hash + Objects.hashCode(this.uid); + hash = 79 * hash + Objects.hashCode(this.version); + hash = 79 * hash + Objects.hashCode(this.identifier); + hash = 79 * hash + Objects.hashCode(this.measureChannelCount); + hash = 79 * hash + Objects.hashCode(this.configChannelCount); + hash = 79 * hash + Objects.hashCode(this.serial); + hash = 79 * hash + Objects.hashCode(this.articleNumber); + hash = 79 * hash + Objects.hashCode(this.name); + hash = 79 * hash + Objects.hashCode(this.measuringChannels); + hash = 79 * hash + Objects.hashCode(this.configChannels); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final CanDevice other = (CanDevice) obj; + if (!Objects.equals(this.uid, other.uid)) { + return false; + } + if (!Objects.equals(this.version, other.version)) { + return false; + } + if (!Objects.equals(this.identifier, other.identifier)) { + return false; + } + if (!Objects.equals(this.serial, other.serial)) { + return false; + } + if (!Objects.equals(this.articleNumber, other.articleNumber)) { + return false; + } + if (!Objects.equals(this.measureChannelCount, other.measureChannelCount)) { + return false; + } + if (!Objects.equals(this.configChannelCount, other.configChannelCount)) { + return false; + } +// if (!Objects.equals(this.measuringChannels, other.measuringChannels)) { +// return false; +// } +// if (!Objects.equals(this.configChannels, other.configChannels)) { +// return false; +// } + return Objects.equals(this.name, other.name); + } + +} diff --git a/src/main/java/jcs/commandStation/marklin/cs/can/device/ConfigChannel.java b/src/main/java/jcs/commandStation/marklin/cs/can/device/ConfigChannel.java new file mode 100644 index 00000000..e6b5686d --- /dev/null +++ b/src/main/java/jcs/commandStation/marklin/cs/can/device/ConfigChannel.java @@ -0,0 +1,282 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.commandStation.marklin.cs.can.device; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import org.json.JSONObject; + +/** + * Represents a Configuration Channel of a Marklin Central Station CanDevice
+ * There are 2 formatConfig Channel, main difference is de use of a choice list.
+ * Quotes from the documentation:
+ * Format eines Datenblocks mit der Möglichkeit eine Auswahl zu treffen:
+ * - Konfigkanalnummer
+ * - Kenner Auswahlliste
+ * - Anzahl der Auswahlpunkte
+ * - Jetzige (Default) Einstellung
+ * - Auswahlbezeichnung
+ * - Auswahl 1
+ * - Auswahl 2
+ * - Auswahl 3
+ * + * Format eines Datenblocks mit der Möglichkeit einen Wert einzustellen:
+ * - Konfigirationskanalnummer
+ * - Kenner Slider
+ * - Unterer Wert
+ * - Oberer Wert
+ * - Aktuelle Einstellung
+ * - Auswahlbezeichnung
+ * - Bezeichnung Start
+ * - Bezeichnung Ende
+ * - Einheit
+ * + */ +public class ConfigChannel { + + private Integer number; + private Integer valueId; + private Integer choicesCount; + private String choiceDescription; + private final List choices; + private Integer lowValue; + private Integer highValue; + private Integer actualValue; + private String startName; + private String endName; + private String unit; + + public ConfigChannel() { + this(null); + } + + public ConfigChannel(String json) { + choices = new ArrayList<>(); + if (json != null) { + parseJson(json); + } + } + + public Integer getNumber() { + return number; + } + + public void setNumber(Integer number) { + this.number = number; + } + + public Integer getValueId() { + return valueId; + } + + public void setValueId(Integer valueId) { + this.valueId = valueId; + } + + public Integer getChoicesCount() { + return choicesCount; + } + + public void setChoicesCount(Integer choicesCount) { + this.choicesCount = choicesCount; + } + + public String getChoiceDescription() { + return choiceDescription; + } + + public void setChoiceDescription(String choiceDescription) { + this.choiceDescription = choiceDescription; + } + + public void addChoice(String choice) { + this.choices.add(choice); + } + + public List getChoices() { + return choices; + } + + public Integer getLowValue() { + return lowValue; + } + + public void setLowValue(Integer lowValue) { + this.lowValue = lowValue; + } + + public Integer getHighValue() { + return highValue; + } + + public void setHighValue(Integer highValue) { + this.highValue = highValue; + } + + public Integer getActualValue() { + return actualValue; + } + + public void setActualValue(Integer actualValue) { + this.actualValue = actualValue; + } + + public String getStartName() { + return startName; + } + + public void setStartName(String startName) { + this.startName = startName; + } + + public String getEndName() { + return endName; + } + + public void setEndName(String endName) { + this.endName = endName; + } + + public String getUnit() { + return unit; + } + + public void setUnit(String unit) { + this.unit = unit; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("ConfigChannel{"); + if (number != null) { + sb.append("number=").append(number); + } + if (choicesCount != null) { + sb.append(", choicesCount=").append(choicesCount); + } + if (valueId != null) { + sb.append(", valueId=").append(valueId); + } + if (choiceDescription != null) { + sb.append(", choiceDescription=").append(choiceDescription); + } + if (!choices.isEmpty()) { + sb.append(", choices=").append(choices); + } + if (lowValue != null) { + sb.append(", lowValue=").append(lowValue); + } + if (highValue != null) { + sb.append(", highValue=").append(highValue); + } + if (actualValue != null) { + sb.append(", actualValue=").append(actualValue); + } + if (startName != null) { + sb.append(", startName=").append(startName); + } + if (endName != null) { + sb.append(", endName=").append(endName); + } + if (unit != null) { + sb.append(", unit=").append(unit); + } + + sb.append("}"); + return sb.toString(); + } + + @Override + public int hashCode() { + int hash = 7; + hash = 83 * hash + Objects.hashCode(this.number); + hash = 83 * hash + Objects.hashCode(this.valueId); + hash = 83 * hash + Objects.hashCode(this.choicesCount); + hash = 83 * hash + Objects.hashCode(this.choiceDescription); + hash = 83 * hash + Objects.hashCode(this.choices); + hash = 83 * hash + Objects.hashCode(this.lowValue); + hash = 83 * hash + Objects.hashCode(this.highValue); + hash = 83 * hash + Objects.hashCode(this.actualValue); + hash = 83 * hash + Objects.hashCode(this.startName); + hash = 83 * hash + Objects.hashCode(this.endName); + hash = 83 * hash + Objects.hashCode(this.unit); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final ConfigChannel other = (ConfigChannel) obj; + if (!Objects.equals(this.choiceDescription, other.choiceDescription)) { + return false; + } + if (!Objects.equals(this.startName, other.startName)) { + return false; + } + if (!Objects.equals(this.endName, other.endName)) { + return false; + } + if (!Objects.equals(this.unit, other.unit)) { + return false; + } + if (!Objects.equals(this.number, other.number)) { + return false; + } + if (!Objects.equals(this.valueId, other.valueId)) { + return false; + } + if (!Objects.equals(this.choicesCount, other.choicesCount)) { + return false; + } + if (!Objects.equals(this.choices, other.choices)) { + return false; + } + if (!Objects.equals(this.lowValue, other.lowValue)) { + return false; + } + if (!Objects.equals(this.highValue, other.highValue)) { + return false; + } + return Objects.equals(this.actualValue, other.actualValue); + } + + private void parseJson(String json) { + JSONObject kanal = new JSONObject(json); + + //this.defaultValueId = kanal.optInt("auswahl"); + this.actualValue = kanal.optInt("auswahl"); + this.unit = kanal.optString("einheit"); + //this.index = kanal.optInt("index"); + this.lowValue = kanal.optInt("min"); + this.highValue = kanal.optInt("max"); + this.choiceDescription = kanal.optString("name"); + this.number = kanal.optInt("nr"); + this.startName = kanal.optString("startWert"); + //this.type = kanal.optInt("typ"); + this.actualValue = kanal.optInt("wert"); + } + +} diff --git a/src/main/java/jcs/commandStation/marklin/cs/can/device/MeasuringChannel.java b/src/main/java/jcs/commandStation/marklin/cs/can/device/MeasuringChannel.java new file mode 100644 index 00000000..e9bac1df --- /dev/null +++ b/src/main/java/jcs/commandStation/marklin/cs/can/device/MeasuringChannel.java @@ -0,0 +1,345 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.commandStation.marklin.cs.can.device; + +import java.util.Objects; +import org.json.JSONObject; +import org.tinylog.Logger; + +/** + * Represents a Measurement Channel in the Marklin Central Station + */ +public class MeasuringChannel { + +// Abfragekanalnummer +//Potenz des Messwerts +//Farbe Bereich 1 +//Farbe Bereich 2 +//Farbe Bereich 3 +// Farbe Bereich 4 +// Nullpunkt +// Ende Bereich 1 +// Ende Bereich 2 +// Ende Bereich 3 +// Ende Bereich 4 +// Messwertbezeichnung +// Bezeichnung Start +// Bezeichnung Ende +// Einheit + private Integer number; + private Integer scale; + private Integer colorGreen; + private Integer colorYellow; + private Integer colorRed; + private Integer colorMax; + private Integer zeroPoint; + private Integer rangeGreen; + private Integer rangeYellow; + private Integer rangeRed; + private Integer rangeMax; + private String name; + private Double startValue; + private Double endValue; + private String unit; + + public MeasuringChannel() { + } + + public MeasuringChannel(String json) { + parseJson(json); + } + + public String getUnit() { + return unit; + } + + public void setUnit(String unit) { + this.unit = unit; + } + + public Double getEndValue() { + return endValue; + } + + public void setEndValue(Double endValue) { + this.endValue = endValue; + } + + public Integer getColorYellow() { + return colorYellow; + } + + public void setColorYellow(Integer colorYellow) { + this.colorYellow = colorYellow; + } + + public Integer getColorGreen() { + return colorGreen; + } + + public void setColorGreen(Integer colorGreen) { + this.colorGreen = colorGreen; + } + + public Integer getColorMax() { + return colorMax; + } + + public void setColorMax(Integer colorMax) { + this.colorMax = colorMax; + } + + public Integer getColorRed() { + return colorRed; + } + + public void setColorRed(Integer colorRed) { + this.colorRed = colorRed; + } + + public Integer getZeroPoint() { + return zeroPoint; + } + + public void setZeroPoint(Integer zeroPoint) { + this.zeroPoint = zeroPoint; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getNumber() { + return number; + } + + public void setNumber(Integer number) { + this.number = number; + } + + public Integer getRangeYellow() { + return rangeYellow; + } + + public void setRangeYellow(Integer rangeYellow) { + this.rangeYellow = rangeYellow; + } + + public Integer getRangeGreen() { + return rangeGreen; + } + + public void setRangeGreen(Integer rangeGreen) { + this.rangeGreen = rangeGreen; + } + + public Integer getRangeMax() { + return rangeMax; + } + + public void setRangeMax(Integer rangeMax) { + this.rangeMax = rangeMax; + } + + public Integer getRangeRed() { + return rangeRed; + } + + public void setRangeRed(Integer rangeRed) { + this.rangeRed = rangeRed; + } + + public Integer getScale() { + return scale; + } + + public void setScale(Integer scale) { + this.scale = scale; + } + + public Double getStartValue() { + return startValue; + } + + public void setStartValue(Double startValue) { + this.startValue = startValue; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("MeasuringChannel{"); + if (number != null) { + sb.append("number=").append(number); + } + if (name != null) { + sb.append(", name=").append(name); + } + if (scale != null) { + sb.append(", scale=").append(scale); + } + if (colorGreen != null) { + sb.append(", colorGreen=").append(colorGreen); + } + if (colorYellow != null) { + sb.append(", colorYellow=").append(colorYellow); + } + if (colorRed != null) { + sb.append(", colorRed=").append(colorRed); + } + if (colorMax != null) { + sb.append(", colorMax=").append(colorMax); + } + if (zeroPoint != null) { + sb.append(", zero=").append(zeroPoint); + } + if (rangeGreen != null) { + sb.append(", rangeGreen=").append(rangeGreen); + } + if (rangeYellow != null) { + sb.append(", rangeYellow=").append(rangeYellow); + } + if (rangeRed != null) { + sb.append(", rangeRed=").append(rangeRed); + } + if (rangeMax != null) { + sb.append(", rangeMax=").append(rangeMax); + } + if (startValue != null) { + sb.append(", startValue=").append(startValue); + } + if (endValue != null) { + sb.append(", endValue=").append(endValue); + } + if (unit != null) { + sb.append(", unit=").append(unit); + } + sb.append("}"); + return sb.toString(); + } + + @Override + public int hashCode() { + int hash = 7; + hash = 23 * hash + Objects.hashCode(this.number); + hash = 23 * hash + Objects.hashCode(this.scale); + hash = 23 * hash + Objects.hashCode(this.colorGreen); + hash = 23 * hash + Objects.hashCode(this.colorYellow); + hash = 23 * hash + Objects.hashCode(this.colorRed); + hash = 23 * hash + Objects.hashCode(this.colorMax); + hash = 23 * hash + Objects.hashCode(this.zeroPoint); + hash = 23 * hash + Objects.hashCode(this.rangeGreen); + hash = 23 * hash + Objects.hashCode(this.rangeYellow); + hash = 23 * hash + Objects.hashCode(this.rangeRed); + hash = 23 * hash + Objects.hashCode(this.rangeMax); + hash = 23 * hash + Objects.hashCode(this.name); + hash = 23 * hash + Objects.hashCode(this.startValue); + hash = 23 * hash + Objects.hashCode(this.endValue); + hash = 23 * hash + Objects.hashCode(this.unit); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final MeasuringChannel other = (MeasuringChannel) obj; + if (!Objects.equals(this.name, other.name)) { + return false; + } + if (!Objects.equals(this.unit, other.unit)) { + return false; + } + if (!Objects.equals(this.number, other.number)) { + return false; + } + if (!Objects.equals(this.scale, other.scale)) { + return false; + } + if (!Objects.equals(this.colorGreen, other.colorGreen)) { + return false; + } + if (!Objects.equals(this.colorYellow, other.colorYellow)) { + return false; + } + if (!Objects.equals(this.colorRed, other.colorRed)) { + return false; + } + if (!Objects.equals(this.colorMax, other.colorMax)) { + return false; + } + if (!Objects.equals(this.zeroPoint, other.zeroPoint)) { + return false; + } + if (!Objects.equals(this.rangeGreen, other.rangeGreen)) { + return false; + } + if (!Objects.equals(this.rangeYellow, other.rangeYellow)) { + return false; + } + if (!Objects.equals(this.rangeRed, other.rangeRed)) { + return false; + } + if (!Objects.equals(this.rangeMax, other.rangeMax)) { + return false; + } + if (!Objects.equals(this.startValue, other.startValue)) { + return false; + } + return Objects.equals(this.endValue, other.endValue); + } + + private void parseJson(String json) { + JSONObject kanal = new JSONObject(json); + +// this.selection = kanal.optString("auswahl"); +// this.config = kanal.optString("auswahl"); + this.unit = kanal.optString("einheit"); + this.colorYellow = kanal.optInt("farbeGelb"); + this.colorGreen = kanal.optInt("farbeGruen"); + this.colorMax = kanal.optInt("farbeMax"); + this.colorRed = kanal.optInt("farbeRot"); +// this.index = kanal.optInt("index"); +// this.present = kanal.optBoolean("isPresent"); +// this.min = kanal.optInt("min"); +// this.max = kanal.optInt("max"); + this.name = kanal.optString("name"); + this.number = kanal.optInt("nr"); +// this.ready = kanal.optBoolean("_ready"); + this.rangeYellow = kanal.optInt("rangeGelb"); + this.rangeGreen = kanal.optInt("rangeGruen"); + this.rangeMax = kanal.optInt("rangeMax"); + this.rangeRed = kanal.optInt("rangeRot"); + this.scale = kanal.optInt("potenz"); + this.startValue = kanal.optDouble("startWert"); +// this.type = kanal.optInt("typ"); +// this.value = kanal.optInt("wert"); + //this.previousValue; +// this.humanValue = kanal.optDouble("valueHuman"); + } + +} diff --git a/src/main/java/jcs/commandStation/marklin/cs/can/parser/CanDevices.java b/src/main/java/jcs/commandStation/marklin/cs/can/parser/CanDevices.java new file mode 100644 index 00000000..71c5f011 --- /dev/null +++ b/src/main/java/jcs/commandStation/marklin/cs/can/parser/CanDevices.java @@ -0,0 +1,420 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.commandStation.marklin.cs.can.parser; + +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.List; +import jcs.commandStation.marklin.cs.can.device.MeasuringChannel; +import jcs.commandStation.marklin.cs.can.device.CanDevice; +import jcs.commandStation.marklin.cs.can.CanMessage; +import jcs.commandStation.marklin.cs.can.device.ConfigChannel; +import org.tinylog.Logger; + +/** + * Parse the CS CAN Bus devices from the
+ * "Softwarestand Anfrage / Teilnehmer Ping" and "Statusdaten Konfiguration" messages + */ +public class CanDevices { + + public static List parse(CanMessage memberPingmessage) { + List devices = new ArrayList<>(); + for (CanMessage response : memberPingmessage.getResponses()) { + CanDevice device = parseResponse(response); + if (device != null) { + devices.add(device); + } + } + Logger.trace("Found " + devices.size() + " CANDevices"); + return devices; + } + + private static CanDevice parseResponse(CanMessage response) { + if (CanMessage.PING_RESP == response.getCommand() && CanMessage.DLC_8 == response.getDlc()) { + byte[] data = response.getData(); + + byte[] uida = new byte[4]; + System.arraycopy(data, 0, uida, 0, uida.length); + + byte[] vera = new byte[2]; + System.arraycopy(data, 4, vera, 0, vera.length); + + byte[] deva = new byte[2]; + System.arraycopy(data, 6, deva, 0, deva.length); + + int uidAsInt = response.getDeviceUidNumberFromMessage(); + String uid = "0x" + Integer.toHexString(uidAsInt); + int major = Byte.toUnsignedInt(vera[0]); + int minor = Byte.toUnsignedInt(vera[1]); + String version = major + "." + minor; + + int identifierAsInt = CanMessage.toInt(deva); + String identifier = "0x" + Integer.toHexString(identifierAsInt); + + CanDevice device = new CanDevice(); + + device.setUid(uid); + device.setVersion(version); + device.setIdentifier(identifier); + return device; + } + return null; + } + + public static void parse(CanDevice canDevice, CanMessage statusConfigmessage) { + //Filter the responses + List responses = new ArrayList<>(statusConfigmessage.getResponses().size()); + for (CanMessage resp : statusConfigmessage.getResponses()) { + if (CanMessage.STATUS_CONFIG_RESP == resp.getCommand()) { + responses.add(resp); + } + } + if (responses.isEmpty()) { + return; + } + + //The last response has the total response messages, aka the package number + CanMessage last = responses.get(responses.size() - 1); + int packets = 0; + int index = 0; + + if (last.getDlc() == CanMessage.DLC_6) { + index = last.getDataByte(4); + packets = last.getDataByte(5); + } else if (last.getDlc() == CanMessage.DLC_5) { + //CS-2 lets assume the number packets to be the size + packets = responses.size() - 1; + } + if (responses.size() - 1 != packets) { + Logger.warn("Config Data might be invalid. Packages expected: " + packets + " received: " + (responses.size() - 1)); + Logger.trace(statusConfigmessage); + for (CanMessage m : responses) { + Logger.trace(m); + } + } + + if (index == 0) { + parseDeviceDescription(canDevice, responses); + } else { + int measurementChannels; + if (canDevice.getMeasureChannelCount() == null) { + measurementChannels = 0; + } else { + measurementChannels = canDevice.getMeasureChannelCount(); + } + if (index <= measurementChannels) { + parseMeasurementChannel(canDevice, responses); + } else { + parseConfigurationChannel(canDevice, responses); + } + } + } + + /** + * In case the index equals zero (0) the responses contain a CAN Device Description. + * + * @param responses + * @return + */ + private static void parseDeviceDescription(CanDevice canDevice, List responses) { + List stringDataList = new ArrayList<>(); + for (int i = 0; i < responses.size(); i++) { + CanMessage msg = responses.get(i); + byte[] data = msg.getData(); + int packageNr = msg.getPackageNumber(); + + switch (packageNr) { + case 1 -> { + if (CanMessage.DLC_8 == msg.getDlc()) { + int measureChannels = Byte.toUnsignedInt(data[0]); + int configChannels = Byte.toUnsignedInt(data[1]); + canDevice.setMeasureChannelCount(measureChannels); + canDevice.setConfigChannelCount(configChannels); + } else { + Logger.trace("Invalid DLC " + msg.getDlc() + " Package " + packageNr + " " + msg); + } + } + case 2 -> { + if (CanMessage.DLC_8 == msg.getDlc()) { + //Article is defined in the full 8 bytes of the 2nd package + String articleNumber = CanMessage.toString(data); + canDevice.setArticleNumber(articleNumber.trim()); + } else { + Logger.trace("Invalid DLC " + msg.getDlc() + " Package " + packageNr + " " + msg); + } + } + default -> { + switch (msg.getDlc()) { + case CanMessage.DLC_8 -> { + for (int j = 0; j < data.length; j++) { + stringDataList.add(data[j]); + } + } + case CanMessage.DLC_6 -> { + //Got the last response + List strings = splitIntoStrings(stringDataList); + if (!strings.isEmpty()) { + canDevice.setName(strings.get(0)); + } + if (strings.size() > 1) { + Logger.warn("There are more name strings than expected " + strings); + } + } + default -> + Logger.trace("Invalid DLC " + msg.getDlc() + " Package " + packageNr + " " + msg); + } + } + } + } + } + + private static void parseMeasurementChannel(CanDevice canDevice, List responses) { + List stringDataList = new ArrayList<>(); + MeasuringChannel channel = new MeasuringChannel(); + + for (int i = 0; i < responses.size(); i++) { + CanMessage msg = responses.get(i); + byte[] data = msg.getData(); + int packageNr = msg.getPackageNumber(); + + switch (packageNr) { + case 1 -> { + if (CanMessage.DLC_8 == msg.getDlc()) { + int channelNumber = Byte.toUnsignedInt(data[0]); + int measurementScale = (int) data[1]; + int colorRange1 = Byte.toUnsignedInt(data[2]); + int colorRange2 = Byte.toUnsignedInt(data[3]); + int colorRange3 = Byte.toUnsignedInt(data[4]); + int colorRange4 = Byte.toUnsignedInt(data[5]); + + byte[] zeroPoint = new byte[2]; + System.arraycopy(data, 6, zeroPoint, 0, zeroPoint.length); + int zero = CanMessage.toInt(zeroPoint); + + //channel.setIndex(index); + channel.setNumber(channelNumber); + channel.setScale(measurementScale); + channel.setColorGreen(colorRange1); + channel.setColorYellow(colorRange2); + channel.setColorRed(colorRange3); + channel.setColorMax(colorRange4); + + channel.setZeroPoint(zero); + } else { + Logger.trace("Invalid DLC " + msg.getDlc() + " Package " + packageNr + " " + msg); + } + } + case 2 -> { + if (CanMessage.DLC_8 == msg.getDlc()) { + byte[] brange1 = new byte[2]; + System.arraycopy(data, 0, brange1, 0, brange1.length); + byte[] brange2 = new byte[2]; + System.arraycopy(data, 2, brange2, 0, brange2.length); + byte[] brange3 = new byte[2]; + System.arraycopy(data, 4, brange3, 0, brange3.length); + byte[] brange4 = new byte[2]; + System.arraycopy(data, 6, brange4, 0, brange4.length); + + int range1 = CanMessage.toInt(brange1); + int range2 = CanMessage.toInt(brange2); + int range3 = CanMessage.toInt(brange2); + int range4 = CanMessage.toInt(brange4); + + channel.setRangeGreen(range1); + channel.setRangeYellow(range2); + channel.setRangeRed(range3); + channel.setRangeMax(range4); + } else { + Logger.trace("Invalid DLC " + msg.getDlc() + " Package " + packageNr + " " + msg); + } + } + default -> { + switch (msg.getDlc()) { + case CanMessage.DLC_8 -> { + //The last part of the measurement data are strings, so first concat all data packets + for (int ii = 0; ii < data.length; ii++) { + stringDataList.add(data[ii]); + } + } + case CanMessage.DLC_6 -> { + //Last message in this response + if (!stringDataList.isEmpty()) { + List strings = splitIntoStrings(stringDataList); + + if (!strings.isEmpty()) { + for (int j = 0; j < strings.size(); j++) { + switch (j) { + case 0 -> + channel.setName(strings.get(0)); + case 1 -> + channel.setStartValue(Double.valueOf(strings.get(1))); + case 2 -> + channel.setEndValue(Double.valueOf(strings.get(2))); + case 3 -> + channel.setUnit(strings.get(3)); + default -> + Logger.trace("Remaining: " + strings.get(j)); + } + } + } + } + } + default -> + Logger.trace("Invalid DLC " + msg.getDlc() + " Package " + packageNr + " " + msg); + } + } + } + } + canDevice.addMeasuringChannel(channel); + } + + private static void parseConfigurationChannel(CanDevice canDevice, List responses) { + List stringDataList = new ArrayList<>(); + ConfigChannel channel = new ConfigChannel(); + + for (int i = 0; i < responses.size(); i++) { + CanMessage msg = responses.get(i); + byte[] data = msg.getData(); + int packageNr = msg.getPackageNumber(); + + //There are 2 possible formats; one with choice lists and one with values. + //Not clear how the recognice the one or the other... + switch (packageNr) { + case 1 -> { + if (CanMessage.DLC_8 == msg.getDlc()) { + int channelConfigNumber = Byte.toUnsignedInt(data[0]); + int valueId = Byte.toUnsignedInt(data[1]); + channel.setNumber(channelConfigNumber); + channel.setValueId(valueId); + //Here it is a bit unclear. For choice list + int choicesCount = Byte.toUnsignedInt(data[2]); + int defaultValueId = Byte.toUnsignedInt(data[3]); + + //next 4 byte are reserved aka 0 + int res1 = Byte.toUnsignedInt(data[4]); + int res2 = Byte.toUnsignedInt(data[5]); + int res3 = Byte.toUnsignedInt(data[6]); + int res4 = Byte.toUnsignedInt(data[7]); + + if (res1 == 0 & res2 == 0 && res3 == 0 && res4 == 0) { + channel.setChoicesCount(choicesCount); + channel.setValueId(defaultValueId); + } else { + //for the other format: + byte[] lowval = new byte[2]; + System.arraycopy(data, 2, lowval, 0, lowval.length); + int lowValue = CanMessage.toInt(lowval); + channel.setLowValue(lowValue); + byte[] upperval = new byte[2]; + System.arraycopy(data, 4, upperval, 0, upperval.length); + int upperValue = CanMessage.toInt(lowval); + channel.setHighValue(upperValue); + byte[] setval = new byte[2]; + System.arraycopy(data, 6, setval, 0, setval.length); + int actualValue = CanMessage.toInt(setval); + channel.setActualValue(actualValue); + } + } else { + Logger.trace("Invalid DLC " + msg.getDlc() + " Package " + packageNr + " " + msg); + } + } + default -> { + int dlc = msg.getDlc(); + switch (dlc) { + case CanMessage.DLC_8 -> { + //The last part of the config channel data are strings, so first concat all data packets + for (int ii = 0; ii < data.length; ii++) { + stringDataList.add(data[ii]); + } + } + case CanMessage.DLC_6 -> { + //Last message in this response + if (!stringDataList.isEmpty()) { + List strings = splitIntoStrings(stringDataList); + for (String s : strings) { + Logger.trace(s); + } + int choicesCount = 0; + if (channel.getChoicesCount() != null) { + choicesCount = channel.getChoicesCount(); + } + + //first string the the description + channel.setChoiceDescription(strings.get(0)); + + if (choicesCount > 0) { + //next are the choices + for (int j = 1; j <= choicesCount; j++) { + if (strings.size() >= j) { + channel.addChoice(strings.get(j)); + } + } + } else { + //No choice list must be single values + for (int j = 1; j < strings.size(); j++) { + switch (j) { + case 1 -> + channel.setStartName(strings.get(j)); + case 2 -> + channel.setEndName(strings.get(j)); + case 3 -> + channel.setUnit(strings.get(j)); + default -> + Logger.trace("Remaining: " + strings.get(j)); + } + } + } + canDevice.addConfigChannel(channel); + } + } + default -> + Logger.trace("Invalid DLC " + msg.getDlc() + " Package " + packageNr + " " + msg); + } + } + } + } + } + + private static List splitIntoStrings(List byteList) { + List strings = new ArrayList<>(); + int index = 0; + byte[] d = new byte[byteList.size()]; + for (int j = 0; j < d.length; j++) { + d[j] = byteList.get(j); + + if (d[j] == 0) { + //Terminator + int len = j - index; + + byte[] tmp = new byte[len]; + System.arraycopy(d, index, tmp, 0, tmp.length); + String s; + try { + s = new String(tmp, "UTF-8"); + + if (s.length() >= 1) { + strings.add(s); + } + } catch (UnsupportedEncodingException ex) { + Logger.error(ex); + } + index = j + 1; + } + } + return strings; + } + +} diff --git a/src/test/java/jcs/commandStation/marklin/cs/can/parser/CanDevicesTest.java b/src/test/java/jcs/commandStation/marklin/cs/can/parser/CanDevicesTest.java new file mode 100644 index 0000000000000000000000000000000000000000..1843c952438036cce45cad49358adc4160228565 GIT binary patch literal 13962 zcmeHOUvtw)62IqsiYY${Dk%PMvta6s3A^46hKj>(aaZ@C$m2vHOI}IF$!_s&?wi~f zyY8NU8d-82B6zr4iV~KlXS%1mr+=+(aq{?xJ!X@5eVYVV*BNU!+dcL=@uHOd?D_F! z>cTjZoCQ9QQodlDXu%VfU2`^Gdp`UlM~>OAJV}E%Vr{p{93*JSp~jeW^(~8+ zc|zu8QfP*MuCr|Y!^z2ZyLCO1*o~8`lThp@Jvp0BPG|GeCm^+)^*#!DnzDrdz6lc8 z@#QV^)*zMdU4pEkw`Fm{ysL!6SQewy+a$<>=<1lI@iNv;lDn-{Uhc+RHt275W4Pv^(D$Zyk&pWeQ|V84ye&&RWi>FJ!kJ!g}*vscrL>Dw9H zy=LRt2lmT!_Uf2%P#GA9->ehd0f-r(I{AWhH|MBxZ7{ZkalB90+z*z44_k|_Hr^Fy zSMg__M6e^a=E*8Z(X1&5xImG@U=?IuMvsg$wNT67c9DhnR7A4U3tl; zFo;|n@gjHaB`Hsy9UXz7agwo*-e=F}qoDMG+6p!iTOf@uF9>);*@eoHt+$P{%zcNr@+Mv)898Ae@a0Zwk0w1O|ks=}c^XP~% zNnj5-k6@6oFGP?8pS_IZWT_H%#j`hjb;*-=U>8Zt@&s%2!cp#ta2co3ylFOB^QMEB z<^V4Jr}&F*54liKg7AP0TyL>B=jj@}oI6IkBC8hiLskQhtcGyuckmW3-5y+q3%E4f zc){D{k}i!$7y$3jYj6qE2ed8Z)k8KN`sKr~E{fAM7u7xOlsdOP1{m88-1U zAcn}RXLuz%+awXG5;sc5{yRE`@ruuJ0MQa2y~7i4Y%U!^n|^+qW_;zwo6KFqS&|bCH%3+C5k$Yw%b!9T0C@A z$4_@ff{^-YJ{(rbC5Lmu^*Wtl&+oPriyVb5A-a^d#?wvdu|SJJEHx=KnI z%1J2I=PUMd)RqpNP)H|-jbv@N)#|8GTR5Oqf)zahfK#}EwrwiIz>agNCGv6C(Tt8E zfxx9myglI$fpL?*@-k0E`yXGwn?j0p)6_=-BvIiKqj{bfG-*bQ;mU(UD#8_pAqq&v za7D+u7%i2~ip&m-k{Glonuyqh(WKeM3x&lZGaSGO*X`@b^Es}o)JQH@R_(! zjLV5pA72ci6g|86tB(lKN2D0w_6I0IAERdcXd zLk;s)f>{+JHNl=hY0*@LON*!^Xe!9FBaaAC7PwaKPGRCi?@7nTs@-XVJ-f4Ls&;1) zmFy0&+M=0xEABKV0L_UPGTals$(Fze!239X^gHCU4d$&*qu*?|A$SQCvKAFD99+I` zOyW(HIo&csE6*2nZG|pceF}%P<=}OboYFFiTwc$TC4YhP0Dg%wO zfY6D-(+8jyvRGn9PY|-iaKiE8=R%u~E)V9bQHy}GO}L5Ay2K5C_4Ko+-TL?%)WWUO zTSb=;nO<^`Ic>jV-gA3p61;~xu+tbT3y~TwZ!`YSe=)3S8LNPw5$z-NxR*eYDu-au z=%5KPOb||nG$qtWCnvBV_o1`#!}Fql{TWeSJZc@Y2s~$mjsux0ddcWX=NK9`$|pwM zp}ZB^9f1eP2cXLl*jwI#=0;%MWA+Ewas)KcpOQu!fzjl>Tm(!YAK)V94i^FSQ_?Jz zJpyGz(?qIv1gbrT_EwOM{x<&d0yfE@dBe6|`oFnJ+#{Zr;)_5Y55NElVWig;sYML= z+G5w4C|lN8@XFQ9F`Fu_ndj1XO8L~Od2nh;NgO5V#GKxsPZABE^d_?FjQpfV-2v4Ixzb04C~{o3tl_vI7SK9mP%J!| zZT0Y(XvL7tNi^YLns2RzCwXM_d-lNzyqu_DuYnkp3VMU*K-JRNi%3}zZsD7p<0O{vj6pk_PWB8g~jK&w(F2oL6~ z>rnzqkQ+fs2Q^H;+E}QP&+6l=L4`n+P=tE=2G$1HQ4?()=t|bLUn=?_h|+$EZx3Y= zEu3OUr#`;a2SdKXv}nsdD%P})M9T_mfrA>s8x2ZbqaC2efud8_vEM_$n~pDu_8q{R z@?8^}?hD~!y22e3UUgKhLOM;5E8rB7&Z4P;F^i}O6&Uj^f^xjHNcJI}MYs>?EW#?J zQ$Y5hG-I~_XVMHn$SVD7^aq+fCMc4X>#s;vWve1xnYoHI`^-_K-Di;^ZIw~bWs0;# zIfdc!U&NUyO5yoYRoBq#QZY+3?Me$>lj|5h6HHD2&5{adQwe6eD6b@m>92U|C&3!q zhft5%q+9qhZv&sOwb&EZDrpnK2R&k<(>M*HKX@3ab8Y0#(Oh_hugS`TZ%c2Gl+>bW z(Xo)+QiL9rkTp^7^arPL>d=VnPgaM7qw7PrFO>sQRU&|&N@`2WilV4Rb5KR}+f^vq z`lSmrXvdG5lgVO!r+nhU$(5;45Q`!oK;RaAEJPsKt^<5Uk$@QKN`a4AjYmlib`|?N zqoky+TO(hcOq%?)m`tKnJ(REO)wf@hOyaK&=6IB~iX;|OD#~)Z4{_T` zsTA{OEzR6Rk}I-4iT1scD|1x;O0IT4Sjm+UbofSm+Xv+qp%s+{U{V=D;e;I=1@$Wb zN$$MxIaU6h9c))w!x5N+pXfpeh8qBEMXgZ|9{-hG<&0vbF;Y3-GPx?RCt-IBQm4|v zlGN$!KmUdv4|};uA$4-jfA034v>quK)TTx|kNph($AjpOm9BmkZ)I;y`js{PC-{F) ndxpVLlT0Mw`cq?TK6K{9aEHE(_`gcWl)Cpds1HlWz8w7*PB;YA literal 0 HcmV?d00001 From eab0206f4c529f1df9dc398098fac122dde0b370 Mon Sep 17 00:00:00 2001 From: Frans Jacobs <41232225+fransjacobs@users.noreply.github.com> Date: Sun, 4 May 2025 00:38:51 +0200 Subject: [PATCH 48/70] Measurement are now producing values. WIP! wifi sometimes weird responses --- .../commandStation/FeedbackController.java | 3 +- .../jcs/commandStation/GenericController.java | 6 +- .../commandStation/JCSCommandStationImpl.java | 25 +- .../dccex/DccExCommandStationImpl.java | 123 ++-- .../commandStation/entities/DeviceBean.java | 10 +- .../jcs/commandStation/entities/InfoBean.java | 14 + .../entities/MeasuredChannels.java | 119 ++++ .../entities/MeasurementBean.java | 194 +++++- .../entities/MeasurementBeanOld.java | 54 ++ .../esu/ecos/EsuEcosCommandStationImpl.java | 79 ++- .../jcs/commandStation/hsis88/HSIImpl.java | 69 +- .../marklin/cs/MarklinCentralStationImpl.java | 622 +++++++----------- .../marklin/cs/can/CanMessageFactory.java | 10 +- .../marklin/cs/can/device/CanDevice.java | 127 ++-- .../cs/can/device/MeasuringChannel.java | 16 - .../marklin/cs/can/parser/CanDevices.java | 27 +- .../marklin/cs2/ChannelDataParser.java | 207 ------ .../GeraetParser.java} | 74 ++- .../marklin/parser/SystemStatusMessage.java | 106 +++ .../virtual/VirtualCommandStationImpl.java | 53 +- .../jcs/ui/settings/CommandStationPanel.java | 55 +- .../ecos/EsuEcosCommandStationImplTest.java | 122 ++-- .../marklin/cs/MarklinCSTest.java | 2 +- .../marklin/cs/can/parser/CanDevicesTest.java | Bin 13962 -> 14105 bytes .../parser/SystemStatusMessageTest.java | 78 +++ 25 files changed, 1172 insertions(+), 1023 deletions(-) create mode 100644 src/main/java/jcs/commandStation/entities/MeasuredChannels.java create mode 100644 src/main/java/jcs/commandStation/entities/MeasurementBeanOld.java delete mode 100644 src/main/java/jcs/commandStation/marklin/cs2/ChannelDataParser.java rename src/main/java/jcs/commandStation/marklin/{cs2/InfoBeanParser.java => parser/GeraetParser.java} (60%) create mode 100644 src/main/java/jcs/commandStation/marklin/parser/SystemStatusMessage.java create mode 100644 src/test/java/jcs/commandStation/marklin/parser/SystemStatusMessageTest.java diff --git a/src/main/java/jcs/commandStation/FeedbackController.java b/src/main/java/jcs/commandStation/FeedbackController.java index 79e27ef1..f96ee9d5 100644 --- a/src/main/java/jcs/commandStation/FeedbackController.java +++ b/src/main/java/jcs/commandStation/FeedbackController.java @@ -18,7 +18,6 @@ import java.util.List; import jcs.commandStation.events.SensorEvent; import jcs.commandStation.events.SensorEventListener; -import jcs.commandStation.entities.DeviceBean; import jcs.entities.FeedbackModuleBean; public interface FeedbackController extends GenericController { @@ -27,7 +26,7 @@ public interface FeedbackController extends GenericController { void removeSensorEventListener(SensorEventListener listener); - DeviceBean getFeedbackDevice(); + //DeviceBean getFeedbackDevice(); List getFeedbackModules(); diff --git a/src/main/java/jcs/commandStation/GenericController.java b/src/main/java/jcs/commandStation/GenericController.java index 3920e50e..523ccc68 100755 --- a/src/main/java/jcs/commandStation/GenericController.java +++ b/src/main/java/jcs/commandStation/GenericController.java @@ -15,10 +15,8 @@ */ package jcs.commandStation; -import java.util.List; import jcs.commandStation.events.DisconnectionEventListener; import jcs.entities.CommandStationBean; -import jcs.commandStation.entities.DeviceBean; import jcs.commandStation.entities.InfoBean; public interface GenericController { @@ -41,9 +39,9 @@ public interface GenericController { InfoBean getCommandStationInfo(); - DeviceBean getDevice(); + //DeviceBean getDevice(); - List getDevices(); + //List getDevices(); String getIp(); diff --git a/src/main/java/jcs/commandStation/JCSCommandStationImpl.java b/src/main/java/jcs/commandStation/JCSCommandStationImpl.java index 0fb4e688..9176c6bf 100755 --- a/src/main/java/jcs/commandStation/JCSCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/JCSCommandStationImpl.java @@ -393,39 +393,34 @@ private void storeImage(Image image, String imageName, boolean locomotive) { @Override public InfoBean getCommandStationInfo() { - if (this.decoderController != null && this.decoderController.getDevice() != null) { - return this.decoderController.getCommandStationInfo(); + if (decoderController != null) { + return decoderController.getCommandStationInfo(); } else { return null; } } - //@Override public String getCommandStationName() { - if (decoderController != null) { - if (decoderController.getDevice() != null) { - return decoderController.getDevice().getName(); - } else { - return decoderController.getCommandStationBean().getDescription(); - } + if (decoderController != null && decoderController.getCommandStationInfo() != null) { + return decoderController.getCommandStationInfo().getProductName(); + } else if (decoderController != null && decoderController.getCommandStationBean() != null) { + return decoderController.getCommandStationBean().getDescription(); } else { return null; } } - //@Override public String getCommandStationSerialNumber() { - if (decoderController != null && decoderController.getDevice() != null) { - return decoderController.getDevice().getSerial(); + if (decoderController != null && decoderController.getCommandStationInfo() != null) { + return decoderController.getCommandStationInfo().getSerialNumber(); } else { return null; } } - //@Override public String getCommandStationArticleNumber() { - if (decoderController != null && decoderController.getDevice() != null) { - return decoderController.getDevice().getArticleNumber(); + if (decoderController != null && decoderController.getCommandStationInfo() != null) { + return decoderController.getCommandStationInfo().getArticleNumber(); } else { return null; } diff --git a/src/main/java/jcs/commandStation/dccex/DccExCommandStationImpl.java b/src/main/java/jcs/commandStation/dccex/DccExCommandStationImpl.java index 2b68c61c..baa948aa 100644 --- a/src/main/java/jcs/commandStation/dccex/DccExCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/dccex/DccExCommandStationImpl.java @@ -59,7 +59,7 @@ public class DccExCommandStationImpl extends AbstractController implements Decod private DccExConnection connection; private InfoBean infoBean; - private DeviceBean mainDevice; + //private DeviceBean mainDevice; private boolean powerStatusSet = false; Map measurementChannels; @@ -165,51 +165,49 @@ public final boolean connect() { long start = now; timeout = now + (conType == ConnectionType.NETWORK ? 200L : 15000L); - while (this.mainDevice == null && now < timeout) { - pause(100); - now = System.currentTimeMillis(); - } - - if (mainDevice != null) { - if (debug) { - Logger.trace("Main Device found in " + (now - start) + " ms"); - } - } else { - //TODO: Fix this! - if (conType == ConnectionType.NETWORK) { - //When using the net work the DCC-EX does not braodcast all kind of setting so ask them - JCS.logProgress("Obtaining Device information..."); - String response = connection.sendMessage(DccExMessageFactory.versionHarwareInfoRequest()); - Logger.trace(response); - - DccExMessage rsp = new DccExMessage(response); - - if ("i".equals(rsp.getOpcode())) { - String content = rsp.getFilteredContent(); - DeviceBean d = new DeviceBean(); - String[] dccexdev = content.split(" "); - d.setName(content); - for (int i = 0; i < dccexdev.length; i++) { - switch (i) { - case 0 -> - d.setName(dccexdev[i]); - case 1 -> - d.setVersion(dccexdev[i]); - case 5 -> - d.setTypeName(dccexdev[i]); - case 6 -> - d.setSerial(dccexdev[i]); - } - } - this.mainDevice = d; - Logger.trace("Main Device set to: " + d); - } - } - if (debug && mainDevice == null) { - Logger.trace("No Main Device found in " + (now - start) + " ms"); - } - } - +// while (this.mainDevice == null && now < timeout) { +// pause(100); +// now = System.currentTimeMillis(); +// } +// if (mainDevice != null) { +// if (debug) { +// Logger.trace("Main Device found in " + (now - start) + " ms"); +// } +// } else { +// //TODO: Fix this! +// if (conType == ConnectionType.NETWORK) { +// //When using the net work the DCC-EX does not braodcast all kind of setting so ask them +// JCS.logProgress("Obtaining Device information..."); +// String response = connection.sendMessage(DccExMessageFactory.versionHarwareInfoRequest()); +// Logger.trace(response); +// +// DccExMessage rsp = new DccExMessage(response); +// +// if ("i".equals(rsp.getOpcode())) { +// String content = rsp.getFilteredContent(); +// DeviceBean d = new DeviceBean(); +// String[] dccexdev = content.split(" "); +// d.setName(content); +// for (int i = 0; i < dccexdev.length; i++) { +// switch (i) { +// case 0 -> +// d.setName(dccexdev[i]); +// case 1 -> +// d.setVersion(dccexdev[i]); +// case 5 -> +// d.setTypeName(dccexdev[i]); +// case 6 -> +// d.setSerial(dccexdev[i]); +// } +// } +// this.mainDevice = d; +// Logger.trace("Main Device set to: " + d); +// } +// } +// if (debug && mainDevice == null) { +// Logger.trace("No Main Device found in " + (now - start) + " ms"); +// } +// } //Create Info this.infoBean = new InfoBean(); this.infoBean.setProductName(commandStationBean.getDescription()); @@ -247,7 +245,7 @@ public final boolean connect() { } initMeasurements(); - Logger.trace("Connected with: " + (this.mainDevice != null ? this.mainDevice.getName() : "Unknown")); + //Logger.trace("Connected with: " + (this.mainDevice != null ? this.mainDevice.getName() : "Unknown")); JCS.logProgress("Power is " + (this.power ? "On" : "Off")); } else { Logger.warn("Can't connect with a DCC-EX Command Station!"); @@ -340,12 +338,10 @@ public void changeFunctionValue(int address, int functionNumber, boolean flag) { // public void switchAccessory(Integer address, AccessoryValue value) { // switchAccessory(address, value, null); // } - // @Override // public void switchAccessory(Integer address, AccessoryValue value, Integer switchTime) { // switchAccessory(address, "dcc", value, switchTime); // } - @Override public void switchAccessory(Integer address, String protocol, AccessoryValue value, Integer switchTime) { if (this.power && this.connected) { @@ -374,7 +370,6 @@ public void switchAccessory(Integer address, String protocol, AccessoryValue val // public void switchAccessory(String id, AccessoryValue value) { // throw new UnsupportedOperationException("Not supported yet."); // } - @Override public List getLocomotives() { throw new UnsupportedOperationException("Not supported yet."); @@ -395,18 +390,16 @@ public List getAccessories() { throw new UnsupportedOperationException("Not supported yet."); } - @Override - public DeviceBean getDevice() { - return this.mainDevice; - } - - @Override - public List getDevices() { - List devices = new ArrayList<>(); - devices.add(this.mainDevice); - return devices; - } - +// @Override +// public DeviceBean getDevice() { +// return this.mainDevice; +// } +// @Override +// public List getDevices() { +// List devices = new ArrayList<>(); +// devices.add(this.mainDevice); +// return devices; +// } @Override public InfoBean getCommandStationInfo() { return this.infoBean; @@ -641,7 +634,7 @@ public void onMessage(DccExMessage message) { d.setSerial(dccexdev[i]); } } - commandStation.mainDevice = d; +// commandStation.mainDevice = d; //Logger.trace("Main Device set to: " + d); } case "c" -> { @@ -690,6 +683,7 @@ public void onDisconnect(DisconnectionEvent event) { ////////////////////////////////////////////////////////////////////////////////////// // For testing only + public static void main(String[] a) { System.setProperty("message.debug", "true"); @@ -737,9 +731,6 @@ public static void main(String[] a) { // ((DccExCommandStationImpl) cs).pause(500L); // cs.power(true); // Logger.trace("Power is: " + (cs.isPower() ? "On" : "Off")); - - - ///// //((DccExCommandStationImpl) cs).pause(500L); // cs.changeFunctionValue(8, 0, true); diff --git a/src/main/java/jcs/commandStation/entities/DeviceBean.java b/src/main/java/jcs/commandStation/entities/DeviceBean.java index bdd1ccb1..a0754c8b 100644 --- a/src/main/java/jcs/commandStation/entities/DeviceBean.java +++ b/src/main/java/jcs/commandStation/entities/DeviceBean.java @@ -32,6 +32,7 @@ * A Device is a Component which "lives" in side a Command Station.
* It can be a Central Station (Marklin) ECos (ESU) etc. TODO: move away Command station specific code */ +@Deprecated public class DeviceBean { public static final String MAIN = "MAIN"; @@ -312,15 +313,6 @@ private void buildFromMessage(CanMessage message) { } } -//Requesting more info for uid: 0x53385c41 -//#TX: 0x00 0x3a 0x7b 0x79 0x05 0x53 0x38 0x5c 0x41 0x00 0x00 0x00 0x00 index is 0 device description -//#RX 0: 0x00 0x3b 0x03 0x01 0x08 0x00 0x0c 0x00 0x00 0x00 0x00 0x24 0x41 char meetwaarde in device 0x00 0x0c aanta config channels0x00 0x00 U32 serie nr 0x24 0x41 -//#RX 1: 0x00 0x3b 0x03 0x02 0x08 0x36 0x30 0x38 0x38 0x33 0x00 0x00 0x00 -//#RX 2: 0x00 0x3b 0x03 0x03 0x08 0x4c 0x69 0x6e 0x6b 0x20 0x53 0x38 0x38 -//#RX 3: 0x00 0x3b 0x03 0x04 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 -//#RX 4: 0x00 0x3b 0x3f 0x3c 0x06 0x53 0x38 0x5c 0x41 0x00 0x04 0x00 0x00 - - public void updateFromMessage(CanMessage message) { //Filter the responses List responses = new ArrayList<>(message.getResponses().size()); diff --git a/src/main/java/jcs/commandStation/entities/InfoBean.java b/src/main/java/jcs/commandStation/entities/InfoBean.java index 79674298..48e8c7ed 100644 --- a/src/main/java/jcs/commandStation/entities/InfoBean.java +++ b/src/main/java/jcs/commandStation/entities/InfoBean.java @@ -32,12 +32,17 @@ public class InfoBean extends CommandStationBean { private String hostname; private String gfpUid; private String guiUid; + private boolean supportMeasurements; public InfoBean() { } public InfoBean(CommandStationBean commandStationBean) { + copyInto(commandStationBean); + } + + public final void copyInto(CommandStationBean commandStationBean) { this.id = commandStationBean.getId(); this.description = commandStationBean.getDescription(); this.shortName = commandStationBean.getShortName(); @@ -140,6 +145,15 @@ public void setGuiUid(String guiUid) { this.guiUid = guiUid; } + @Transient + public boolean isSupportMeasurements() { + return supportMeasurements; + } + + public void setSupportMeasurements(boolean supportMeasurements) { + this.supportMeasurements = supportMeasurements; + } + @Override public String toString() { return "InfoBean{" + "softwareVersion=" + softwareVersion + ", hardwareVersion=" + hardwareVersion + ", serialNumber=" + serialNumber + ", productName=" + productName + ", articleNumber=" + articleNumber + ", hostname=" + hostname + ", gfpUid=" + gfpUid + ", guiUid=" + guiUid + "}"; diff --git a/src/main/java/jcs/commandStation/entities/MeasuredChannels.java b/src/main/java/jcs/commandStation/entities/MeasuredChannels.java new file mode 100644 index 00000000..d333b44a --- /dev/null +++ b/src/main/java/jcs/commandStation/entities/MeasuredChannels.java @@ -0,0 +1,119 @@ +/* + * Copyright 2025 frans. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.commandStation.entities; + +import java.util.Date; +import java.util.Objects; +import org.tinylog.Logger; + +/** + * Hold a group of measurements + */ +public class MeasuredChannels { + + private long measurementTime; + private MeasurementBean main; + private MeasurementBean prog; + private MeasurementBean volt; + private MeasurementBean temp; + + public MeasuredChannels() { + + } + + public MeasuredChannels(long measurementTime) { + this.measurementTime = measurementTime; + } + + public long getMeasurementTime() { + return measurementTime; + } + + public void addMeasurement(MeasurementBean measurement) { + switch(measurement.getName()) { + case "MAIN" -> + this.main = measurement; + case "PROG" -> + this.prog = measurement; + case "VOLT" -> + this.volt = measurement; + case "TEMP" -> + this.temp = measurement; + default -> + Logger.error("Unknown measurement "+measurement); + } + } + + public MeasurementBean getMain() { + return main; + } + + public MeasurementBean getProg() { + return prog; + } + + public MeasurementBean getVolt() { + return volt; + } + + public MeasurementBean getTemp() { + return temp; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 43 * hash + (int) (this.measurementTime ^ (this.measurementTime >>> 32)); + hash = 43 * hash + Objects.hashCode(this.main); + hash = 43 * hash + Objects.hashCode(this.prog); + hash = 43 * hash + Objects.hashCode(this.volt); + hash = 43 * hash + Objects.hashCode(this.temp); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final MeasuredChannels other = (MeasuredChannels) obj; + if (this.measurementTime != other.measurementTime) { + return false; + } + if (!Objects.equals(this.main, other.main)) { + return false; + } + if (!Objects.equals(this.prog, other.prog)) { + return false; + } + if (!Objects.equals(this.volt, other.volt)) { + return false; + } + return Objects.equals(this.temp, other.temp); + } + + @Override + public String toString() { + return "MeasuredChanels{" + "measurementTime=" + new Date(measurementTime) + ", main=" + main.getDisplayValue() + " " + main.getUnit() + ", prog=" + prog.getDisplayValue() + " " + prog.getUnit() + ", volt=" + volt.getDisplayValue() + " " + volt.getUnit() + ", temp=" + temp.getDisplayValue() + " " + temp.getUnit() + "}"; + } + +} diff --git a/src/main/java/jcs/commandStation/entities/MeasurementBean.java b/src/main/java/jcs/commandStation/entities/MeasurementBean.java index 76c3c7c7..397a306c 100644 --- a/src/main/java/jcs/commandStation/entities/MeasurementBean.java +++ b/src/main/java/jcs/commandStation/entities/MeasurementBean.java @@ -16,38 +16,180 @@ package jcs.commandStation.entities; import java.util.Date; +import java.util.Objects; /** - * Object to hold measured values + * A Bean which hold measured values */ public class MeasurementBean { + private Integer channelNumber; private String name; - private Double value; + private boolean valid; + private Long measurementMillis; + + private Integer measuredValue; private String unit; - private Date measurementTime; - - private String selection; - private String config; - private Double endValue; - private Integer colorYellow; - private Integer colorGreen; - private Integer colorMax; - private Integer colorRed; - private Integer index; - private Boolean present; - private Integer min; - private Integer max; - private Integer number; - private Boolean ready; - private Integer rangeYellow; - private Integer rangeGreen; - private Integer rangeMax; - private Integer rangeRed; - private Integer scale; - private Double startValue; - private Integer type; - private Integer previousValue; - private Double humanValue; + + private Double displayValue; + + public MeasurementBean() { + } + + public MeasurementBean(Integer channelNumber, String name, boolean valid, Long measurementMillis) { + this(channelNumber, name, valid, measurementMillis, null, null, null); + } + + public MeasurementBean(Integer channelNumber, String name, Long measurementMillis, Integer measuredValue, String unit, Double displayValue) { + this(channelNumber, name, true, measurementMillis, measuredValue, unit, displayValue); + } + + public MeasurementBean(Integer channelNumber, String name, boolean valid, Long measurementMillis, Integer measuredValue, String unit, Double displayValue) { + this.channelNumber = channelNumber; + this.name = name; + this.valid = valid; + this.measurementMillis = measurementMillis; + this.measuredValue = measuredValue; + this.unit = unit; + this.displayValue = displayValue; + } + + public Integer getChannelNumber() { + return channelNumber; + } + + public void setChannelNumber(Integer channelNumber) { + this.channelNumber = channelNumber; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public boolean isValid() { + return valid; + } + + public void setValid(boolean valid) { + this.valid = valid; + } + + public Date getMeasurementTime() { + return new Date(measurementMillis); + } + + public void setMeasurementTime(Date measurementTime) { + this.measurementMillis = measurementTime.getTime(); + } + + public Long getMeasurementMillis() { + return measurementMillis; + } + + public void setMeasurementMillis(Long measurementMillis) { + this.measurementMillis = measurementMillis; + } + + public Integer getMeasuredValue() { + return measuredValue; + } + + public void setMeasuredValue(Integer measuredValue) { + this.measuredValue = measuredValue; + } + + public String getUnit() { + return unit; + } + + public void setUnit(String unit) { + this.unit = unit; + } + + public Double getDisplayValue() { + return displayValue; + } + + public void setDisplayValue(Double displayValue) { + this.displayValue = displayValue; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("CanDevice{"); + if (channelNumber != null) { + sb.append("channelNumber=").append(channelNumber); + } + if (name != null) { + sb.append(", name=").append(name); + } + sb.append(", valid=").append(valid); + if (measurementMillis != null) { + sb.append(", measurementTime=").append(getMeasurementTime()); + } + if (measuredValue != null) { + sb.append(", measuredValue=").append(measuredValue); + } + if (displayValue != null) { + sb.append(", humanValue=").append(displayValue); + } + if (unit != null) { + sb.append(", unit=").append(unit); + } + + sb.append("}"); + return sb.toString(); + } + + @Override + public int hashCode() { + int hash = 7; + hash = 19 * hash + Objects.hashCode(this.channelNumber); + hash = 19 * hash + Objects.hashCode(this.name); + hash = 19 * hash + (this.valid ? 1 : 0); + hash = 19 * hash + Objects.hashCode(this.measurementMillis); + hash = 19 * hash + Objects.hashCode(this.measuredValue); + hash = 19 * hash + Objects.hashCode(this.unit); + hash = 19 * hash + Objects.hashCode(this.displayValue); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final MeasurementBean other = (MeasurementBean) obj; + if (this.valid != other.valid) { + return false; + } + if (!Objects.equals(this.name, other.name)) { + return false; + } + if (!Objects.equals(this.unit, other.unit)) { + return false; + } + if (!Objects.equals(this.channelNumber, other.channelNumber)) { + return false; + } + if (!Objects.equals(this.measurementMillis, other.measurementMillis)) { + return false; + } + if (!Objects.equals(this.measuredValue, other.measuredValue)) { + return false; + } + return Objects.equals(this.displayValue, other.displayValue); + } } diff --git a/src/main/java/jcs/commandStation/entities/MeasurementBeanOld.java b/src/main/java/jcs/commandStation/entities/MeasurementBeanOld.java new file mode 100644 index 00000000..6409d84c --- /dev/null +++ b/src/main/java/jcs/commandStation/entities/MeasurementBeanOld.java @@ -0,0 +1,54 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.commandStation.entities; + +import java.util.Date; + +/** + * Object to hold measured values + */ +@Deprecated +public class MeasurementBeanOld { + + private String name; + private Double value; + private String unit; + private Date measurementTime; + + private String selection; + private String config; + private Double endValue; + private Integer colorYellow; + private Integer colorGreen; + private Integer colorMax; + private Integer colorRed; + private Integer index; + private Boolean present; + private Integer min; + private Integer max; + private Integer number; + private Boolean ready; + private Integer rangeYellow; + private Integer rangeGreen; + private Integer rangeMax; + private Integer rangeRed; + private Integer scale; + private Double startValue; + private Integer type; + private Integer previousValue; + private Double humanValue; + +} diff --git a/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java b/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java index d6351d7c..6fba24a6 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java @@ -268,7 +268,7 @@ public void disconnect() { @Override public InfoBean getCommandStationInfo() { - InfoBean ib = new InfoBean(this.commandStationBean); + InfoBean ib = new InfoBean(commandStationBean); if (this.ecosManager != null) { ib.setArticleNumber(ecosManager.getName().replace(this.ecosManager.getCommandStationType() + "-", "")); @@ -289,28 +289,26 @@ public InfoBean getCommandStationInfo() { } //TODO: is the device in this form it is now really necessary? - @Override - public DeviceBean getDevice() { - DeviceBean d = new DeviceBean(); - if (ecosManager != null) { - d.setName(ecosManager.getName()); - d.setVersion(ecosManager.getHardwareVersion()); - d.setTypeName(ecosManager.getCommandStationType()); - d.setSerial(ecosManager.getSerialNumber()); - } else { - d.setName("Not Connected"); - } - return d; - } - +// @Override +// public DeviceBean getDevice() { +// DeviceBean d = new DeviceBean(); +// if (ecosManager != null) { +// d.setName(ecosManager.getName()); +// d.setVersion(ecosManager.getHardwareVersion()); +// d.setTypeName(ecosManager.getCommandStationType()); +// d.setSerial(ecosManager.getSerialNumber()); +// } else { +// d.setName("Not Connected"); +// } +// return d; +// } //TODO: is the device in this form it is now really necessary? - @Override - public List getDevices() { - List devices = new ArrayList<>(); - devices.add(getDevice()); - return devices; - } - +// @Override +// public List getDevices() { +// List devices = new ArrayList<>(); +// devices.add(getDevice()); +// return devices; +// } @Override public String getIp() { if (this.connection != null && this.connection.isConnected()) { @@ -556,25 +554,24 @@ EcosConnection getConnection() { return connection; } - @Override - public DeviceBean getFeedbackDevice() { - DeviceBean db = new DeviceBean(); - db.setArticleNumber(this.ecosManager.getName()); - db.setIdentifier("0x0"); - db.getBusLength(this.feedbackManager.getSize()); - db.setVersion(this.ecosManager.getApplicationVersion()); - db.setSerial(this.ecosManager.getSerialNumber()); - db.setTypeName("Link S88"); - - ChannelBean cb = new ChannelBean(); - cb.setName(DeviceBean.BUS0); - cb.setNumber(0); - - db.addSensorBus(0, cb); - - return db; - } - +// @Override +// public DeviceBean getFeedbackDevice() { +// DeviceBean db = new DeviceBean(); +// db.setArticleNumber(this.ecosManager.getName()); +// db.setIdentifier("0x0"); +// db.getBusLength(this.feedbackManager.getSize()); +// db.setVersion(this.ecosManager.getApplicationVersion()); +// db.setSerial(this.ecosManager.getSerialNumber()); +// db.setTypeName("Link S88"); +// +// ChannelBean cb = new ChannelBean(); +// cb.setName(DeviceBean.BUS0); +// cb.setNumber(0); +// +// db.addSensorBus(0, cb); +// +// return db; +// } @Override public List getFeedbackModules() { List feedbackModules = new ArrayList<>(this.feedbackManager.getModules().values()); diff --git a/src/main/java/jcs/commandStation/hsis88/HSIImpl.java b/src/main/java/jcs/commandStation/hsis88/HSIImpl.java index 1be08b88..30482db1 100644 --- a/src/main/java/jcs/commandStation/hsis88/HSIImpl.java +++ b/src/main/java/jcs/commandStation/hsis88/HSIImpl.java @@ -30,7 +30,6 @@ import static jcs.commandStation.hsis88.HSIConnection.COMMAND_VERSION; import jcs.entities.CommandStationBean; import jcs.entities.CommandStationBean.ConnectionType; -import jcs.commandStation.entities.DeviceBean; import jcs.entities.FeedbackModuleBean; import jcs.commandStation.entities.InfoBean; import jcs.commandStation.VirtualConnection; @@ -47,9 +46,9 @@ public class HSIImpl extends AbstractController implements FeedbackController { private HSIConnection connection; private InfoBean infoBean; - private final Map devices; - private DeviceBean mainDevice; - private DeviceBean feedbackDevice; + //private final Map devices; + //private DeviceBean mainDevice; + //private DeviceBean feedbackDevice; private final Map sensors; @@ -59,9 +58,9 @@ public HSIImpl(CommandStationBean commandStationBean) { public HSIImpl(CommandStationBean commandStationBean, boolean autoConnect) { super(autoConnect, commandStationBean); - devices = new HashMap<>(); + //devices = new HashMap<>(); sensors = new HashMap<>(); - this.executor = Executors.newCachedThreadPool(); + //this.executor = Executors.newCachedThreadPool(); if (commandStationBean != null) { if (autoConnect) { @@ -123,24 +122,24 @@ public final synchronized boolean connect() { this.infoBean.setHostname(this.commandStationBean.getSerialPort()); this.infoBean.setProductName(info); - DeviceBean d = new DeviceBean(); + //DeviceBean d = new DeviceBean(); String[] hsiinfo = info.split("/"); - d.setName(info); - d.setUid("0"); - for (int i = 0; i < hsiinfo.length; i++) { - switch (i) { - case 0 -> - d.setVersion(hsiinfo[i]); - case 1 -> - d.setSerial(hsiinfo[i]); - case 2 -> - d.setName(hsiinfo[i]); - case 3 -> - d.setTypeName(hsiinfo[i]); - } - } - this.mainDevice = d; - this.devices.put(0, d); + //d.setName(info); + //d.setUid("0"); +// for (int i = 0; i < hsiinfo.length; i++) { +// switch (i) { +// case 0 -> +// //d.setVersion(hsiinfo[i]); +// case 1 -> +// //d.setSerial(hsiinfo[i]); +// case 2 -> +// //d.setName(hsiinfo[i]); +// case 3 -> +// //d.setTypeName(hsiinfo[i]); +// } +// } +// //this.mainDevice = d; +// this.devices.put(0, d); //Query the S88 Modules ? //connection.sendMessage("m\r"); @@ -156,25 +155,25 @@ public final synchronized boolean connect() { return connected; } - @Override - public DeviceBean getDevice() { - return this.mainDevice; - } +// @Override +// public DeviceBean getDevice() { +// return this.mainDevice; +// } - @Override - public List getDevices() { - return null;//this.devices.values().stream().collect(Collectors.toList()); - } +// @Override +// public List getDevices() { +// return null;//this.devices.values().stream().collect(Collectors.toList()); +// } @Override public InfoBean getCommandStationInfo() { return infoBean; } - @Override - public DeviceBean getFeedbackDevice() { - return this.feedbackDevice; - } +// @Override +// public DeviceBean getFeedbackDevice() { +// return this.feedbackDevice; +// } @Override public List getFeedbackModules() { diff --git a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java index 4e198566..4b7177a0 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java +++ b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java @@ -22,11 +22,12 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.SortedMap; import java.util.Timer; import java.util.TimerTask; +import java.util.concurrent.ConcurrentSkipListMap; import java.util.concurrent.Executors; import java.util.concurrent.TransferQueue; -import java.util.stream.Collectors; import jcs.JCS; import jcs.commandStation.AbstractController; import jcs.commandStation.AccessoryController; @@ -52,20 +53,16 @@ import jcs.commandStation.marklin.cs.net.CSConnection; import jcs.commandStation.marklin.cs.net.CSConnectionFactory; import jcs.commandStation.marklin.cs2.AccessoryBeanParser; -import jcs.commandStation.marklin.cs2.ChannelDataParser; import jcs.commandStation.marklin.cs2.LocomotiveBeanParser; -import jcs.commandStation.marklin.cs3.DeviceJSONParser; import jcs.commandStation.marklin.cs3.FunctionSvgToPngConverter; import jcs.commandStation.marklin.cs3.LocomotiveBeanJSONParser; import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.AccessoryValue; import jcs.entities.ChannelBean; import jcs.entities.CommandStationBean; -import jcs.commandStation.entities.DeviceBean; import jcs.commandStation.entities.InfoBean; import jcs.commandStation.marklin.cs.can.parser.AccessoryMessage; import jcs.entities.FeedbackModuleBean; -import jcs.commandStation.marklin.cs2.InfoBeanParser; import jcs.commandStation.marklin.cs2.LocomotiveDirectionEventParser; import jcs.commandStation.marklin.cs2.LocomotiveFunctionEventParser; import jcs.commandStation.marklin.cs.can.parser.LocomotiveVelocityMessage; @@ -73,8 +70,12 @@ import jcs.commandStation.VirtualConnection; import jcs.commandStation.autopilot.AutoPilot; import jcs.commandStation.autopilot.DriveSimulator; +import jcs.commandStation.entities.MeasuredChannels; +import jcs.commandStation.entities.MeasurementBean; import jcs.commandStation.events.DisconnectionEvent; import jcs.commandStation.events.DisconnectionEventListener; +import jcs.commandStation.marklin.cs.can.device.ConfigChannel; +import jcs.commandStation.marklin.cs.can.device.MeasuringChannel; import jcs.commandStation.marklin.cs.can.parser.CanDevices; import jcs.commandStation.marklin.cs.can.parser.LocomotiveEmergencyStopMessage; import jcs.entities.LocomotiveBean; @@ -83,6 +84,8 @@ import jcs.util.RunUtil; import org.tinylog.Logger; import jcs.commandStation.marklin.cs.net.CSHTTPConnection; +import jcs.commandStation.marklin.parser.GeraetParser; +import jcs.commandStation.marklin.parser.SystemStatusMessage; /** * @@ -93,28 +96,27 @@ public class MarklinCentralStationImpl extends AbstractController implements Dec private CSConnection connection; private InfoBean infoBean; - private final Map devices; - private DeviceBean mainDevice; - private DeviceBean feedbackDevice; + private Map canDevices; + private int csUid; private EventMessageHandler eventMessageHandler; - Map analogChannels; - private DriveSimulator simulator; private Long canBootLoaderLastCallMillis; private WatchdogTask watchdogTask; private Timer watchDogTimer; + private SortedMap measuredValues; + public MarklinCentralStationImpl(CommandStationBean commandStationBean) { this(commandStationBean, false); } public MarklinCentralStationImpl(CommandStationBean commandStationBean, boolean autoConnect) { super(autoConnect, commandStationBean); - devices = new HashMap<>(); - analogChannels = new HashMap<>(); + canDevices = new HashMap<>(); + measuredValues = new ConcurrentSkipListMap<>(); if (commandStationBean != null) { if (autoConnect) { @@ -130,14 +132,9 @@ int getCsUid() { return csUid; } - private boolean isCS3(String articleNumber) { - return "60216".equals(articleNumber) || "60226".equals(articleNumber); - } - - public boolean isCS3() { - if (mainDevice != null) { - String articleNumber = mainDevice.getArticleNumber(); - return "60216".equals(articleNumber) || "60226".equals(articleNumber); + private boolean isCS3() { + if (infoBean != null && infoBean.getArticleNumber() != null) { + return "60216".equals(infoBean.getArticleNumber()) || "60226".equals(infoBean.getArticleNumber()); } else { return false; } @@ -185,53 +182,32 @@ public final synchronized boolean connect() { if (connected) { canBootLoaderLastCallMillis = System.currentTimeMillis(); + JCS.logProgress("Obtaining Device information..."); + CanDevice gfp = getGFP(); + csUid = Integer.parseUnsignedInt(gfp.getUid(), 16); + + canDevices.put(gfp.getUidInt(), gfp); + + obtainDevices(); + infoBean = createInfoBean(canDevices); + //The eventMessageHandler Thread is in charge to handle all event messages which are send from the CS to JCS eventMessageHandler = new EventMessageHandler(connection); eventMessageHandler.start(); - JCS.logProgress("Obtaining Device information..."); - infoBean = getCSInfo(); - - //request all members on the Marklin CAN bus to give a response - long start = System.currentTimeMillis(); - now = System.currentTimeMillis(); - timeout = now + 30000L; - - if (isCS3(infoBean.getArticleNumber())) { - Logger.trace("Connected to CS3"); - getAppDevicesCs3(); - } else { - Logger.trace("Connected to CS2"); - getMembers(); - while (mainDevice == null && mainDevice.getName() == null && mainDevice.getArticleNumber() == null && now < timeout) { - pause(100); - now = System.currentTimeMillis(); - } - } - - if (mainDevice != null) { - Logger.trace("Found " + mainDevice.getName() + ", " + mainDevice.getArticleNumber() + " SerialNumber: " + mainDevice.getSerial() + " in " + (now - start) + " ms"); - JCS.logProgress("Connected with " + infoBean.getProductName()); - } else { - Logger.warn("No main Device found yet..."); - } + Logger.trace("Connected to " + infoBean.getProductName() + ", " + infoBean.getArticleNumber() + " SerialNumber: " + infoBean.getSerialNumber()); csConnection.addDisconnectionEventListener(this); startWatchdog(); power = isPower(); JCS.logProgress("Power is " + (power ? "On" : "Off")); - } - Logger.trace("Connected: " + connected + " Default Accessory SwitchTime: " + defaultSwitchTime); } else { Logger.warn("Can't connect with Central Station!"); JCS.logProgress("Can't connect with Central Station!"); } } -// if (isCS3()) { -// getMembers(); -// } if (isVirtual()) { simulator = new DriveSimulator(); Logger.info("Marklin Central Station Virtual Mode Enabled!"); @@ -244,82 +220,201 @@ public final synchronized boolean connect() { //The Central station has a "geraet.vrs" file which can be retrieved via HTTP. //Based on the info in this file it is quicker to know whether the CS is a version 2 or 3. //In case of a CS-3 the information can be retrieved via JSON else use CAN - private InfoBean getCSInfo() { + CanDevice getGFP() { CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(virtual); String geraet = httpCon.getInfoFile(); - InfoBean ib = InfoBeanParser.parseFile(geraet); - - //CS3? - if ("60126".equals(ib.getArticleNumber()) || "60226".equals(ib.getArticleNumber())) { - String json = httpCon.getInfoJSON(); - ib = InfoBeanParser.parseJson(json); - httpCon.setCs3(true); - } + CanDevice gfp = GeraetParser.parseFile(geraet); + csUid = Integer.parseUnsignedInt(gfp.getUid(), 16); + +// //CS3? +// if ("60126".equals(ib.getArticleNumber()) || "60226".equals(ib.getArticleNumber())) { +// String json = httpCon.getInfoJSON(); +// ib = GeraetParser.parseJson(json); +// httpCon.setCs3(true); +// } +// if (ib.getIpAddress() == null) { +// ib.setIpAddress(connection.getControllerAddress().getHostAddress()); +// } + return gfp; + } - csUid = Integer.parseUnsignedInt(ib.getGfpUid(), 16); + InfoBean createInfoBean(Map canDevices) { + InfoBean ib = new InfoBean(commandStationBean); + ib.setIpAddress(connection.getControllerAddress().getHostAddress()); - if (ib.getIpAddress() == null) { - ib.setIpAddress(connection.getControllerAddress().getHostAddress()); + for (CanDevice d : canDevices.values()) { + Logger.trace("Checking device: " + d); + String name = d.getName(); + if (name == null) { + name = "null"; + } + switch (name) { + case "Central Station 3" -> { + ib.setGfpUid(d.getUid()); + String uid = d.getUid(); + uid = uid.replace("0x", ""); + //csUid = Integer.parseUnsignedInt(uid, 16); + Logger.trace("GFP uid: " + d.getUid() + " -> " + csUid); + + ib.setArticleNumber(d.getArticleNumber()); + ib.setProductName(d.getName()); + ib.setSerialNumber(d.getSerial()); + ib.setHardwareVersion(d.getVersion()); + ib.setSupportMeasurements(d.getMeasureChannelCount() > 0); + + //TODO: Only CS 2 and CS3 plus... + //ib.setFeedbackBus0ModuleCount(0); + //ib.setFeedbackSupport(true); + //Is the System property still needed? + //if (System.getProperty("cs.article") == null) { + //System.setProperty("cs.article", mainDevice.getArticleNumber()); + //System.setProperty("cs.serial", mainDevice.getSerial()); + //System.setProperty("cs.name", mainDevice.getName()); + //System.setProperty("cs.cs3", (isCS3() ? "true" : "false")); + //} + } + case "Link S88" -> { + ib.setFeedbackSupport(true); + ConfigChannel bus1 = d.getConfigChannel(2); + ConfigChannel bus2 = d.getConfigChannel(3); + ConfigChannel bus3 = d.getConfigChannel(4); + + ib.setFeedbackBus1ModuleCount(bus1.getActualValue()); + ib.setFeedbackBus2ModuleCount(bus2.getActualValue()); + ib.setFeedbackBus3ModuleCount(bus3.getActualValue()); + } + case "CS2/3-GUI (Master)" -> { + ib.setSoftwareVersion(d.getVersion()); + } + default -> { + Logger.info("A yet unknown CAN Device " + d); + } + } } - return ib; } /** - * The CS3 has a Web App API which is used for the Web GUI.
- * The Internal devices can be obtained calling this API which returns a JSON string.
- * From this JSON all devices are found.
- * Most important is the GFP which is the heart of the CS 3 most CAN Commands need the GFP UID.
- * This data can also be obtained using the CAN Member PING command, but The JSON gives a little more detail. + * Obtain information about the connected CAN Device in the Central Station */ - private void getAppDevicesCs3() { - CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(virtual); + void obtainDevices() { + //Map members = new HashMap<>(); + CanMessage msg = CanMessageFactory.getMembersPing(); + connection.sendCanMessage(msg); - String devJson = httpCon.getDevicesJSON(); - List devs = DeviceJSONParser.parse(devJson); - //Update the devices - for (DeviceBean d : devs) { - if (devices.containsKey(d.getUidAsInt())) { - devices.put(d.getUidAsInt(), d); + List devices = CanDevices.parse(msg); + Logger.trace("Found " + devices.size() + " CANDevices"); + for (CanDevice d : devices) { + if (!canDevices.containsKey(d.getUidInt())) { + canDevices.put(d.getUidInt(), d); } else { - devices.put(d.getUidAsInt(), d); - } - String an = d.getArticleNumber(); - if ("60213".equals(an) || "60214".equals(an) || "60215".equals(an) || "60126".equals(an) || "60226".equals(an)) { - csUid = d.getUidAsInt(); - mainDevice = d; - Logger.trace("MainDevice: " + d.getName()); - } - - if ("60883".equals(an)) { - feedbackDevice = d; - Logger.trace("FeedbackDevice: " + d.getName()); + CanDevice ed = canDevices.get(d.getUidInt()); + if (d.getSerial() != null) { + ed.setSerial(d.getSerial()); + } + if (d.getVersion() != null) { + ed.setVersion(d.getVersion()); + } + if (d.getIdentifier() != null) { + ed.setIdentifier(d.getIdentifier()); + } + if (d.getMeasureChannelCount() != null) { + ed.setMeasureChannelCount(d.getMeasureChannelCount()); + } + if (d.getConfigChannelCount() != null) { + ed.setConfigChannelCount(d.getConfigChannelCount()); + } + if (d.getArticleNumber() != null) { + ed.setArticleNumber(d.getArticleNumber()); + } + if (d.getName() != null) { + ed.setName(d.getName()); + } + Logger.trace("Updated: " + ed); } - } - Logger.trace("Found " + devices.size() + " devices"); - } - @Override - public DeviceBean getDevice() { - return this.mainDevice; - } + //Lets get some info about these members + for (CanDevice device : canDevices.values()) { + Logger.trace("Obtaining data for device " + device); + CanMessage updateMessage = sendMessage(CanMessageFactory.statusDataConfig(device.getUidInt(), 0)); + if (updateMessage.hasValidResponse()) { + CanDevices.parse(device, updateMessage); - @Override - public List getDevices() { - return this.devices.values().stream().collect(Collectors.toList()); + int measurementChannels; + if (device.getMeasureChannelCount() == null) { + measurementChannels = 0; + } else { + measurementChannels = device.getMeasureChannelCount(); + } + int configChannels; + if (device.getConfigChannelCount() == null) { + configChannels = 0; + } else { + configChannels = device.getConfigChannelCount(); + } + + int channels = measurementChannels + configChannels; + if (channels > 0) { + Logger.trace("Quering " + channels + " channels for device " + device); + for (int index = 1; index <= channels; index++) { + Logger.trace("Query channel " + index); + updateMessage = sendMessage(CanMessageFactory.statusDataConfig(device.getUidInt(), index)); + CanDevices.parse(device, updateMessage); + + if (index <= measurementChannels) { + Logger.trace("M#" + index + "; " + device.getMeasuringChannel(index)); + } else { + int configChannelNumber = index - measurementChannels; + Logger.trace("C#" + configChannelNumber + "; " + device.getConfigChannel(configChannelNumber)); + } + } + } + } else { + Logger.trace("No response data in query for " + device); + } + } } + /** + * The CS3 has a Web App API which is used for the Web GUI.
+ * The Internal devices can be obtained calling this API which returns a JSON string.
+ * From this JSON all devices are found.
+ * Most important is the GFP which is the heart of the CS 3 most CAN Commands need the GFP UID.
+ * This data can also be obtained using the CAN Member PING command, but The JSON gives a little more detail. + */ +// private void getAppDevicesCs3() { +// CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(virtual); +// +// String devJson = httpCon.getDevicesJSON(); +// List devs = DeviceJSONParser.parse(devJson); +// //Update the devices +// for (DeviceBean d : devs) { +// if (devices.containsKey(d.getUidAsInt())) { +// devices.put(d.getUidAsInt(), d); +// } else { +// devices.put(d.getUidAsInt(), d); +// } +// String an = d.getArticleNumber(); +// if ("60213".equals(an) || "60214".equals(an) || "60215".equals(an) || "60126".equals(an) || "60226".equals(an)) { +// csUid = d.getUidAsInt(); +// mainDevice = d; +// Logger.trace("MainDevice: " + d.getName()); +// } +// +// if ("60883".equals(an)) { +// feedbackDevice = d; +// Logger.trace("FeedbackDevice: " + d.getName()); +// } +// +// } +// Logger.trace("Found " + devices.size() + " devices"); +// } @Override public InfoBean getCommandStationInfo() { return infoBean; } - @Override - public DeviceBean getFeedbackDevice() { - return this.feedbackDevice; - } - //TODO! @Override public List getFeedbackModules() { @@ -398,279 +493,66 @@ public void onDisconnect(DisconnectionEvent event) { } } -//#TX: 0x00 0x30 0x07 0x69 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 -> Member ping -//#RX 0: 0x00 0x31 0x37 0x7e 0x08 0x63 0x73 0x45 0x8d 0x02 0x05 0xff 0xff -> Response member CS2-GUI (Master) sw 0x02 0x05 id: 0x63 0x73 0x45 0x8d -//#RX 1: 0x00 0x31 0x7b 0x79 0x08 0x53 0x38 0x5c 0x41 0x01 0x01 0x00 0x40 -> ? sw 0x01 0x01 id: 0x53 0x38 0x5c 0x41 -//#RX 2: 0x00 0x31 0x03 0x26 0x08 0x63 0x73 0x45 0x8c 0x0c 0x71 0x00 0x50 -> ? sw 0x0c 0x71 id: 0x63 0x73 0x45 0x8c - void getMembers() { - CanMessage msg = CanMessageFactory.getMembersPing(); - connection.sendCanMessage(msg); + @Override + public boolean isSupportTrackMeasurements() { + return true; + } - for (CanMessage r : msg.getResponses()) { - DeviceBean d = new DeviceBean(r); + void performMeasurements() { + //The measurable channels are in the GFP. + CanDevice gfp = canDevices.get(csUid); + if (gfp != null) { + List channels = gfp.getMeasuringChannels(); - if (!devices.containsKey(d.getUidAsInt())) { - devices.put(d.getUidAsInt(), d); - } - Logger.trace("Found uid: " + d.getUid() + " deviceId: " + d.getIdentifier() + " Device Type: " + d.getDevice()); - } - Logger.trace("Found " + devices.size() + " devices"); + Logger.trace("Take a measurment on " + channels.size() + " channels"); - while (mainDevice == null) { - for (DeviceBean d : getDevices()) { - if (!d.isDataComplete()) { - if (debug) { - Logger.trace("Requesting more info for uid: " + d.getUid()); - } - CanMessage updateMessage = sendMessage(CanMessageFactory.statusDataConfig(d.getUidAsInt(), 0)); + MeasuredChannels measuredChannels = new MeasuredChannels(System.currentTimeMillis()); + for (MeasuringChannel channel : channels) { + int channelNumber = channel.getNumber(); - //if (debug) { - Logger.trace(updateMessage); - for (CanMessage r : updateMessage.getResponses()) { - Logger.trace(r); - } - //} - d.updateFromMessage(updateMessage); - if (debug) { - if (d.isDataComplete()) { - Logger.trace("Updated: " + d); - } else { - Logger.trace("No data received for Device uid: " + d.getUid()); - } - } - } - } + CanMessage message = sendMessage(CanMessageFactory.systemStatus(csUid, channelNumber)); - for (DeviceBean d : getDevices()) { - if (d.isDataComplete() && ("60213".equals(d.getArticleNumber()) || "60214".equals(d.getArticleNumber()) || "60215".equals(d.getArticleNumber()) || "60126".equals(d.getArticleNumber()) || "60226".equals(d.getArticleNumber()))) { - csUid = d.getUidAsInt(); - mainDevice = d; - if (debug) { - Logger.trace("Main Device: " + d); - } - if (System.getProperty("cs.article") == null) { - System.setProperty("cs.article", mainDevice.getArticleNumber()); - System.setProperty("cs.serial", mainDevice.getSerial()); - System.setProperty("cs.name", mainDevice.getName()); - System.setProperty("cs.cs3", (isCS3() ? "true" : "false")); - } - } else { - if (debug) { - Logger.trace(d); - } - } + MeasurementBean measurement = SystemStatusMessage.parse(channel, message); + measuredChannels.addMeasurement(measurement); + Logger.trace(measurement); } + Logger.trace("Measurement: " + measuredChannels); + } else { + Logger.warn("No measurable channels avalaible"); } } - //Map devices; - void memberPing() { - Map members = new HashMap<>(); - CanMessage msg = CanMessageFactory.getMembersPing(); - connection.sendCanMessage(msg); - - List canDevices = CanDevices.parse(msg); - for (CanDevice d : canDevices) { - if (!members.containsKey(d.getUidInt())) { - members.put(d.getUidInt(), d); - } - } - - for (CanDevice device : canDevices) { - Logger.trace("Device: " + device); - } - - //Lets get some info about these members - //for (CanDevice d : members.values()) { - for (CanDevice device : canDevices) { - //if ("0x6373458c".equals(device.getUid())) { - if ("0x53385c41".equals(device.getUid())) { - //if (!d.isDataComplete()) { - Logger.trace("Query Device data for uid: " + device.getUid()); - - CanMessage updateMessage = sendMessage(CanMessageFactory.statusDataConfig(device.getUidInt(), 0)); - CanDevices.parse(device, updateMessage); - - Logger.trace("Device: " + device); - - int measurementChannels; - if (device.getMeasureChannelCount() == null) { - measurementChannels = 0; - } else { - measurementChannels = device.getMeasureChannelCount(); - } - int configChannels; - if (device.getConfigChannelCount() == null) { - configChannels = 0; - } else { - configChannels = device.getConfigChannelCount(); - } - - Logger.trace("Device " + device.getName() + " has " + measurementChannels + " Measurement Channels and " + configChannels + " Config Channels"); - int channels = measurementChannels + configChannels; - if (channels > 0) { - for (int index = 1; index <= channels; index++) { - updateMessage = sendMessage(CanMessageFactory.statusDataConfig(device.getUidInt(), index)); - CanDevices.parse(device, updateMessage); - } - } - } - } -// // d.updateFromMessage(updateMessage); -// -// Logger.trace("Updated with device info: " + d); -// -// if (d.getMeasureChannels() != null && d.getMeasureChannels() > 0) { -// Logger.trace(d.getMeasureChannels() + " Measurement Channels"); -// //Query the measurement channels -// int max = d.getMeasureChannels(); -// for (int ch = 1; ch <= max; ch++) { -// Logger.trace("Query measurment channels for device " + d.getName() + " and measure channel " + ch); -// updateMessage = sendMessage(CanMessageFactory.statusDataConfig(d.getUidAsInt(), ch)); -// d.updateFromMessage(updateMessage); -// -// Logger.trace("# Updated after ch " + ch + " " + d); -// -// } -// Logger.trace("Updated " + d); -// } -// -// if (d.getConfigChannels() != null && d.getConfigChannels() > 0 && 1==2) { -// Logger.trace(d.getConfigChannels() + " Config Channels"); -// //Get the channels -// int max = d.getConfigChannels(); -// for (int ch = 1; ch < max; ch++) { -// Logger.trace("Requesting more info for uid: " + d.getUid() + " and config channel " + ch); -// -// updateMessage = sendMessage(CanMessageFactory.statusDataConfig(d.getUidAsInt(), ch)); -// if (updateMessage.hasValidResponse()) { -// d.updateFromMessage(updateMessage); -// } else { -// break; -// } -// } -// Logger.trace("Updated " + d); -// //} + @Override + public synchronized Map getTrackMeasurements() { +// Logger.trace("Perform measurement..."); +// if (connected && mainDevice != null) { +// //main device +// int nrOfChannels = mainDevice.getAnalogChannels().size(); // -// if (d.isDataComplete()) { -// Logger.trace("#Updated: " + d); -// } else { -// Logger.trace("No data received for Device uid: " + d.getUid()); -// } +// ChannelDataParser parser = new ChannelDataParser(); // -// } else { -// Logger.trace("Data complete for " + d); +// if (this.analogChannels.isEmpty()) { +// //No channels configured so let do this first +// for (int c = 1; c <= nrOfChannels; c++) { +// Logger.trace("Quering config for channel " + c); +// CanMessage message = sendMessage(CanMessageFactory.statusDataConfig(csUid, c)); // +// ChannelBean ch = parser.parseConfigMessage(message); +// analogChannels.put(c, ch); // } // } -// } - -// for (DeviceBean d : getDevices()) { -// if (d.isDataComplete() && ("60213".equals(d.getArticleNumber()) || "60214".equals(d.getArticleNumber()) || "60215".equals(d.getArticleNumber()) || "60126".equals(d.getArticleNumber()) || "60226".equals(d.getArticleNumber()))) { -// csUid = d.getUidAsInt(); -// mainDevice = d; -// if (debug) { -// Logger.trace("Main Device: " + d); -// } -// if (System.getProperty("cs.article") == null) { -// System.setProperty("cs.article", mainDevice.getArticleNumber()); -// System.setProperty("cs.serial", mainDevice.getSerial()); -// System.setProperty("cs.name", mainDevice.getName()); -// System.setProperty("cs.cs3", (isCS3() ? "true" : "false")); -// } -// } else { -// if (debug) { -// Logger.trace(d); -// } +// +// for (int c = 1; c <= nrOfChannels; c++) { +// ChannelBean ch = this.analogChannels.get(c); +// if (ch != null) { +// CanMessage message = sendMessage(CanMessageFactory.systemStatus(c, csUid)); +// ch = parser.parseUpdateMessage(message, ch); +// analogChannels.put(c, ch); // } -// +// } // } - } - - private void updateDevice(final CanMessage message) { - if (CanMessage.PING_RESP == message.getCommand()) { - int uid = message.getDeviceUidNumberFromMessage(); - - DeviceBean device; - if (devices.containsKey(uid)) { - device = devices.get(uid); - } else { - device = new DeviceBean(message); - devices.put(device.getUidAsInt(), device); - } - - if (!device.isDataComplete()) { - CanMessage msg = sendMessage(CanMessageFactory.statusDataConfig(device.getUidAsInt(), 0)); - device.updateFromMessage(msg); - if (debug) { - Logger.trace("Updated: " + device); - } - //Can the main device be set from the avaliable data - for (DeviceBean d : devices.values()) { - if (d.isDataComplete() && ("60214".equals(d.getArticleNumber()) || "60226".equals(d.getArticleNumber()) || "60126".equals(d.getArticleNumber()))) { - csUid = d.getUidAsInt(); - mainDevice = d; - if (debug) { - Logger.trace("Main Device: " + d); - } - } - } - } - - if (mainDevice == null) { - //Lets send a ping again - getMembers(); - } else { - if (mainDevice != null && mainDevice.isDataComplete()) { - if (System.getProperty("cs.article") == null) { - System.setProperty("cs.article", mainDevice.getArticleNumber()); - System.setProperty("cs.serial", mainDevice.getSerial()); - System.setProperty("cs.name", mainDevice.getName()); - System.setProperty("cs.cs3", (isCS3() ? "true" : "false")); - if (debug) { - Logger.trace("CS " + (isCS3() ? "3" : "2") + " Device: " + device); - } - } - } - } - } - } - - @Override - public boolean isSupportTrackMeasurements() { - return true; - } - - @Override - public synchronized Map getTrackMeasurements() { - Logger.trace("Perform measurement..."); - if (connected && mainDevice != null) { - //main device - int nrOfChannels = mainDevice.getAnalogChannels().size(); - - ChannelDataParser parser = new ChannelDataParser(); - - if (this.analogChannels.isEmpty()) { - //No channels configured so let do this first - for (int c = 1; c <= nrOfChannels; c++) { - Logger.trace("Quering config for channel " + c); - CanMessage message = sendMessage(CanMessageFactory.statusDataConfig(csUid, c)); - - ChannelBean ch = parser.parseConfigMessage(message); - analogChannels.put(c, ch); - } - } - - for (int c = 1; c <= nrOfChannels; c++) { - ChannelBean ch = this.analogChannels.get(c); - if (ch != null) { - CanMessage message = sendMessage(CanMessageFactory.systemStatus(c, csUid)); - ch = parser.parseUpdateMessage(message, ch); - analogChannels.put(c, ch); - } - } - } - return analogChannels; +// return analogChannels; + return null; } /** @@ -697,9 +579,6 @@ public void changeDirection(int locUid, Direction direction) { Logger.trace("Change direction to " + direction + " CS val " + direction.getMarklinValue()); CanMessage message = sendMessage(CanMessageFactory.setDirection(locUid, direction.getMarklinValue(), this.csUid)); //query velocity of give a not halt - //DirectionChange# 0x00 0x0a 0x37 0x7e 0x05 0x00 0x00 0x40 0x0c 0x01 0x00 0x00 0x00 - //BR 216 059-6 Speed changed from 218 to 0 - //DirectionChange 0x00 0x0b 0x03 0x26 0x05 0x00 0x00 0x40 0x0c 0x01 0x00 0x00 0x00 LocomotiveDirectionEvent dme = LocomotiveDirectionEventParser.parseMessage(message); notifyLocomotiveDirectionEventListeners(dme); } @@ -970,18 +849,16 @@ public void run() { switch (command) { case CanMessage.PING_REQ -> { //Lets do this the when we know all of the CS... - if (mainDevice != null) { - if (CanMessage.DLC_0 == dlc) { - //Logger.trace("Answering Ping RQ: " + eventMessage); - sendJCSUIDMessage(); - } + if (CanMessage.DLC_0 == dlc) { + //Logger.trace("Answering Ping RQ: " + eventMessage); + //sendJCSUIDMessage(); } } case CanMessage.PING_RESP -> { if (CanMessage.DLC_8 == dlc) { //Logger.trace("Ping Response RX: " + eventMessage); - updateDevice(eventMessage); + //updateDevice(eventMessage); } } case CanMessage.STATUS_CONFIG -> { @@ -992,6 +869,8 @@ public void run() { } case CanMessage.STATUS_CONFIG_RESP -> { Logger.trace("StatusConfigResponse RX: " + eventMessage); + //add to an list of resposne check + } case CanMessage.S88_EVENT_RESPONSE -> { if (CanMessage.DLC_8 == dlc) { @@ -1180,7 +1059,7 @@ public static void main(String[] a) { //cs.getAccessoriesViaCan(); //cs.pause(2000); //cs.getMembers(); - cs.memberPing(); + //cs.memberPing(); //Logger.trace("getStatusDataConfig CS3"); //cs.getStatusDataConfigCS3(); //cs.pause(2000); @@ -1210,6 +1089,7 @@ public static void main(String[] a) { // Logger.debug("Channel 3: " + cs.channelData3.getChannel().getHumanValue() + " " + cs.channelData3.getChannel().getUnit()); // Logger.debug("Channel 4: " + cs.channelData4.getChannel().getHumanValue() + " " + cs.channelData4.getChannel().getUnit()); //cs.getSystemStatus(1); + cs.performMeasurements(); // // Logger.debug("Channel 4...."); // cs.getSystemStatus(4); diff --git a/src/main/java/jcs/commandStation/marklin/cs/can/CanMessageFactory.java b/src/main/java/jcs/commandStation/marklin/cs/can/CanMessageFactory.java index 19ac023c..acce43e0 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/can/CanMessageFactory.java +++ b/src/main/java/jcs/commandStation/marklin/cs/can/CanMessageFactory.java @@ -196,13 +196,13 @@ public static CanMessage getMobileAppPingRequest() { * @param gfpUid the GFP UID * @return */ - public static CanMessage systemStatus(int channel, int gfpUid) { + public static CanMessage systemStatus(int uid, int channel) { byte[] data = new byte[CanMessage.DATA_SIZE]; byte[] hash; - if (gfpUid > 0) { - byte[] uid = CanMessage.to4Bytes(gfpUid); - System.arraycopy(uid, 0, data, 0, uid.length); - hash = CanMessage.generateHash(gfpUid); + if (uid > 0) { + byte[] uidb = CanMessage.to4Bytes(uid); + System.arraycopy(uidb, 0, data, 0, uidb.length); + hash = CanMessage.generateHash(uid); } else { hash = MAGIC_HASH; } diff --git a/src/main/java/jcs/commandStation/marklin/cs/can/device/CanDevice.java b/src/main/java/jcs/commandStation/marklin/cs/can/device/CanDevice.java index 639b4eec..e8cb2802 100644 --- a/src/main/java/jcs/commandStation/marklin/cs/can/device/CanDevice.java +++ b/src/main/java/jcs/commandStation/marklin/cs/can/device/CanDevice.java @@ -15,12 +15,12 @@ */ package jcs.commandStation.marklin.cs.can.device; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Objects; import jcs.commandStation.marklin.cs.can.CanMessage; -import org.json.JSONArray; -import org.json.JSONObject; /** * A CanDevice is a Device inside or connected to the Marklin Central Station
@@ -52,6 +52,7 @@ public class CanDevice { // Gerätebezeichnung, \0 Terminiert private String uid; private String version; + private String hwVersion; private String identifier; private Integer measureChannelCount; private Integer configChannelCount; @@ -59,16 +60,6 @@ public class CanDevice { private String articleNumber; private String name; -// private String typeName; -// private String type; -// private Integer queryInteval; -// private Boolean present; -// private Integer available; -// private String config; -// private Boolean ready; -// private String path; -// private Boolean mounted; -// private final List channels; private final Map measuringChannels; private final Map configChannels; @@ -84,9 +75,6 @@ public CanDevice() { public CanDevice(String json) { measuringChannels = new HashMap<>(); configChannels = new HashMap<>(); - if (json != null) { - parse(json); - } } /** @@ -103,16 +91,23 @@ public String getUid() { return uid; } + public Integer getUidInt() { + String ui = uid.replace("0x", ""); + return Integer.parseUnsignedInt(ui, 16); + } + public void setUid(String uid) { this.uid = uid; } - public Integer getUidInt() { - String ui = uid.replace("0x", ""); - return Integer.parseUnsignedInt(ui, 16); + public void setUid(Integer uid) { + this.uid = "0x" + uid; } public String getName() { + if (name == null && this.identifier != null && this.identifier.equals("0xffff")) { + return getDeviceType(); + } return name; } @@ -149,6 +144,10 @@ public void setSerial(String serial) { this.serial = serial; } + public void setSerial(Integer serial) { + this.serial = serial.toString(); + } + public Integer getMeasureChannelCount() { return measureChannelCount; } @@ -173,37 +172,12 @@ public void setVersion(String version) { this.version = version; } - private void parse(String json) { - if (json == null) { - return; - } - JSONObject device = new JSONObject(json); - - this.uid = device.optString("_uid"); - this.name = device.optString("_name"); - //this.typeName = device.optString("_typname"); - this.identifier = device.optString("_kennung"); - //this.type = device.optString("_typ"); - this.articleNumber = device.optString("_artikelnr"); - this.serial = device.optString("_seriennr"); - //this.queryInteval = device.optInt("_queryInterval"); - - JSONObject versionObj = device.optJSONObject("_version"); - if (versionObj != null) { - String major = versionObj.optString("major"); - String minor = versionObj.optString("minor"); - this.version = (major != null ? major : "") + (major != null ? "." : "") + (minor != null ? minor : ""); - } - - JSONArray channelsJA = device.optJSONArray("_kanal"); - if (channelsJA != null) { - for (int i = 0; i < channelsJA.length(); i++) { - JSONObject kanal = channelsJA.getJSONObject(i); + public String getHwVersion() { + return hwVersion; + } - MeasuringChannel cb = new MeasuringChannel(kanal.toString()); - this.measuringChannels.put(cb.getNumber(), cb); - } - } + public void setHwVersion(String HwVersion) { + this.hwVersion = HwVersion; } public String getDeviceType() { @@ -237,6 +211,10 @@ public void addMeasuringChannel(MeasuringChannel measuringChannel) { measuringChannels.put(measuringChannel.getNumber(), measuringChannel); } + public List getMeasuringChannels() { + return new ArrayList<>(measuringChannels.values()); + } + public void addConfigChannel(ConfigChannel configChannel) { configChannels.put(configChannel.getNumber(), configChannel); } @@ -245,28 +223,10 @@ public ConfigChannel getConfigChannel(Integer number) { return configChannels.get(number); } -// public int getBusLength(Integer busNr) { -// if (this.isFeedbackDevice()) { -// CSChannel cb = this.sensorBuses.get(busNr); -// if (cb != null) { -// if (busNr == 0) { -// return 1; -// } else { -// return cb.getValue(); -// } -// } else { -// return 0; -// } -// } else { -// return -1; -// } -// } -// public Integer getLinkS88ContactIdOffset(int busNr) { -// return (busNr - 1) * 1000; -// } -// public boolean isFeedbackDevice() { -// return "Link S88".equals(typeName); -// } + public List getConfigChannels() { + return new ArrayList<>(configChannels.values()); + } + @Override public String toString() { StringBuilder sb = new StringBuilder(); @@ -276,6 +236,8 @@ public String toString() { } if (name != null) { sb.append(", name=").append(name); + } else if (getName() != null) { + sb.append(", derivedname=").append(getName()); } if (identifier != null) { sb.append(", identifier=").append(identifier); @@ -295,6 +257,15 @@ public String toString() { if (version != null) { sb.append(", version=").append(version); } + if (hwVersion != null) { + sb.append(", hwVersion=").append(hwVersion); + } + if (!measuringChannels.isEmpty()) { + sb.append(", measuringChannels=").append(measuringChannels); + } + if (!configChannels.isEmpty()) { + sb.append(", configChannels=").append(configChannels); + } sb.append("}"); return sb.toString(); } @@ -304,6 +275,7 @@ public int hashCode() { int hash = 7; hash = 79 * hash + Objects.hashCode(this.uid); hash = 79 * hash + Objects.hashCode(this.version); + hash = 79 * hash + Objects.hashCode(this.hwVersion); hash = 79 * hash + Objects.hashCode(this.identifier); hash = 79 * hash + Objects.hashCode(this.measureChannelCount); hash = 79 * hash + Objects.hashCode(this.configChannelCount); @@ -333,6 +305,9 @@ public boolean equals(Object obj) { if (!Objects.equals(this.version, other.version)) { return false; } + if (!Objects.equals(this.hwVersion, other.hwVersion)) { + return false; + } if (!Objects.equals(this.identifier, other.identifier)) { return false; } @@ -348,12 +323,12 @@ public boolean equals(Object obj) { if (!Objects.equals(this.configChannelCount, other.configChannelCount)) { return false; } -// if (!Objects.equals(this.measuringChannels, other.measuringChannels)) { -// return false; -// } -// if (!Objects.equals(this.configChannels, other.configChannels)) { -// return false; -// } + if (!Objects.equals(this.measuringChannels, other.measuringChannels)) { + return false; + } + if (!Objects.equals(this.configChannels, other.configChannels)) { + return false; + } return Objects.equals(this.name, other.name); } diff --git a/src/main/java/jcs/commandStation/marklin/cs/can/device/MeasuringChannel.java b/src/main/java/jcs/commandStation/marklin/cs/can/device/MeasuringChannel.java index e9bac1df..c2ddf901 100644 --- a/src/main/java/jcs/commandStation/marklin/cs/can/device/MeasuringChannel.java +++ b/src/main/java/jcs/commandStation/marklin/cs/can/device/MeasuringChannel.java @@ -17,28 +17,12 @@ import java.util.Objects; import org.json.JSONObject; -import org.tinylog.Logger; /** * Represents a Measurement Channel in the Marklin Central Station */ public class MeasuringChannel { -// Abfragekanalnummer -//Potenz des Messwerts -//Farbe Bereich 1 -//Farbe Bereich 2 -//Farbe Bereich 3 -// Farbe Bereich 4 -// Nullpunkt -// Ende Bereich 1 -// Ende Bereich 2 -// Ende Bereich 3 -// Ende Bereich 4 -// Messwertbezeichnung -// Bezeichnung Start -// Bezeichnung Ende -// Einheit private Integer number; private Integer scale; private Integer colorGreen; diff --git a/src/main/java/jcs/commandStation/marklin/cs/can/parser/CanDevices.java b/src/main/java/jcs/commandStation/marklin/cs/can/parser/CanDevices.java index 71c5f011..c88d56f7 100644 --- a/src/main/java/jcs/commandStation/marklin/cs/can/parser/CanDevices.java +++ b/src/main/java/jcs/commandStation/marklin/cs/can/parser/CanDevices.java @@ -38,7 +38,7 @@ public static List parse(CanMessage memberPingmessage) { devices.add(device); } } - Logger.trace("Found " + devices.size() + " CANDevices"); + return devices; } @@ -123,6 +123,15 @@ public static void parse(CanDevice canDevice, CanMessage statusConfigmessage) { } } + +//Anzahl der Messwerte im Gerät. +//Anzahl der Konfigurationskanäle +//frei. +//Seriennummer CS2. +//8 Byte Artikelnummer. +//Gerätebezeichnung, \0 Terminiert + + /** * In case the index equals zero (0) the responses contain a CAN Device Description. * @@ -143,6 +152,14 @@ private static void parseDeviceDescription(CanDevice canDevice, List int configChannels = Byte.toUnsignedInt(data[1]); canDevice.setMeasureChannelCount(measureChannels); canDevice.setConfigChannelCount(configChannels); + + byte[] free = new byte[2]; + System.arraycopy(data, 2, free, 0, free.length); + + byte[] sn = new byte[4]; + System.arraycopy(data, 4, sn, 0, sn.length); + int serial = CanMessage.toInt(sn); + canDevice.setSerial(serial); } else { Logger.trace("Invalid DLC " + msg.getDlc() + " Package " + packageNr + " " + msg); } @@ -344,9 +361,9 @@ private static void parseConfigurationChannel(CanDevice canDevice, List strings = splitIntoStrings(stringDataList); - for (String s : strings) { - Logger.trace(s); - } + //for (String s : strings) { + // Logger.trace(s); + //} int choicesCount = 0; if (channel.getChoicesCount() != null) { choicesCount = channel.getChoicesCount(); @@ -358,7 +375,7 @@ private static void parseConfigurationChannel(CanDevice canDevice, List 0) { //next are the choices for (int j = 1; j <= choicesCount; j++) { - if (strings.size() >= j) { + if (strings.size() > j) { channel.addChoice(strings.get(j)); } } diff --git a/src/main/java/jcs/commandStation/marklin/cs2/ChannelDataParser.java b/src/main/java/jcs/commandStation/marklin/cs2/ChannelDataParser.java deleted file mode 100644 index 152b4350..00000000 --- a/src/main/java/jcs/commandStation/marklin/cs2/ChannelDataParser.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright 2023 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.commandStation.marklin.cs2; - -import java.io.Serializable; -import java.util.List; -import jcs.commandStation.marklin.cs.can.CanMessage; -import jcs.entities.ChannelBean; -import jcs.util.ByteUtil; -import org.tinylog.Logger; - -/** - * - * @author Frans Jacobs - */ -public class ChannelDataParser implements Serializable { - - public ChannelDataParser() { - - } - - private int getStringLength(byte[] data) { - for (int i = 0; i < data.length; i++) { - if (data[i] == 0x00) { - return i; - } - } - return data.length; - } - - private int getNumberOfPackets(CanMessage message) { - int packets = -1; - List responses = message.getResponses(); - Logger.trace("Response count: "+responses.size()); - - if(responses.isEmpty()) { - return 0; - } - int lastIdx = responses.size(); - if (lastIdx > 0) { - lastIdx = lastIdx - 1; - } else { - return -1; - } - CanMessage last = responses.get(lastIdx); - - if (last.getDlc() == CanMessage.DLC_6) { - packets = last.getDataByte(5); - } else if (last.getDlc() == CanMessage.DLC_5) { - //CS-2 lets assume the number packets to be the size - packets = responses.size() - 1; - } - return packets; - } - - public ChannelBean parseConfigMessage(CanMessage message) { - ChannelBean channel = new ChannelBean(); - if (message.getCommand() == CanMessage.STATUS_CONFIG) { - List responses = message.getResponses(); - int packets = getNumberOfPackets(message); - if(packets == 0) { - Logger.trace("No packets avaliable"); - return null; - } - - //Create one array with data - byte[] data = new byte[8 * packets]; - - if (packets > 0) { - for (int i = 0; i < packets; i++) { - byte[] d = responses.get(i).getData(); - System.arraycopy(d, 0, data, (i * d.length), d.length); - } - int number = Byte.toUnsignedInt(data[0]); - int scale = data[1]; - - int colorMax = Byte.toUnsignedInt(data[2]); - int colorGreen = Byte.toUnsignedInt(data[3]); - int colorYellow = Byte.toUnsignedInt(data[4]); - int colorRed = Byte.toUnsignedInt(data[5]); - double startValue = ((double) ByteUtil.toInt(new byte[]{data[6], data[7]})); - - channel.setNumber(number); - channel.setScale(scale); - channel.setColorMax(colorMax); - channel.setColorGreen(colorGreen); - channel.setColorYellow(colorYellow); - channel.setColorRed(colorRed); - channel.setStartValue(startValue); - - //1 - int rangeMax = ByteUtil.toInt(new byte[]{data[8], data[9]}); - int rangeGreen = ByteUtil.toInt(new byte[]{data[10], data[11]}); - int rangeYellow = ByteUtil.toInt(new byte[]{data[12], data[13]}); - int rangeRed = ByteUtil.toInt(new byte[]{data[14], data[15]}); - - channel.setRangeMax(rangeMax); - channel.setRangeGreen(rangeGreen); - channel.setRangeYellow(rangeYellow); - channel.setRangeRed(rangeRed); - - //2,3,4 - //parse the strings - int idx = 16; //we are now @ byte 16; get all remaining bytes from here - int fullLen = data.length - idx; - byte[] stringdata = new byte[fullLen]; - System.arraycopy(data, idx, stringdata, 0, stringdata.length); - //get the lenght util \0 - int len = this.getStringLength(stringdata); - byte[] strArr = new byte[len]; - System.arraycopy(data, idx, strArr, 0, strArr.length); - - String name = ByteUtil.bytesToString(strArr); - channel.setName(name); - - //next string - idx = idx + len + 1; - fullLen = data.length - idx; - stringdata = new byte[fullLen]; - System.arraycopy(data, idx, stringdata, 0, stringdata.length); - len = this.getStringLength(stringdata); - strArr = new byte[len]; - System.arraycopy(data, idx, strArr, 0, strArr.length); - String startVal = ByteUtil.bytesToString(strArr); - if(startVal == null) { - startVal = "0.0"; - } - double startValDouble = Double.parseDouble(startVal); - channel.setStartValue(startValDouble); - - //next string - idx = idx + len + 1; - fullLen = data.length - idx; - stringdata = new byte[fullLen]; - System.arraycopy(data, idx, stringdata, 0, stringdata.length); - len = this.getStringLength(stringdata); - strArr = new byte[len]; - System.arraycopy(data, idx, strArr, 0, strArr.length); - String endVal = ByteUtil.bytesToString(strArr); - - double endValue = Double.parseDouble(endVal); - channel.setEndValue(endValue); - - //next string - idx = idx + len + 1; - fullLen = data.length - idx; - stringdata = new byte[fullLen]; - System.arraycopy(data, idx, stringdata, 0, stringdata.length); - len = this.getStringLength(stringdata); - strArr = new byte[len]; - System.arraycopy(data, idx, strArr, 0, strArr.length); - String uom = ByteUtil.bytesToString(strArr); - channel.setUnit(uom); - - //last string?? - idx = idx + len + 1; - fullLen = data.length - idx; - if (fullLen > 0) { - stringdata = new byte[fullLen]; - System.arraycopy(data, idx, stringdata, 0, stringdata.length); - len = this.getStringLength(stringdata); - strArr = new byte[len]; - System.arraycopy(data, idx, strArr, 0, strArr.length); - String xxx = ByteUtil.bytesToString(strArr); - Logger.trace("Found string part: " + xxx); - } - } else { - Logger.warn("Config packet data Invalid"); - } - } else { - Logger.trace("Command: " + ByteUtil.toHexString(message.getCommand()) + " Sub Command: " + ByteUtil.toHexString(message.getSubCommand())); - } - return channel; - } - - public ChannelBean parseUpdateMessage(CanMessage message, ChannelBean channel) { - if (message.getCommand() == CanMessage.SYSTEM_COMMAND && message.getSubCommand() == CanMessage.SYSTEM_SUB_STATUS) { - CanMessage response = message.getResponse(); - byte[] data = response.getData(); - int number = data[5]; - int value = CanMessage.toInt(new byte[]{data[6], data[7]}); - - if (channel.getNumber() == number) { - channel.setValue(value); - } else { - Logger.warn("Can't set value for " + channel.getNumber() + " as the response is for channel " + number); - } - } else { - Logger.trace("Command: " + ByteUtil.toHexString(message.getCommand()) + " Sub Command: " + ByteUtil.toHexString(message.getSubCommand())); - } - return channel; - } - -} diff --git a/src/main/java/jcs/commandStation/marklin/cs2/InfoBeanParser.java b/src/main/java/jcs/commandStation/marklin/parser/GeraetParser.java similarity index 60% rename from src/main/java/jcs/commandStation/marklin/cs2/InfoBeanParser.java rename to src/main/java/jcs/commandStation/marklin/parser/GeraetParser.java index 16f61e39..ecfea8e1 100644 --- a/src/main/java/jcs/commandStation/marklin/cs2/InfoBeanParser.java +++ b/src/main/java/jcs/commandStation/marklin/parser/GeraetParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2024 Frans Jacobs. + * Copyright 2025 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,24 +13,34 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package jcs.commandStation.marklin.cs2; +package jcs.commandStation.marklin.parser; import jcs.commandStation.entities.InfoBean; +import jcs.commandStation.marklin.cs.can.device.CanDevice; import org.json.JSONObject; /** - * Parse an InfoBean from Marklin CS2 file or CS 3 JSON. + * Parse an InfoBean from Marklin CS2/3 file. */ -public class InfoBeanParser { +public class GeraetParser { - public static InfoBean parseFile(String file) { - if (file == null) { + /** + * The quickest method to obtain basic information of the Central Station is to query the "geraet" file via the http interface. + * + * @param commandStationBean + * @param geraetFile + * @return + */ + public static CanDevice parseFile(String geraetFile) { + if (geraetFile == null) { return null; } - InfoBean ib = new InfoBean(); + CanDevice gfp = new CanDevice(); + //InfoBean ib = new InfoBean(); + //ib.copyInto(commandStationBean); - String[] lines = file.split("\n"); + String[] lines = geraetFile.split("\n"); String minor = ""; String major = ""; for (String line : lines) { @@ -52,50 +62,56 @@ public static InfoBean parseFile(String file) { minor = value; } case ".sernum" -> { - //this.serialNumber = value; - ib.setSerialNumber(value); + //ib.setSerialNumber(value); + gfp.setSerial(value); } case ".gfpuid" -> { - //this.gfpUid = value; - ib.setGfpUid(value); + //ib.setGfpUid(value); + gfp.setUid(value); } case ".guiuid" -> { - //this.guiUid = value; - ib.setGuiUid(value); + //ib.setGuiUid(value); } case ".hardvers" -> { - //this.hardwareVersion = value; - ib.setHardwareVersion(value); + //ib.setHardwareVersion(value); + gfp.setHwVersion(value); } case ".articleno" -> { - //this.articleNumber = value; - ib.setArticleNumber(value); + //ib.setArticleNumber(value); + gfp.setArticleNumber(value); } case ".produkt" -> { - //this.productName = value; - ib.setProductName(value); + //ib.setProductName(value); + gfp.setName(value); } } } String softwareVersion = (major != null ? major : "") + (major != null ? "." : "") + (minor != null ? minor : ""); - ib.setSoftwareVersion(softwareVersion); + //ib.setSoftwareVersion(softwareVersion); + gfp.setVersion(softwareVersion); + + if (gfp.getSerial().length() < 5) { + gfp.setSerial("0" + gfp.getSerial()); + } String shortName; - //String sn = ib.getSerialNumber(); - if (ib.getProductName() != null && ib.getProductName().contains("Central Station 3")) { + if (gfp.getName() != null && gfp.getName().contains("Central Station 3")) { shortName = "CS3"; } else { shortName = "CS2"; } - if (ib.getSerialNumber().length() < 5) { - ib.setSerialNumber("0" + ib.getSerialNumber()); - } - ib.setHostname(shortName + "-" + ib.getSerialNumber()); - - return ib; + + gfp.setIdentifier("0x00"); + return gfp; } + /** + * The CS 3 has JSON files accessible via the web interface which contains lots of info about the CS + * + * @param json + * @return + */ public static InfoBean parseJson(String json) { if (json == null) { return null; diff --git a/src/main/java/jcs/commandStation/marklin/parser/SystemStatusMessage.java b/src/main/java/jcs/commandStation/marklin/parser/SystemStatusMessage.java new file mode 100644 index 00000000..d5da87f2 --- /dev/null +++ b/src/main/java/jcs/commandStation/marklin/parser/SystemStatusMessage.java @@ -0,0 +1,106 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.commandStation.marklin.parser; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import jcs.commandStation.entities.MeasurementBean; +import jcs.commandStation.marklin.cs.can.CanMessage; +import jcs.commandStation.marklin.cs.can.device.MeasuringChannel; +import org.tinylog.Logger; + +/** + * Convert the SystemStatus Message measured values into a MeasurementBean + */ +public class SystemStatusMessage { + + public SystemStatusMessage() { + + } + + public static MeasurementBean parse(MeasuringChannel channel, CanMessage systemStatusmessage) { + + Logger.trace(systemStatusmessage); + + MeasurementBean measurement = null; + if (systemStatusmessage.getCommand() == CanMessage.SYSTEM_COMMAND && systemStatusmessage.getSubCommand() == CanMessage.SYSTEM_SUB_STATUS) { + CanMessage response = systemStatusmessage.getResponse(); + byte[] data = response.getData(); + + switch (response.getDlc()) { + case CanMessage.DLC_7 -> { + int channelNumber = data[5]; + int valid = data[6]; + measurement = new MeasurementBean(channelNumber, channel.getName(), (valid == 1), System.currentTimeMillis()); + } + case CanMessage.DLC_8 -> { + int channelNumber = data[5]; + int measuredValue = CanMessage.toInt(new byte[]{data[6], data[7]}); + + Double displayValue = calculateDisplayValue(measuredValue, channel); + measurement = new MeasurementBean(channelNumber, channel.getName(), System.currentTimeMillis(), measuredValue, channel.getUnit(), displayValue); + } + default -> + Logger.error("Invalid DLC " + response.getDlc() + " response " + response); + } + } else { + Logger.error("Unexpected message " + systemStatusmessage); + } + return measurement; + } + + private static Double calculateDisplayValue(Integer measuredValue, MeasuringChannel channel) { + Double startVal = channel.getStartValue(); + Double endVal = channel.getEndValue(); + Integer rangeMax = channel.getRangeMax(); + //Logger.trace("Ch: "+channel); + + if (startVal != null && endVal != null && rangeMax != null) { + //Logger.trace("endVal: "+endVal+" startVal: "+startVal+" rangeMax: "+rangeMax+" measuredValue: "+measuredValue); + + Double displayValue = ((endVal - startVal) / rangeMax * measuredValue) + startVal; + return round(displayValue, getDigits(channel.getName())); + } + return null; + } + + private static Double round(Double value, int digits) { + if (digits < 0) { + throw new IllegalArgumentException(); + } + + BigDecimal bd = new BigDecimal(Double.toString(value)); + bd = bd.setScale(digits, RoundingMode.HALF_UP); + return bd.doubleValue(); + } + + private static int getDigits(String channelName) { + + return switch (channelName) { + case "MAIN" -> + 3; + case "PROG" -> + 3; + case "VOLT" -> + 1; + case "TEMP" -> + 1; + default -> + 0; + }; + } + +} diff --git a/src/main/java/jcs/commandStation/virtual/VirtualCommandStationImpl.java b/src/main/java/jcs/commandStation/virtual/VirtualCommandStationImpl.java index 52c0eaed..5666cfb9 100644 --- a/src/main/java/jcs/commandStation/virtual/VirtualCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/virtual/VirtualCommandStationImpl.java @@ -17,7 +17,6 @@ import jcs.commandStation.autopilot.DriveSimulator; import java.awt.Image; -import java.util.ArrayList; import java.util.List; import java.util.Map; import jcs.JCS; @@ -41,12 +40,10 @@ import jcs.entities.AccessoryBean; import jcs.entities.ChannelBean; import jcs.entities.CommandStationBean; -import jcs.commandStation.entities.DeviceBean; import jcs.entities.FeedbackModuleBean; import jcs.commandStation.entities.InfoBean; import jcs.entities.LocomotiveBean; import jcs.util.NetworkUtil; -import jcs.util.VersionInfo; import org.tinylog.Logger; /** @@ -55,7 +52,7 @@ */ public class VirtualCommandStationImpl extends AbstractController implements DecoderController, AccessoryController, FeedbackController { - private DeviceBean mainDevice; + //private DeviceBean mainDevice; private InfoBean infoBean; private DriveSimulator simulator; @@ -82,13 +79,13 @@ private void autoConnect() { public synchronized boolean connect() { this.connected = true; - mainDevice = new DeviceBean(); - mainDevice.setArticleNumber("JCS Virtual CS"); - mainDevice.setVersion(VersionInfo.getVersion()); - - mainDevice.setSerial("1"); - mainDevice.setIdentifier(this.commandStationBean.getId()); - mainDevice.setName(this.commandStationBean.getDescription()); +// mainDevice = new DeviceBean(); +// mainDevice.setArticleNumber("JCS Virtual CS"); +// mainDevice.setVersion(VersionInfo.getVersion()); +// +// mainDevice.setSerial("1"); +// mainDevice.setIdentifier(this.commandStationBean.getId()); +// mainDevice.setName(this.commandStationBean.getDescription()); infoBean = new InfoBean(); infoBean.setProductName(commandStationBean.getDescription()); @@ -104,7 +101,7 @@ public synchronized boolean connect() { public void disconnect() { this.connected = false; this.infoBean = null; - this.mainDevice = null; + //this.mainDevice = null; } @Override @@ -117,19 +114,19 @@ public InfoBean getCommandStationInfo() { return this.infoBean; } - @Override - public DeviceBean getDevice() { - return this.mainDevice; - } +// @Override +// public DeviceBean getDevice() { +// return this.mainDevice; +// } - @Override - public List getDevices() { - List devices = new ArrayList<>(); - if (mainDevice != null) { - devices.add(this.mainDevice); - } - return devices; - } +// @Override +// public List getDevices() { +// List devices = new ArrayList<>(); +// if (mainDevice != null) { +// devices.add(this.mainDevice); +// } +// return devices; +// } @Override public String getIp() { @@ -318,10 +315,10 @@ public List getAccessories() { throw new UnsupportedOperationException("Not supported yet."); } - @Override - public DeviceBean getFeedbackDevice() { - throw new UnsupportedOperationException("Not supported yet."); - } +// @Override +// public DeviceBean getFeedbackDevice() { +// throw new UnsupportedOperationException("Not supported yet."); +// } @Override public List getFeedbackModules() { diff --git a/src/main/java/jcs/ui/settings/CommandStationPanel.java b/src/main/java/jcs/ui/settings/CommandStationPanel.java index 4f07ae34..02f9ced1 100644 --- a/src/main/java/jcs/ui/settings/CommandStationPanel.java +++ b/src/main/java/jcs/ui/settings/CommandStationPanel.java @@ -56,7 +56,7 @@ import jcs.entities.CommandStationBean; import jcs.entities.CommandStationBean.ConnectionType; import jcs.entities.CommandStationBean.Protocol; -import jcs.commandStation.entities.DeviceBean; +import jcs.entities.FeedbackModuleBean; import jcs.persistence.PersistenceFactory; import jcs.ui.swing.layout.VerticalFlowLayout; import jcs.util.Ping; @@ -1483,35 +1483,38 @@ public Void doInBackground() { if (canConnect) { //Let obtain some data fail safe try { - String sn = commandStation.getDevice().getSerial(); + String sn = commandStation.getCommandStationInfo().getSerialNumber(); firePropertyChange("serial", "", sn); setProgress(50); if (commandStation instanceof FeedbackController feedbackController) { - DeviceBean fbDevice = feedbackController.getFeedbackDevice(); - if (fbDevice != null) { - Logger.trace(fbDevice.getName() + " Supports Feedback"); - String id = fbDevice.getIdentifier(); - - int node = Integer.parseInt(id.replace("0x", ""), 16); - firePropertyChange("node", selectedCommandStation.getFeedbackModuleIdentifier(), node); - - Integer channelCount = fbDevice.getSensorBuses().size(); - firePropertyChange("channels", selectedCommandStation.getFeedbackChannelCount(), channelCount); - - Integer bus0 = fbDevice.getBusLength(0); - firePropertyChange("bus0", selectedCommandStation.getFeedbackBus0ModuleCount(), bus0); - - Integer bus1 = fbDevice.getBusLength(1); - firePropertyChange("bus1", selectedCommandStation.getFeedbackBus1ModuleCount(), bus1); - - Integer bus2 = fbDevice.getBusLength(2); - firePropertyChange("bus2", selectedCommandStation.getFeedbackBus2ModuleCount(), bus2); - - Integer bus3 = fbDevice.getBusLength(3); - firePropertyChange("bus3", selectedCommandStation.getFeedbackBus3ModuleCount(), bus3); - - Logger.trace("ID: " + id + " Node: " + node + " Bus 0: " + bus0 + " Bus 1: " + bus1 + " Bus 2: " + bus2 + " Bus 3: " + bus3); + //DeviceBean fbDevice = feedbackController.getFeedbackDevice(); + + List feedbackModules = feedbackController.getFeedbackModules(); + + if (!feedbackModules.isEmpty()) { + Logger.trace(feedbackController.getCommandStationInfo().getProductName() + " Supports Feedback"); + //String id = fbDevice.getIdentifier(); + +// int node = Integer.parseInt(id.replace("0x", ""), 16); +// firePropertyChange("node", selectedCommandStation.getFeedbackModuleIdentifier(), node); +// +// Integer channelCount = fbDevice.getSensorBuses().size(); +// firePropertyChange("channels", selectedCommandStation.getFeedbackChannelCount(), channelCount); +// +// Integer bus0 = fbDevice.getBusLength(0); +// firePropertyChange("bus0", selectedCommandStation.getFeedbackBus0ModuleCount(), bus0); +// +// Integer bus1 = fbDevice.getBusLength(1); +// firePropertyChange("bus1", selectedCommandStation.getFeedbackBus1ModuleCount(), bus1); +// +// Integer bus2 = fbDevice.getBusLength(2); +// firePropertyChange("bus2", selectedCommandStation.getFeedbackBus2ModuleCount(), bus2); +// +// Integer bus3 = fbDevice.getBusLength(3); +// firePropertyChange("bus3", selectedCommandStation.getFeedbackBus3ModuleCount(), bus3); +// +// Logger.trace("ID: " + id + " Node: " + node + " Bus 0: " + bus0 + " Bus 1: " + bus1 + " Bus 2: " + bus2 + " Bus 3: " + bus3); } } } catch (RuntimeException e) { diff --git a/src/test/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImplTest.java b/src/test/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImplTest.java index 5060aa8c..1e4bb0d8 100644 --- a/src/test/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImplTest.java +++ b/src/test/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImplTest.java @@ -148,46 +148,46 @@ public void testGetCommandStationInfo() { /** * Test of getDevice method, of class EsuEcosCommandStationImpl. */ - @Test - public void testGetDevice() { - if (!skip) { - - System.out.println("getDevice"); - EsuEcosCommandStationImpl instance = new EsuEcosCommandStationImpl(commandStationBean); - instance.connect(); - DeviceBean expResult = new DeviceBean(); - expResult.setName("ECoS-Virtual"); - expResult.setVersion("1.3"); - expResult.setTypeName("ECoS"); - expResult.setSerial("0x00000000"); - - DeviceBean result = instance.getDevice(); - assertEquals(expResult, result); - } - } +// @Test +// public void testGetDevice() { +// if (!skip) { +// +// System.out.println("getDevice"); +// EsuEcosCommandStationImpl instance = new EsuEcosCommandStationImpl(commandStationBean); +// instance.connect(); +// DeviceBean expResult = new DeviceBean(); +// expResult.setName("ECoS-Virtual"); +// expResult.setVersion("1.3"); +// expResult.setTypeName("ECoS"); +// expResult.setSerial("0x00000000"); +// +// DeviceBean result = instance.getDevice(); +// assertEquals(expResult, result); +// } +// } /** * Test of getDevices method, of class EsuEcosCommandStationImpl. */ - @Test - public void testGetDevices() { - if (!skip) { - System.out.println("getDevices"); - EsuEcosCommandStationImpl instance = new EsuEcosCommandStationImpl(commandStationBean); - instance.connect(); - DeviceBean db = new DeviceBean(); - db.setName("ECoS-Virtual"); - db.setVersion("1.3"); - db.setTypeName("ECoS"); - db.setSerial("0x00000000"); - - List expResult = new ArrayList<>(); - expResult.add(db); - - List result = instance.getDevices(); - assertEquals(expResult, result); - } - } +// @Test +// public void testGetDevices() { +// if (!skip) { +// System.out.println("getDevices"); +// EsuEcosCommandStationImpl instance = new EsuEcosCommandStationImpl(commandStationBean); +// instance.connect(); +// DeviceBean db = new DeviceBean(); +// db.setName("ECoS-Virtual"); +// db.setVersion("1.3"); +// db.setTypeName("ECoS"); +// db.setSerial("0x00000000"); +// +// List expResult = new ArrayList<>(); +// expResult.add(db); +// +// List result = instance.getDevices(); +// assertEquals(expResult, result); +// } +// } /** * Test of getIp method, of class EsuEcosCommandStationImpl. @@ -388,31 +388,31 @@ public void testGetAccessories() { /** * Test of getFeedbackDevice method, of class EsuEcosCommandStationImpl. */ - @Test - public void testGetFeedbackDevice() { - if (!skip) { - System.out.println("getFeedbackDevice"); - EsuEcosCommandStationImpl instance = new EsuEcosCommandStationImpl(commandStationBean); - instance.connect(); - - DeviceBean expResult = new DeviceBean(); - expResult.setArticleNumber("ECoS-Virtual"); - expResult.setIdentifier("0x0"); - expResult.getBusLength(1); - expResult.setVersion("4.2.13"); - expResult.setSerial("0x00000000"); - expResult.setTypeName("Link S88"); - - ChannelBean cb = new ChannelBean(); - cb.setName(DeviceBean.BUS0); - cb.setNumber(0); - - expResult.addSensorBus(0, cb); - - DeviceBean result = instance.getFeedbackDevice(); - assertEquals(expResult, result); - } - } +// @Test +// public void testGetFeedbackDevice() { +// if (!skip) { +// System.out.println("getFeedbackDevice"); +// EsuEcosCommandStationImpl instance = new EsuEcosCommandStationImpl(commandStationBean); +// instance.connect(); +// +// DeviceBean expResult = new DeviceBean(); +// expResult.setArticleNumber("ECoS-Virtual"); +// expResult.setIdentifier("0x0"); +// expResult.getBusLength(1); +// expResult.setVersion("4.2.13"); +// expResult.setSerial("0x00000000"); +// expResult.setTypeName("Link S88"); +// +// ChannelBean cb = new ChannelBean(); +// cb.setName(DeviceBean.BUS0); +// cb.setNumber(0); +// +// expResult.addSensorBus(0, cb); +// +// DeviceBean result = instance.getFeedbackDevice(); +// assertEquals(expResult, result); +// } +// } /** * Test of getFeedbackModules method, of class EsuEcosCommandStationImpl. diff --git a/src/test/java/jcs/commandStation/marklin/cs/MarklinCSTest.java b/src/test/java/jcs/commandStation/marklin/cs/MarklinCSTest.java index 6a659f55..0b603de2 100644 --- a/src/test/java/jcs/commandStation/marklin/cs/MarklinCSTest.java +++ b/src/test/java/jcs/commandStation/marklin/cs/MarklinCSTest.java @@ -63,7 +63,7 @@ public MarklinCSTest() { instance = new MarklinCentralStationImpl(csb, false); pause(200); - csAvailable = instance.connect(); + csAvailable = false; //instance.connect(); if (csAvailable) { instance.disconnect(); diff --git a/src/test/java/jcs/commandStation/marklin/cs/can/parser/CanDevicesTest.java b/src/test/java/jcs/commandStation/marklin/cs/can/parser/CanDevicesTest.java index 1843c952438036cce45cad49358adc4160228565..340aaf94ad77481f92d72f2de229977663b6ddb9 100644 GIT binary patch delta 713 zcmcJNyGjE=6owlSvf!QAXfebl;;Px~CRr~lNK_EiLah`b8#tQ_q_9Y#Q=a+%|NMNM=kSHSzfQ%)Iv?yA`2dupB8SJ+1X4c0>BL+q5^f@+P_mE=a^Y zYfUd47E$3fEw4OeqfOS^lqhSFZY+8^Nere64t4#(*B%I;lRKGY?h;0L1M;tj_=56|XRm#g2=wyqH2z-jRYClg)+|d6Vozd!r_n|lgkr$GgDc88 zviOdN!!8O^Gl0_}l6LFp*npr%8IsC|0X?7j;!q%RQr{}%88YUNiCwQ2MhE-Ew(Esz z(+R0<+XmdC@QKO@%00|C97p+6osY!C*>nphTlrAgitDO&AgPe2l!ZvDrqam!xpGX$ zfKYu8nQ7fO6()2;31b?3$NZ5p{vXUwTwf`zzhElLWUsW6Hr7|?(reJQ#CI>#X63c? E21?|_?*IS* diff --git a/src/test/java/jcs/commandStation/marklin/parser/SystemStatusMessageTest.java b/src/test/java/jcs/commandStation/marklin/parser/SystemStatusMessageTest.java new file mode 100644 index 00000000..a84a5d67 --- /dev/null +++ b/src/test/java/jcs/commandStation/marklin/parser/SystemStatusMessageTest.java @@ -0,0 +1,78 @@ +/* + * Copyright 2025 frans. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.commandStation.marklin.parser; + +import jcs.commandStation.entities.MeasurementBean; +import jcs.commandStation.marklin.cs.can.CanMessage; +import jcs.commandStation.marklin.cs.can.device.MeasuringChannel; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +/** + * + * @author frans + */ +public class SystemStatusMessageTest { + + public SystemStatusMessageTest() { + } + + @BeforeEach + public void setUp() { + } + + @AfterEach + public void tearDown() { + } + + //Example + //0x00 0x00 0x47 0x11 0x06 0x43 0x53 0x32 0x08 0x0B 0x01 0x00 0x00 + //Abfrage des Messwertes Kanalnummer 1 +//00014711 8 43 53 32 08 0B 01 00 03 + + private CanMessage getSystemStatusMessageIndex1() { + CanMessage sysStat = CanMessage.parse("0x00 0x3a 0x37 0x7f 0x05 0x63 0x73 0x45 0x8c 0x01 0x00 0x00 0x00"); + sysStat.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x01 0x08 0x01 0xfd 0x30 0xf0 0xe0 0xc0 0x00 0x00")); + sysStat.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x02 0x08 0x02 0x28 0x02 0x40 0x02 0x58 0x02 0x94")); + sysStat.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x03 0x08 0x4d 0x41 0x49 0x4e 0x00 0x30 0x2e 0x30")); + sysStat.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x04 0x08 0x30 0x00 0x35 0x2e 0x35 0x30 0x00 0x41")); + sysStat.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x05 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00")); + sysStat.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x26 0x06 0x63 0x73 0x45 0x8c 0x01 0x05 0x00 0x00")); + + return sysStat; + +// TRACE 2025-05-03 23:04:11.593 [main] CSTCPConnection.sendCanMessage(): #TX: 0x00 0x3a 0x37 0x7f 0x05 0x63 0x73 0x45 0x8c 0x01 0x00 0x00 0x00 +//TRACE 2025-05-03 23:04:11.593 [main] CSTCPConnection.sendCanMessage(): #RX 0: 0x00 0x3b 0x03 0x01 0x08 0x01 0xfd 0x30 0xf0 0xe0 0xc0 0x00 0x00 +//TRACE 2025-05-03 23:04:11.593 [main] CSTCPConnection.sendCanMessage(): #RX 1: 0x00 0x3b 0x03 0x02 0x08 0x02 0x28 0x02 0x40 0x02 0x58 0x02 0x94 +//TRACE 2025-05-03 23:04:11.593 [main] CSTCPConnection.sendCanMessage(): #RX 2: 0x00 0x3b 0x03 0x03 0x08 0x4d 0x41 0x49 0x4e 0x00 0x30 0x2e 0x30 +//TRACE 2025-05-03 23:04:11.593 [main] CSTCPConnection.sendCanMessage(): #RX 3: 0x00 0x3b 0x03 0x04 0x08 0x30 0x00 0x35 0x2e 0x35 0x30 0x00 0x41 +//TRACE 2025-05-03 23:04:11.593 [main] CSTCPConnection.sendCanMessage(): #RX 4: 0x00 0x3b 0x03 0x05 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 +//TRACE 2025-05-03 23:04:11.593 [main] CSTCPConnection.sendCanMessage(): #RX 5: 0x00 0x3b 0x03 0x26 0x06 0x63 0x73 0x45 0x8c 0x01 0x05 0x00 0x00 + } + + @Test + public void testParse() { + System.out.println("parse"); + MeasuringChannel channel = null; + CanMessage systemStatusmessage = null; + MeasurementBean expResult = null; + MeasurementBean result = SystemStatusMessage.parse(channel, systemStatusmessage); + assertEquals(expResult, result); + fail("The test case is a prototype."); + } +} From f53f0b2630019700029c3a0cd7c21cfca450dcff Mon Sep 17 00:00:00 2001 From: Frans Jacobs <41232225+fransjacobs@users.noreply.github.com> Date: Sun, 4 May 2025 17:03:46 +0200 Subject: [PATCH 49/70] More refactoring on Measurement and connections. Test disabled due to yet unknown issues with maven build --- pom.xml | 3 +- src/main/java/jcs/JCS.java | 7 +- .../commandStation/AbstractController.java | 27 +++- .../jcs/commandStation/DecoderController.java | 8 +- .../jcs/commandStation/GenericController.java | 10 +- .../jcs/commandStation/JCSCommandStation.java | 4 +- .../commandStation/JCSCommandStationImpl.java | 126 ++++++++------- .../dccex/DccExCommandStationImpl.java | 13 +- .../connection/DccExMessageListener.java | 4 +- .../connection/DccExSerialConnection.java | 4 +- .../dccex/connection/DccExTCPConnection.java | 6 +- .../entities/MeasurementBean.java | 2 +- .../esu/ecos/net/EcosMessageListener.java | 4 +- .../esu/ecos/net/EcosTCPConnection.java | 6 +- ...nectionEvent.java => ConnectionEvent.java} | 13 +- ...ener.java => ConnectionEventListener.java} | 4 +- .../events/MeasurementEvent.java | 33 ++-- .../events/MeasurementEventListener.java | 2 +- .../jcs/commandStation/hsis88/HSIImpl.java | 12 +- .../hsis88/HSIMessageListener.java | 4 +- .../hsis88/HSISerialConnection.java | 4 +- .../marklin/cs/MarklinCentralStationImpl.java | 91 +++++++++-- .../marklin/cs/net/CSConnection.java | 4 +- .../marklin/cs/net/CSTCPConnection.java | 14 +- .../marklin/cs/net/CSVirtualConnection.java | 18 +-- .../marklin/parser/SystemStatusMessage.java | 6 +- src/main/java/jcs/ui/JCSFrame.java | 22 ++- src/main/java/jcs/ui/StatusPanel.java | 24 +-- .../parser/SystemStatusMessageTest.java | 153 ++++++++++++++---- .../persistence/PersistenceServiceTest.java | 137 ++++++++++------ src/test/resources/jcs-test-data-h2.sql | 11 +- 31 files changed, 505 insertions(+), 271 deletions(-) rename src/main/java/jcs/commandStation/events/{DisconnectionEvent.java => ConnectionEvent.java} (74%) rename src/main/java/jcs/commandStation/events/{DisconnectionEventListener.java => ConnectionEventListener.java} (87%) diff --git a/pom.xml b/pom.xml index 03447ce4..87a25e6f 100644 --- a/pom.xml +++ b/pom.xml @@ -22,6 +22,7 @@ jar jcs.JCS 21 + true
@@ -294,7 +295,7 @@ maven-surefire-plugin 3.5.2 - false + true -Dfile.encoding=UTF-8 junit.jupiter.execution.parallel.enabled=false diff --git a/src/main/java/jcs/JCS.java b/src/main/java/jcs/JCS.java index d001ca1a..2b324140 100755 --- a/src/main/java/jcs/JCS.java +++ b/src/main/java/jcs/JCS.java @@ -31,8 +31,6 @@ import java.io.File; import java.io.IOException; import java.net.URL; -import java.util.ArrayList; -import java.util.List; import javax.imageio.ImageIO; import javax.swing.ImageIcon; import javax.swing.JOptionPane; @@ -42,7 +40,6 @@ import jcs.commandStation.JCSCommandStationImpl; import jcs.commandStation.events.PowerEvent; import jcs.commandStation.events.PowerEventListener; -import jcs.commandStation.events.RefreshEventListener; import jcs.persistence.PersistenceFactory; import jcs.persistence.PersistenceService; import jcs.persistence.util.H2DatabaseUtil; @@ -72,10 +69,10 @@ public class JCS extends Thread { private static UICallback uiCallback; - private final List refreshEventListeners; + //private final List refreshEventListeners; private JCS() { - refreshEventListeners = new ArrayList<>(); + //refreshEventListeners = new ArrayList<>(); } public static void logProgress(String message) { diff --git a/src/main/java/jcs/commandStation/AbstractController.java b/src/main/java/jcs/commandStation/AbstractController.java index 03ed9600..0c2777c3 100644 --- a/src/main/java/jcs/commandStation/AbstractController.java +++ b/src/main/java/jcs/commandStation/AbstractController.java @@ -20,7 +20,6 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import jcs.commandStation.events.AccessoryEventListener; -import jcs.commandStation.events.DisconnectionEventListener; import jcs.commandStation.events.LocomotiveDirectionEventListener; import jcs.commandStation.events.LocomotiveFunctionEventListener; import jcs.commandStation.events.LocomotiveSpeedEventListener; @@ -28,6 +27,8 @@ import jcs.commandStation.events.SensorEventListener; import jcs.entities.CommandStationBean; import org.tinylog.Logger; +import jcs.commandStation.events.ConnectionEventListener; +import jcs.commandStation.events.MeasurementEventListener; public abstract class AbstractController implements GenericController { @@ -42,7 +43,9 @@ public abstract class AbstractController implements GenericController { protected final List locomotiveDirectionEventListeners; protected final List locomotiveSpeedEventListeners; - protected final List disconnectionEventListeners; + protected final List connectionEventListeners; + + private final List measurementEventListeners; protected ExecutorService executor; @@ -70,7 +73,9 @@ public AbstractController(boolean autoConnect, CommandStationBean commandStation locomotiveDirectionEventListeners = new LinkedList<>(); locomotiveSpeedEventListeners = new LinkedList<>(); - disconnectionEventListeners = new LinkedList<>(); + connectionEventListeners = new LinkedList<>(); + + measurementEventListeners = new LinkedList<>(); if (this.commandStationBean != null) { this.virtual = commandStationBean.isVirtual(); @@ -101,13 +106,13 @@ public boolean isVirtual() { } @Override - public void addDisconnectionEventListener(DisconnectionEventListener listener) { - this.disconnectionEventListeners.add(listener); + public void addConnectionEventListener(ConnectionEventListener listener) { + this.connectionEventListeners.add(listener); } @Override - public void removeDisconnectionEventListener(DisconnectionEventListener listener) { - this.disconnectionEventListeners.remove(listener); + public void removeConnectionEventListener(ConnectionEventListener listener) { + this.connectionEventListeners.remove(listener); } public boolean isPower() { @@ -162,6 +167,14 @@ public void removeLocomotiveSpeedEventListener(LocomotiveSpeedEventListener list this.locomotiveSpeedEventListeners.remove(listener); } + public void addMeasurementEventListener(MeasurementEventListener listener) { + this.measurementEventListeners.add(listener); + } + + public void removeMeasurementEventListener(MeasurementEventListener listener) { + this.measurementEventListeners.remove(listener); + } + protected void pause(long millis) { try { Thread.sleep(millis); diff --git a/src/main/java/jcs/commandStation/DecoderController.java b/src/main/java/jcs/commandStation/DecoderController.java index 9b914e49..4ed96e7d 100644 --- a/src/main/java/jcs/commandStation/DecoderController.java +++ b/src/main/java/jcs/commandStation/DecoderController.java @@ -21,6 +21,7 @@ import jcs.commandStation.events.LocomotiveDirectionEventListener; import jcs.commandStation.events.LocomotiveFunctionEventListener; import jcs.commandStation.events.LocomotiveSpeedEventListener; +import jcs.commandStation.events.MeasurementEventListener; import jcs.commandStation.events.PowerEventListener; import jcs.entities.ChannelBean; import jcs.entities.LocomotiveBean; @@ -54,8 +55,6 @@ public interface DecoderController extends GenericController { void removeLocomotiveSpeedEventListener(LocomotiveSpeedEventListener listener); - //List getLocomotiveSpeedEventListeners(); - List getLocomotives(); Image getLocomotiveImage(String icon); @@ -65,4 +64,9 @@ public interface DecoderController extends GenericController { boolean isSupportTrackMeasurements(); Map getTrackMeasurements(); + + void addMeasurementEventListener(MeasurementEventListener listener); + + void removeMeasurementEventListener(MeasurementEventListener listener); + } diff --git a/src/main/java/jcs/commandStation/GenericController.java b/src/main/java/jcs/commandStation/GenericController.java index 523ccc68..66a1485f 100755 --- a/src/main/java/jcs/commandStation/GenericController.java +++ b/src/main/java/jcs/commandStation/GenericController.java @@ -15,9 +15,9 @@ */ package jcs.commandStation; -import jcs.commandStation.events.DisconnectionEventListener; import jcs.entities.CommandStationBean; import jcs.commandStation.entities.InfoBean; +import jcs.commandStation.events.ConnectionEventListener; public interface GenericController { @@ -33,16 +33,12 @@ public interface GenericController { boolean isVirtual(); - void addDisconnectionEventListener(DisconnectionEventListener listener); + void addConnectionEventListener(ConnectionEventListener listener); - void removeDisconnectionEventListener(DisconnectionEventListener listener); + void removeConnectionEventListener(ConnectionEventListener listener); InfoBean getCommandStationInfo(); - //DeviceBean getDevice(); - - //List getDevices(); - String getIp(); } diff --git a/src/main/java/jcs/commandStation/JCSCommandStation.java b/src/main/java/jcs/commandStation/JCSCommandStation.java index 75babf65..124ac5df 100755 --- a/src/main/java/jcs/commandStation/JCSCommandStation.java +++ b/src/main/java/jcs/commandStation/JCSCommandStation.java @@ -18,7 +18,6 @@ import java.awt.Image; import java.util.List; import jcs.commandStation.events.AccessoryEventListener; -import jcs.commandStation.events.DisconnectionEventListener; import jcs.commandStation.events.LocomotiveDirectionEventListener; import jcs.commandStation.events.LocomotiveFunctionEventListener; import jcs.commandStation.events.LocomotiveSpeedEventListener; @@ -30,6 +29,7 @@ import jcs.entities.CommandStationBean; import jcs.commandStation.entities.InfoBean; import jcs.entities.LocomotiveBean; +import jcs.commandStation.events.ConnectionEventListener; /** * The Track repository contain all track item which are used on the Track This can be Locomotives, Turnouts, Signals, etc There For future use the implementation of the Repository could be changed to @@ -53,7 +53,7 @@ public interface JCSCommandStation { boolean isVirtual(); - void addDisconnectionEventListener(DisconnectionEventListener listener); + void addDisconnectionEventListener(ConnectionEventListener listener); void addPowerEventListener(PowerEventListener listener); diff --git a/src/main/java/jcs/commandStation/JCSCommandStationImpl.java b/src/main/java/jcs/commandStation/JCSCommandStationImpl.java index 9176c6bf..9c5f8c68 100755 --- a/src/main/java/jcs/commandStation/JCSCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/JCSCommandStationImpl.java @@ -38,8 +38,7 @@ import javax.imageio.ImageIO; import jcs.commandStation.events.AccessoryEvent; import jcs.commandStation.events.AccessoryEventListener; -import jcs.commandStation.events.DisconnectionEvent; -import jcs.commandStation.events.DisconnectionEventListener; +import jcs.commandStation.events.ConnectionEvent; import jcs.commandStation.events.LocomotiveDirectionEvent; import jcs.commandStation.events.LocomotiveDirectionEventListener; import jcs.commandStation.events.LocomotiveFunctionEvent; @@ -64,6 +63,7 @@ import jcs.entities.SensorBean; import jcs.persistence.PersistenceFactory; import org.tinylog.Logger; +import jcs.commandStation.events.ConnectionEventListener; /** * The JCSCommandStation is the layer between the UI, engines and Command stations @@ -82,8 +82,7 @@ public class JCSCommandStationImpl implements JCSCommandStation { private final List locomotiveDirectionEventListeners; private final List locomotiveSpeedEventListeners; - private final List measurementEventListeners; - + //private final List measurementEventListeners; private final Set supportedProtocols; private CommandStationBean commandStation; @@ -110,7 +109,7 @@ private JCSCommandStationImpl(boolean autoConnectController) { locomotiveFunctionEventListeners = new LinkedList<>(); locomotiveDirectionEventListeners = new LinkedList<>(); locomotiveSpeedEventListeners = new LinkedList<>(); - measurementEventListeners = new LinkedList<>(); + //measurementEventListeners = new LinkedList<>(); supportedProtocols = new HashSet<>(); try { @@ -224,7 +223,7 @@ public final boolean connect() { Logger.trace("Connected Controllers: Decoder: " + (decoderControllerConnected ? "Yes" : "No") + " Accessory: " + accessoryCntrConnected + " Feedback: " + feedbackCntrConnected); if (decoderControllerConnected && !allreadyConnected && decoderController != null) { - decoderController.addDisconnectionEventListener(new DisconnectionListener(this)); + decoderController.addConnectionEventListener(new DisconnectionListener(this)); decoderController.addLocomotiveFunctionEventListener(new LocomotiveFunctionChangeEventListener(this)); decoderController.addLocomotiveDirectionEventListener(new LocomotiveDirectionChangeEventListener(this)); @@ -232,29 +231,29 @@ public final boolean connect() { supportedProtocols.addAll(decoderController.getCommandStationBean().getSupportedProtocols()); - if (decoderController.isSupportTrackMeasurements()) { - //Start the measurements background task - long measureInterval = Long.parseLong(System.getProperty("track.measurements.interval", "5")); - measureInterval = measureInterval * 1000; - - if (measureInterval > 0) { - TrackMeasurementTask measurementTask = new TrackMeasurementTask(this); - Timer timer = new Timer("Timer"); - timer.schedule(measurementTask, 0, measureInterval); - Logger.debug("Started Track measurements with an interval of " + measureInterval + "s"); - } else { - Logger.debug("Skipping Track measurements"); - } - } else { - Logger.debug("Track measurements are not supported"); - } +// if (decoderController.isSupportTrackMeasurements()) { +// //Start the measurements background task +// long measureInterval = Long.parseLong(System.getProperty("track.measurements.interval", "5")); +// measureInterval = measureInterval * 1000; +// +// if (measureInterval > 0) { +// TrackMeasurementTask measurementTask = new TrackMeasurementTask(this); +// Timer timer = new Timer("Timer"); +// timer.schedule(measurementTask, 0, measureInterval); +// Logger.debug("Started Track measurements with an interval of " + measureInterval + "s"); +// } else { +// Logger.debug("Skipping Track measurements"); +// } +// } else { +// Logger.debug("Track measurements are not supported"); +// } } if (accessoryCntrConnected > 0 && !allreadyConnected) { for (AccessoryController ac : accessoryControllers.values()) { if (ac.isConnected()) { ac.addAccessoryEventListener(new AccessoryChangeEventListener(this)); - ac.addDisconnectionEventListener(new DisconnectionListener(this)); + ac.addConnectionEventListener(new DisconnectionListener(this)); } } } @@ -263,7 +262,7 @@ public final boolean connect() { for (FeedbackController fc : feedbackControllers.values()) { if (fc.isConnected()) { fc.addSensorEventListener(new SensorChangeEventListener(this)); - fc.addDisconnectionEventListener(new DisconnectionListener(this)); + fc.addConnectionEventListener(new DisconnectionListener(this)); } } } @@ -624,19 +623,19 @@ public void removeLocomotiveSpeedEventListener(LocomotiveSpeedEventListener list } @Override - public void addDisconnectionEventListener(DisconnectionEventListener listener) { + public void addDisconnectionEventListener(ConnectionEventListener listener) { if (decoderController != null) { - decoderController.addDisconnectionEventListener(listener); + decoderController.addConnectionEventListener(listener); } for (AccessoryController ac : accessoryControllers.values()) { if (ac != decoderController) { - ac.addDisconnectionEventListener(listener); + ac.addConnectionEventListener(listener); } } for (FeedbackController fc : feedbackControllers.values()) { if (fc != decoderController) { - fc.addDisconnectionEventListener(listener); + fc.addConnectionEventListener(listener); } } } @@ -657,12 +656,16 @@ public void removePowerEventListener(PowerEventListener listener) { @Override public void addMeasurementEventListener(MeasurementEventListener listener) { - measurementEventListeners.add(listener); + if (decoderController != null && decoderController.isSupportTrackMeasurements()) { + decoderController.addMeasurementEventListener(listener); + } } @Override public void removeMeasurementListener(MeasurementEventListener listener) { - measurementEventListeners.remove(listener); + if (decoderController != null && decoderController.isSupportTrackMeasurements()) { + decoderController.removeMeasurementEventListener(listener); + } } @Override @@ -680,36 +683,35 @@ public List getFeedbackControllers() { return feedbackControllers.values().stream().collect(Collectors.toList()); } - private class TrackMeasurementTask extends TimerTask { - - private final JCSCommandStationImpl Controller; - private boolean debuglog = false; - - TrackMeasurementTask(JCSCommandStationImpl Controller) { - this.Controller = Controller; - this.debuglog = System.getProperty("debug.measurements", "false").equalsIgnoreCase("true"); - } - - @Override - public void run() { - if (this.Controller != null && this.Controller.decoderController != null) { - Map measurements = this.Controller.decoderController.getTrackMeasurements(); - for (ChannelBean ch : measurements.values()) { - - if (ch != null && ch.isChanged()) { - MeasurementEvent me = new MeasurementEvent(ch); - if (debuglog) { - Logger.trace("Changed Channel " + ch.getNumber() + ", " + ch.getName() + ": " + ch.getHumanValue() + " " + ch.getUnit()); - } - for (MeasurementEventListener mel : this.Controller.measurementEventListeners) { - mel.onMeasurement(me); - } - } - } - } - } - } - +// private class TrackMeasurementTask extends TimerTask { +// +// private final JCSCommandStationImpl Controller; +// private boolean debuglog = false; +// +// TrackMeasurementTask(JCSCommandStationImpl Controller) { +// this.Controller = Controller; +// this.debuglog = System.getProperty("debug.measurements", "false").equalsIgnoreCase("true"); +// } +// +// @Override +// public void run() { +// if (this.Controller != null && this.Controller.decoderController != null) { +// Map measurements = this.Controller.decoderController.getTrackMeasurements(); +// for (ChannelBean ch : measurements.values()) { +// +// if (ch != null && ch.isChanged()) { +// MeasurementEvent me = new MeasurementEvent(ch); +// if (debuglog) { +// Logger.trace("Changed Channel " + ch.getNumber() + ", " + ch.getName() + ": " + ch.getHumanValue() + " " + ch.getUnit()); +// } +// for (MeasurementEventListener mel : this.Controller.measurementEventListeners) { +// mel.onMeasurement(me); +// } +// } +// } +// } +// } +// } private class SensorChangeEventListener implements SensorEventListener { private final JCSCommandStationImpl commandStation; @@ -947,7 +949,7 @@ public void onSpeedChange(LocomotiveSpeedEvent speedEvent) { } } - private class DisconnectionListener implements DisconnectionEventListener { + private class DisconnectionListener implements ConnectionEventListener { private final JCSCommandStationImpl jcsCommandStationImpl; @@ -956,7 +958,7 @@ private class DisconnectionListener implements DisconnectionEventListener { } @Override - public void onDisconnect(DisconnectionEvent event) { + public void onConnectionChange(ConnectionEvent event) { Logger.trace(event.getSource() + " is Disconnected!"); jcsCommandStationImpl.disconnect(); } diff --git a/src/main/java/jcs/commandStation/dccex/DccExCommandStationImpl.java b/src/main/java/jcs/commandStation/dccex/DccExCommandStationImpl.java index baa948aa..3c5d6731 100644 --- a/src/main/java/jcs/commandStation/dccex/DccExCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/dccex/DccExCommandStationImpl.java @@ -16,7 +16,6 @@ package jcs.commandStation.dccex; import java.awt.Image; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -31,8 +30,7 @@ import jcs.commandStation.dccex.events.DccExMeasurementEvent; import jcs.commandStation.events.AccessoryEvent; import jcs.commandStation.events.AccessoryEventListener; -import jcs.commandStation.events.DisconnectionEvent; -import jcs.commandStation.events.DisconnectionEventListener; +import jcs.commandStation.events.ConnectionEvent; import jcs.commandStation.events.LocomotiveDirectionEvent; import jcs.commandStation.events.LocomotiveDirectionEventListener; import jcs.commandStation.events.LocomotiveFunctionEvent; @@ -54,6 +52,7 @@ import jcs.util.KeyValuePair; import jcs.util.SerialPortUtil; import org.tinylog.Logger; +import jcs.commandStation.events.ConnectionEventListener; public class DccExCommandStationImpl extends AbstractController implements DecoderController, AccessoryController { @@ -421,9 +420,9 @@ public Map getTrackMeasurements() { return this.measurementChannels; } - private void fireAllDisconnectionEventListeners(final DisconnectionEvent disconnectionEvent) { - for (DisconnectionEventListener listener : this.disconnectionEventListeners) { - listener.onDisconnect(disconnectionEvent); + private void fireAllDisconnectionEventListeners(final ConnectionEvent disconnectionEvent) { + for (ConnectionEventListener listener : this.connectionEventListeners) { + listener.onConnectionChange(disconnectionEvent); } disconnect(); } @@ -675,7 +674,7 @@ public void onMessage(DccExMessage message) { } @Override - public void onDisconnect(DisconnectionEvent event) { + public void onDisconnect(ConnectionEvent event) { this.commandStation.fireAllDisconnectionEventListeners(event); } diff --git a/src/main/java/jcs/commandStation/dccex/connection/DccExMessageListener.java b/src/main/java/jcs/commandStation/dccex/connection/DccExMessageListener.java index 0604e99d..7f3ad7c9 100644 --- a/src/main/java/jcs/commandStation/dccex/connection/DccExMessageListener.java +++ b/src/main/java/jcs/commandStation/dccex/connection/DccExMessageListener.java @@ -16,7 +16,7 @@ package jcs.commandStation.dccex.connection; import jcs.commandStation.dccex.DccExMessage; -import jcs.commandStation.events.DisconnectionEvent; +import jcs.commandStation.events.ConnectionEvent; /** * @@ -26,6 +26,6 @@ public interface DccExMessageListener { void onMessage(DccExMessage message); - void onDisconnect(DisconnectionEvent event); + void onDisconnect(ConnectionEvent event); } diff --git a/src/main/java/jcs/commandStation/dccex/connection/DccExSerialConnection.java b/src/main/java/jcs/commandStation/dccex/connection/DccExSerialConnection.java index 5421884b..60cc2ca2 100644 --- a/src/main/java/jcs/commandStation/dccex/connection/DccExSerialConnection.java +++ b/src/main/java/jcs/commandStation/dccex/connection/DccExSerialConnection.java @@ -29,7 +29,7 @@ import static jcs.commandStation.dccex.DccExConnection.MESSAGE_DELIMITER; import jcs.commandStation.dccex.DccExMessage; import jcs.commandStation.dccex.DccExMessageFactory; -import jcs.commandStation.events.DisconnectionEvent; +import jcs.commandStation.events.ConnectionEvent; import org.tinylog.Logger; /** @@ -157,7 +157,7 @@ private void disconnected() { Logger.trace("Port " + commPort.getSystemPortName() + " is Disconnected"); String msg = commPort.getDescriptivePortName() + " [" + commPort.getSystemPortName() + "]"; - DisconnectionEvent de = new DisconnectionEvent(msg); + ConnectionEvent de = new ConnectionEvent(msg, false); for (DccExMessageListener listener : dccExListeners) { listener.onDisconnect(de); diff --git a/src/main/java/jcs/commandStation/dccex/connection/DccExTCPConnection.java b/src/main/java/jcs/commandStation/dccex/connection/DccExTCPConnection.java index ab5e2c25..c0fff96c 100644 --- a/src/main/java/jcs/commandStation/dccex/connection/DccExTCPConnection.java +++ b/src/main/java/jcs/commandStation/dccex/connection/DccExTCPConnection.java @@ -27,7 +27,7 @@ import jcs.commandStation.dccex.DccExConnection; import jcs.commandStation.dccex.DccExMessage; import jcs.commandStation.dccex.DccExMessageFactory; -import jcs.commandStation.events.DisconnectionEvent; +import jcs.commandStation.events.ConnectionEvent; import org.tinylog.Logger; /** @@ -126,7 +126,7 @@ public synchronized String sendMessage(String message) { } catch (IOException ex) { Logger.error(ex); String msg = "Host " + dccExAddress.getHostName(); - DisconnectionEvent de = new DisconnectionEvent(msg); + ConnectionEvent de = new ConnectionEvent(msg, false); messageReceiver.messageListener.onDisconnect(de); messageReceiver.quit(); @@ -216,7 +216,7 @@ public void run() { } catch (SocketException se) { Logger.error(se.getMessage()); String msg = "Host " + dccExAddress.getHostName(); - DisconnectionEvent de = new DisconnectionEvent(msg); + ConnectionEvent de = new ConnectionEvent(msg, false); this.messageListener.onDisconnect(de); quit(); } catch (IOException ioe) { diff --git a/src/main/java/jcs/commandStation/entities/MeasurementBean.java b/src/main/java/jcs/commandStation/entities/MeasurementBean.java index 397a306c..722183e4 100644 --- a/src/main/java/jcs/commandStation/entities/MeasurementBean.java +++ b/src/main/java/jcs/commandStation/entities/MeasurementBean.java @@ -121,7 +121,7 @@ public void setDisplayValue(Double displayValue) { @Override public String toString() { StringBuilder sb = new StringBuilder(); - sb.append("CanDevice{"); + sb.append("MeasurementBean{"); if (channelNumber != null) { sb.append("channelNumber=").append(channelNumber); } diff --git a/src/main/java/jcs/commandStation/esu/ecos/net/EcosMessageListener.java b/src/main/java/jcs/commandStation/esu/ecos/net/EcosMessageListener.java index 6abdfe69..61b57712 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/net/EcosMessageListener.java +++ b/src/main/java/jcs/commandStation/esu/ecos/net/EcosMessageListener.java @@ -16,7 +16,7 @@ package jcs.commandStation.esu.ecos.net; import jcs.commandStation.esu.ecos.EcosMessage; -import jcs.commandStation.events.DisconnectionEvent; +import jcs.commandStation.events.ConnectionEvent; /** * @@ -26,6 +26,6 @@ public interface EcosMessageListener { void onMessage(EcosMessage message); - void onDisconnect(DisconnectionEvent event); + void onDisconnect(ConnectionEvent event); } diff --git a/src/main/java/jcs/commandStation/esu/ecos/net/EcosTCPConnection.java b/src/main/java/jcs/commandStation/esu/ecos/net/EcosTCPConnection.java index de735e57..98b6a828 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/net/EcosTCPConnection.java +++ b/src/main/java/jcs/commandStation/esu/ecos/net/EcosTCPConnection.java @@ -28,7 +28,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TransferQueue; import jcs.commandStation.esu.ecos.EcosMessage; -import jcs.commandStation.events.DisconnectionEvent; +import jcs.commandStation.events.ConnectionEvent; import org.tinylog.Logger; /** @@ -144,7 +144,7 @@ public synchronized EcosMessage sendMessage(EcosMessage message) { } catch (IOException | InterruptedException ex) { Logger.error(ex); String msg = "Host " + ecosAddress.getHostName(); - DisconnectionEvent de = new DisconnectionEvent(msg); + ConnectionEvent de = new ConnectionEvent(msg,false); messageReceiver.messageListener.onDisconnect(de); messageReceiver.quit(); @@ -266,7 +266,7 @@ public void run() { } catch (SocketException se) { Logger.error(se.getMessage()); String msg = "Host " + ecosAddress.getHostName(); - DisconnectionEvent de = new DisconnectionEvent(msg); + ConnectionEvent de = new ConnectionEvent(msg, false); this.messageListener.onDisconnect(de); quit(); } catch (IOException | InterruptedException ex) { diff --git a/src/main/java/jcs/commandStation/events/DisconnectionEvent.java b/src/main/java/jcs/commandStation/events/ConnectionEvent.java similarity index 74% rename from src/main/java/jcs/commandStation/events/DisconnectionEvent.java rename to src/main/java/jcs/commandStation/events/ConnectionEvent.java index 3b3645bc..0c1994c1 100644 --- a/src/main/java/jcs/commandStation/events/DisconnectionEvent.java +++ b/src/main/java/jcs/commandStation/events/ConnectionEvent.java @@ -16,19 +16,24 @@ package jcs.commandStation.events; /** - * - * @author frans + * Event to signal Connection and Disconnection */ -public class DisconnectionEvent { +public class ConnectionEvent { private final String source; + private final boolean connected; - public DisconnectionEvent(String source) { + public ConnectionEvent(String source, boolean connected) { this.source = source; + this.connected = connected; } public String getSource() { return source; } + public boolean isConnected() { + return connected; + } + } diff --git a/src/main/java/jcs/commandStation/events/DisconnectionEventListener.java b/src/main/java/jcs/commandStation/events/ConnectionEventListener.java similarity index 87% rename from src/main/java/jcs/commandStation/events/DisconnectionEventListener.java rename to src/main/java/jcs/commandStation/events/ConnectionEventListener.java index aae616c5..ca11d8c9 100644 --- a/src/main/java/jcs/commandStation/events/DisconnectionEventListener.java +++ b/src/main/java/jcs/commandStation/events/ConnectionEventListener.java @@ -19,7 +19,7 @@ * * @author frans */ -public interface DisconnectionEventListener { +public interface ConnectionEventListener { - void onDisconnect(DisconnectionEvent event); + void onConnectionChange(ConnectionEvent event); } diff --git a/src/main/java/jcs/commandStation/events/MeasurementEvent.java b/src/main/java/jcs/commandStation/events/MeasurementEvent.java index 9d1d33c6..7fc76fe9 100644 --- a/src/main/java/jcs/commandStation/events/MeasurementEvent.java +++ b/src/main/java/jcs/commandStation/events/MeasurementEvent.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 frans. + * Copyright 2025 frans. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,30 +15,37 @@ */ package jcs.commandStation.events; -import jcs.entities.ChannelBean; +import jcs.commandStation.entities.MeasuredChannels; +import jcs.commandStation.entities.MeasurementBean; /** - * - * @author frans + * Signals the lastMeasurment(s) */ public class MeasurementEvent { - private final ChannelBean measurementChannel; + private final MeasuredChannels measuredChannels; + + public MeasurementEvent(MeasuredChannels measuredChannels) { + this.measuredChannels = measuredChannels; + } - public MeasurementEvent(ChannelBean measurementChannel) { - this.measurementChannel = measurementChannel; + public MeasuredChannels getMeasuredChannels() { + return measuredChannels; } - public ChannelBean getMeasurementChannel() { - return measurementChannel; + public MeasurementBean getMain() { + return measuredChannels.getMain(); } - public Integer getCannel() { - return this.measurementChannel.getNumber(); + public MeasurementBean getProg() { + return measuredChannels.getProg(); } - public String getFormattedValue() { - return this.measurementChannel.getHumanValue() + " " + this.measurementChannel.getUnit(); + public MeasurementBean getVolt() { + return measuredChannels.getVolt(); } + public MeasurementBean getTemp() { + return measuredChannels.getTemp(); + } } diff --git a/src/main/java/jcs/commandStation/events/MeasurementEventListener.java b/src/main/java/jcs/commandStation/events/MeasurementEventListener.java index ee36d981..189a8f7c 100644 --- a/src/main/java/jcs/commandStation/events/MeasurementEventListener.java +++ b/src/main/java/jcs/commandStation/events/MeasurementEventListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 frans. + * Copyright 2025 frans. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/src/main/java/jcs/commandStation/hsis88/HSIImpl.java b/src/main/java/jcs/commandStation/hsis88/HSIImpl.java index 30482db1..95b015a6 100644 --- a/src/main/java/jcs/commandStation/hsis88/HSIImpl.java +++ b/src/main/java/jcs/commandStation/hsis88/HSIImpl.java @@ -23,8 +23,7 @@ import jcs.JCS; import jcs.commandStation.AbstractController; import jcs.commandStation.FeedbackController; -import jcs.commandStation.events.DisconnectionEvent; -import jcs.commandStation.events.DisconnectionEventListener; +import jcs.commandStation.events.ConnectionEvent; import jcs.commandStation.events.SensorEvent; import jcs.commandStation.events.SensorEventListener; import static jcs.commandStation.hsis88.HSIConnection.COMMAND_VERSION; @@ -36,6 +35,7 @@ import jcs.entities.SensorBean; import jcs.util.RunUtil; import org.tinylog.Logger; +import jcs.commandStation.events.ConnectionEventListener; /** * @@ -201,9 +201,9 @@ public void disconnect() { Logger.trace("Disconnected"); } - private void fireAllDisconnectionEventListeners(final DisconnectionEvent disconnectionEvent) { - for (DisconnectionEventListener listener : this.disconnectionEventListeners) { - listener.onDisconnect(disconnectionEvent); + private void fireAllDisconnectionEventListeners(final ConnectionEvent disconnectionEvent) { + for (ConnectionEventListener listener : this.connectionEventListeners) { + listener.onConnectionChange(disconnectionEvent); } disconnect(); } @@ -236,7 +236,7 @@ public void onMessage(final HSIMessage message) { } @Override - public void onDisconnect(DisconnectionEvent event) { + public void onDisconnect(ConnectionEvent event) { this.hsiImpl.fireAllDisconnectionEventListeners(event); } } diff --git a/src/main/java/jcs/commandStation/hsis88/HSIMessageListener.java b/src/main/java/jcs/commandStation/hsis88/HSIMessageListener.java index 0a7cf7df..acb94478 100644 --- a/src/main/java/jcs/commandStation/hsis88/HSIMessageListener.java +++ b/src/main/java/jcs/commandStation/hsis88/HSIMessageListener.java @@ -15,7 +15,7 @@ */ package jcs.commandStation.hsis88; -import jcs.commandStation.events.DisconnectionEvent; +import jcs.commandStation.events.ConnectionEvent; /** * @@ -25,6 +25,6 @@ public interface HSIMessageListener { void onMessage(HSIMessage message); - void onDisconnect(DisconnectionEvent event); + void onDisconnect(ConnectionEvent event); } diff --git a/src/main/java/jcs/commandStation/hsis88/HSISerialConnection.java b/src/main/java/jcs/commandStation/hsis88/HSISerialConnection.java index 27e42871..1eade79d 100644 --- a/src/main/java/jcs/commandStation/hsis88/HSISerialConnection.java +++ b/src/main/java/jcs/commandStation/hsis88/HSISerialConnection.java @@ -25,7 +25,7 @@ import java.io.Writer; import java.util.ArrayList; import java.util.List; -import jcs.commandStation.events.DisconnectionEvent; +import jcs.commandStation.events.ConnectionEvent; import org.tinylog.Logger; /** @@ -175,7 +175,7 @@ private void disconnected() { Logger.trace("Port " + commPort.getSystemPortName() + " is Disconnected"); String msg = commPort.getDescriptivePortName() + " [" + commPort.getSystemPortName() + "]"; - DisconnectionEvent de = new DisconnectionEvent(msg); + ConnectionEvent de = new ConnectionEvent(msg, false); for (HSIMessageListener listener : feedbackListeners) { listener.onDisconnect(de); diff --git a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java index 4b7177a0..29991350 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java +++ b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java @@ -18,6 +18,7 @@ import jcs.commandStation.marklin.cs.can.device.CanDevice; import jcs.commandStation.marklin.cs.can.parser.FeedbackEventMessage; import java.awt.Image; +import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -72,8 +73,7 @@ import jcs.commandStation.autopilot.DriveSimulator; import jcs.commandStation.entities.MeasuredChannels; import jcs.commandStation.entities.MeasurementBean; -import jcs.commandStation.events.DisconnectionEvent; -import jcs.commandStation.events.DisconnectionEventListener; +import jcs.commandStation.events.ConnectionEvent; import jcs.commandStation.marklin.cs.can.device.ConfigChannel; import jcs.commandStation.marklin.cs.can.device.MeasuringChannel; import jcs.commandStation.marklin.cs.can.parser.CanDevices; @@ -86,12 +86,13 @@ import jcs.commandStation.marklin.cs.net.CSHTTPConnection; import jcs.commandStation.marklin.parser.GeraetParser; import jcs.commandStation.marklin.parser.SystemStatusMessage; +import jcs.commandStation.events.ConnectionEventListener; /** * * @author Frans Jacobs */ -public class MarklinCentralStationImpl extends AbstractController implements DecoderController, AccessoryController, FeedbackController, DisconnectionEventListener { +public class MarklinCentralStationImpl extends AbstractController implements DecoderController, AccessoryController, FeedbackController, ConnectionEventListener { private CSConnection connection; @@ -107,6 +108,9 @@ public class MarklinCentralStationImpl extends AbstractController implements Dec private WatchdogTask watchdogTask; private Timer watchDogTimer; + private MeasurementTask measurementTask; + private Timer measurementTimer; + private SortedMap measuredValues; public MarklinCentralStationImpl(CommandStationBean commandStationBean) { @@ -361,11 +365,11 @@ void obtainDevices() { Logger.trace("Query channel " + index); updateMessage = sendMessage(CanMessageFactory.statusDataConfig(device.getUidInt(), index)); CanDevices.parse(device, updateMessage); - + if (index <= measurementChannels) { Logger.trace("M#" + index + "; " + device.getMeasuringChannel(index)); } else { - int configChannelNumber = index - measurementChannels; + int configChannelNumber = index - measurementChannels; Logger.trace("C#" + configChannelNumber + "; " + device.getConfigChannel(configChannelNumber)); } } @@ -484,18 +488,24 @@ public void disconnect() { } @Override - public void onDisconnect(DisconnectionEvent event) { + public void onConnectionChange(ConnectionEvent event) { String s = event.getSource(); - disconnect(); + boolean con = event.isConnected(); + if (con) { + Logger.trace(s + " has re-connected"); + } else { + disconnect(); + } - for (DisconnectionEventListener listener : disconnectionEventListeners) { - listener.onDisconnect(event); + for (ConnectionEventListener listener : connectionEventListeners) { + listener.onConnectionChange(event); } } @Override public boolean isSupportTrackMeasurements() { - return true; + CanDevice gfp = canDevices.get(csUid); + return gfp.getMeasureChannelCount() > 0; } void performMeasurements() { @@ -506,15 +516,20 @@ void performMeasurements() { Logger.trace("Take a measurment on " + channels.size() + " channels"); - MeasuredChannels measuredChannels = new MeasuredChannels(System.currentTimeMillis()); + long now = System.currentTimeMillis(); + MeasuredChannels measuredChannels = new MeasuredChannels(now); for (MeasuringChannel channel : channels) { int channelNumber = channel.getNumber(); CanMessage message = sendMessage(CanMessageFactory.systemStatus(csUid, channelNumber)); - - MeasurementBean measurement = SystemStatusMessage.parse(channel, message); + MeasurementBean measurement = SystemStatusMessage.parse(channel, message, now); measuredChannels.addMeasurement(measurement); - Logger.trace(measurement); + //Logger.trace(measurement); + measuredValues.putLast(now, measuredChannels); + if (measuredValues.size() > 100) { + long first = measuredValues.firstKey(); + measuredValues.remove(first); + } } Logger.trace("Measurement: " + measuredChannels); } else { @@ -522,6 +537,14 @@ void performMeasurements() { } } + public List getMeasurements() { + return new ArrayList<>(measuredValues.values()); + } + + public MeasuredChannels getLastMeasurment() { + return measuredValues.firstEntry().getValue(); + } + @Override public synchronized Map getTrackMeasurements() { // Logger.trace("Perform measurement..."); @@ -1002,18 +1025,52 @@ public void run() { if (connectionLost) { Logger.trace("The last CANBootLoader request is received more than " + (checkInterval / 1000) + "s ago!"); - DisconnectionEvent de = new DisconnectionEvent("Marklin Central Station"); - commandStation.onDisconnect(de); + ConnectionEvent de = new ConnectionEvent("Marklin Central Station", false); + commandStation.onConnectionChange(de); } } else { //Try to reconnect if (!virtual && "true".equalsIgnoreCase(System.getProperty("controller.autoconnect", "true"))) { - commandStation.connect(); + boolean con = commandStation.connect(); + if (con) { + ConnectionEvent de = new ConnectionEvent("Marklin Central Station", true); + commandStation.onConnectionChange(de); + } } } } } + private void startMeasurements() { + long measureInterval = Long.parseLong(System.getProperty("measurement.interval", "5")); + measureInterval = measureInterval * 1000; + + if (measureInterval > 0 && !virtual) { + measurementTask = new MeasurementTask(this); + measurementTimer = new Timer("WatchDogTimer"); + measurementTimer.schedule(watchdogTask, 0, measureInterval); + Logger.debug("Started Measurement Timer with an interval of " + measureInterval + "ms"); + } else { + Logger.debug("Skipping Measurement Timer"); + } + } + + private class MeasurementTask extends TimerTask { + + private final MarklinCentralStationImpl commandStation; + + MeasurementTask(MarklinCentralStationImpl commandStation) { + this.commandStation = commandStation; + } + + @Override + public void run() { + if (commandStation.isConnected() && !virtual) { + commandStation.performMeasurements(); + } + } + } + //////////// For Testing only.....////// /// @param a /// diff --git a/src/main/java/jcs/commandStation/marklin/cs/net/CSConnection.java b/src/main/java/jcs/commandStation/marklin/cs/net/CSConnection.java index 98570204..2048f354 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/net/CSConnection.java +++ b/src/main/java/jcs/commandStation/marklin/cs/net/CSConnection.java @@ -17,8 +17,8 @@ import java.net.InetAddress; import java.util.concurrent.TransferQueue; -import jcs.commandStation.events.DisconnectionEventListener; import jcs.commandStation.marklin.cs.can.CanMessage; +import jcs.commandStation.events.ConnectionEventListener; public interface CSConnection extends AutoCloseable { @@ -36,7 +36,7 @@ public interface CSConnection extends AutoCloseable { TransferQueue getEventQueue(); - void addDisconnectionEventListener(DisconnectionEventListener listener); + void addDisconnectionEventListener(ConnectionEventListener listener); } diff --git a/src/main/java/jcs/commandStation/marklin/cs/net/CSTCPConnection.java b/src/main/java/jcs/commandStation/marklin/cs/net/CSTCPConnection.java index ff23b27c..88c5257b 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/net/CSTCPConnection.java +++ b/src/main/java/jcs/commandStation/marklin/cs/net/CSTCPConnection.java @@ -26,10 +26,10 @@ import java.util.List; import java.util.concurrent.LinkedTransferQueue; import java.util.concurrent.TransferQueue; -import jcs.commandStation.events.DisconnectionEvent; -import jcs.commandStation.events.DisconnectionEventListener; +import jcs.commandStation.events.ConnectionEvent; import jcs.commandStation.marklin.cs.can.CanMessage; import org.tinylog.Logger; +import jcs.commandStation.events.ConnectionEventListener; /** * @@ -43,7 +43,7 @@ class CSTCPConnection implements CSConnection { private DataOutputStream dos; private ClientMessageReceiver messageReceiver; - private final List disconnectionEventListeners; + private final List disconnectionEventListeners; private static final long SHORT_TIMEOUT = 1000L; private static final long LONG_TIMEOUT = 5000L; @@ -85,7 +85,7 @@ public TransferQueue getEventQueue() { } @Override - public void addDisconnectionEventListener(DisconnectionEventListener listener) { + public void addDisconnectionEventListener(ConnectionEventListener listener) { this.disconnectionEventListeners.add(listener); } @@ -300,9 +300,9 @@ public void run() { } catch (SocketException se) { if (!quit) { String msg = "Host " + centralStationAddress.getHostName(); - DisconnectionEvent de = new DisconnectionEvent(msg); - for (DisconnectionEventListener listener : disconnectionEventListeners) { - listener.onDisconnect(de); + ConnectionEvent de = new ConnectionEvent(msg, false); + for (ConnectionEventListener listener : disconnectionEventListeners) { + listener.onConnectionChange(de); } } diff --git a/src/main/java/jcs/commandStation/marklin/cs/net/CSVirtualConnection.java b/src/main/java/jcs/commandStation/marklin/cs/net/CSVirtualConnection.java index 8cf10b5f..4802eb57 100644 --- a/src/main/java/jcs/commandStation/marklin/cs/net/CSVirtualConnection.java +++ b/src/main/java/jcs/commandStation/marklin/cs/net/CSVirtualConnection.java @@ -22,13 +22,13 @@ import java.util.concurrent.LinkedTransferQueue; import java.util.concurrent.TransferQueue; import jcs.commandStation.VirtualConnection; -import jcs.commandStation.events.DisconnectionEvent; -import jcs.commandStation.events.DisconnectionEventListener; +import jcs.commandStation.events.ConnectionEvent; import jcs.commandStation.events.SensorEvent; import jcs.commandStation.marklin.cs.can.CanMessage; import jcs.commandStation.marklin.cs.can.CanMessageFactory; import jcs.commandStation.marklin.cs.can.parser.SystemStatus; import org.tinylog.Logger; +import jcs.commandStation.events.ConnectionEventListener; /** * Virtual Marklin CS Connection @@ -42,7 +42,7 @@ class CSVirtualConnection implements CSConnection, VirtualConnection { private final InetAddress centralStationAddress; private PeriodicCSMessageSender periodicMessageSender; - private final List disconnectionEventListeners; + private final List disconnectionEventListeners; private final TransferQueue eventQueue; @@ -92,7 +92,7 @@ public TransferQueue getEventQueue() { } @Override - public void addDisconnectionEventListener(DisconnectionEventListener listener) { + public void addDisconnectionEventListener(ConnectionEventListener listener) { this.disconnectionEventListeners.add(listener); } @@ -217,9 +217,7 @@ public synchronized CanMessage sendCanMessage(CanMessage message) { //RX: 0x00 0x16 0x37 0x7e 0x06 0x00 0x00 0x38 0x01 0x00 0x00 0x00 0x00 //RX: 0x00 0x16 0x37 0x7e 0x06 0x00 0x00 0x38 0x01 0x01 0x01 0x00 0x00 //RX: 0x00 0x16 0x37 0x7e 0x06 0x00 0x00 0x38 0x01 0x01 0x00 0x00 0x00 - - - + } case CanMessage.LOC_VELOCITY -> { message.addResponse(CanMessage.parse(message.toString(), true)); @@ -294,9 +292,9 @@ public void run() { } String msg = "Host " + centralStationAddress.getHostName(); - DisconnectionEvent de = new DisconnectionEvent(msg); - for (DisconnectionEventListener listener : disconnectionEventListeners) { - listener.onDisconnect(de); + ConnectionEvent de = new ConnectionEvent(msg, false); + for (ConnectionEventListener listener : disconnectionEventListeners) { + listener.onConnectionChange(de); } Logger.trace("Stop sending"); diff --git a/src/main/java/jcs/commandStation/marklin/parser/SystemStatusMessage.java b/src/main/java/jcs/commandStation/marklin/parser/SystemStatusMessage.java index d5da87f2..16746441 100644 --- a/src/main/java/jcs/commandStation/marklin/parser/SystemStatusMessage.java +++ b/src/main/java/jcs/commandStation/marklin/parser/SystemStatusMessage.java @@ -32,8 +32,10 @@ public SystemStatusMessage() { } public static MeasurementBean parse(MeasuringChannel channel, CanMessage systemStatusmessage) { + return parse(channel, systemStatusmessage, System.currentTimeMillis()); + } - Logger.trace(systemStatusmessage); + public static MeasurementBean parse(MeasuringChannel channel, CanMessage systemStatusmessage, long measurementMillis) { MeasurementBean measurement = null; if (systemStatusmessage.getCommand() == CanMessage.SYSTEM_COMMAND && systemStatusmessage.getSubCommand() == CanMessage.SYSTEM_SUB_STATUS) { @@ -51,7 +53,7 @@ public static MeasurementBean parse(MeasuringChannel channel, CanMessage systemS int measuredValue = CanMessage.toInt(new byte[]{data[6], data[7]}); Double displayValue = calculateDisplayValue(measuredValue, channel); - measurement = new MeasurementBean(channelNumber, channel.getName(), System.currentTimeMillis(), measuredValue, channel.getUnit(), displayValue); + measurement = new MeasurementBean(channelNumber, channel.getName(), measurementMillis, measuredValue, channel.getUnit(), displayValue); } default -> Logger.error("Invalid DLC " + response.getDlc() + " response " + response); diff --git a/src/main/java/jcs/ui/JCSFrame.java b/src/main/java/jcs/ui/JCSFrame.java index f4ed9f97..b4225329 100755 --- a/src/main/java/jcs/ui/JCSFrame.java +++ b/src/main/java/jcs/ui/JCSFrame.java @@ -56,8 +56,7 @@ import javax.swing.border.LineBorder; import jcs.JCS; import jcs.commandStation.autopilot.AutoPilot; -import jcs.commandStation.events.DisconnectionEvent; -import jcs.commandStation.events.DisconnectionEventListener; +import jcs.commandStation.events.ConnectionEvent; import jcs.commandStation.events.PowerEvent; import jcs.commandStation.entities.InfoBean; import jcs.persistence.PersistenceFactory; @@ -76,12 +75,13 @@ import jcs.util.SerialPortUtil; import jcs.util.VersionInfo; import org.tinylog.Logger; +import jcs.commandStation.events.ConnectionEventListener; /** * * @author frans */ -public class JCSFrame extends JFrame implements UICallback, DisconnectionEventListener { +public class JCSFrame extends JFrame implements UICallback, ConnectionEventListener { private static final long serialVersionUID = -5800900684173242844L; @@ -1143,11 +1143,17 @@ public void openFiles(List files) { } @Override - public void onDisconnect(DisconnectionEvent event) { - JOptionPane.showMessageDialog(this, "CommandStation " + event.getSource() + " is disconnected.", "Disconnection error", JOptionPane.ERROR_MESSAGE); - connectMI.setText("Connect"); - connectButton.setSelected(false); - showVNCBtn.setEnabled(false); + public void onConnectionChange(ConnectionEvent event) { + if (event.isConnected()) { + connectMI.setText("DisConnect"); + connectButton.setSelected(true); + showVNCBtn.setEnabled(true); + } else { + JOptionPane.showMessageDialog(this, "CommandStation " + event.getSource() + " is disconnected.", "Disconnection error", JOptionPane.ERROR_MESSAGE); + connectMI.setText("Connect"); + connectButton.setSelected(false); + showVNCBtn.setEnabled(false); + } } @Override diff --git a/src/main/java/jcs/ui/StatusPanel.java b/src/main/java/jcs/ui/StatusPanel.java index 12e6a5e2..416051d2 100644 --- a/src/main/java/jcs/ui/StatusPanel.java +++ b/src/main/java/jcs/ui/StatusPanel.java @@ -48,18 +48,18 @@ private void postInit() { @Override public void onMeasurement(MeasurementEvent event) { - switch (event.getCannel()) { - case 1: - this.currentLbl.setText(event.getFormattedValue()); - break; - case 3: - this.voltageLbl.setText(event.getFormattedValue()); - break; - case 4: - this.tempLbl.setText(event.getFormattedValue()); - default: - break; - } +// switch (event.getCannel()) { +// case 1: +// this.currentLbl.setText(event.getFormattedValue()); +// break; +// case 3: +// this.voltageLbl.setText(event.getFormattedValue()); +// break; +// case 4: +// this.tempLbl.setText(event.getFormattedValue()); +// default: +// break; +// } } diff --git a/src/test/java/jcs/commandStation/marklin/parser/SystemStatusMessageTest.java b/src/test/java/jcs/commandStation/marklin/parser/SystemStatusMessageTest.java index a84a5d67..8096567a 100644 --- a/src/test/java/jcs/commandStation/marklin/parser/SystemStatusMessageTest.java +++ b/src/test/java/jcs/commandStation/marklin/parser/SystemStatusMessageTest.java @@ -40,39 +40,138 @@ public void setUp() { public void tearDown() { } - //Example - //0x00 0x00 0x47 0x11 0x06 0x43 0x53 0x32 0x08 0x0B 0x01 0x00 0x00 - //Abfrage des Messwertes Kanalnummer 1 -//00014711 8 43 53 32 08 0B 01 00 03 - - private CanMessage getSystemStatusMessageIndex1() { - CanMessage sysStat = CanMessage.parse("0x00 0x3a 0x37 0x7f 0x05 0x63 0x73 0x45 0x8c 0x01 0x00 0x00 0x00"); - sysStat.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x01 0x08 0x01 0xfd 0x30 0xf0 0xe0 0xc0 0x00 0x00")); - sysStat.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x02 0x08 0x02 0x28 0x02 0x40 0x02 0x58 0x02 0x94")); - sysStat.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x03 0x08 0x4d 0x41 0x49 0x4e 0x00 0x30 0x2e 0x30")); - sysStat.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x04 0x08 0x30 0x00 0x35 0x2e 0x35 0x30 0x00 0x41")); - sysStat.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x05 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00")); - sysStat.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x26 0x06 0x63 0x73 0x45 0x8c 0x01 0x05 0x00 0x00")); + private CanMessage getSystemStatusMessageChannel1() { + CanMessage sysStat = CanMessage.parse("0x00 0x00 0x37 0x7f 0x06 0x63 0x73 0x45 0x8c 0x0b 0x01 0x00 0x00"); + sysStat.addResponse(CanMessage.parse("0x00 0x01 0x03 0x26 0x08 0x63 0x73 0x45 0x8c 0x0b 0x01 0x00 0x00")); + return sysStat; + } + + private CanMessage getSystemStatusMessageChannel2() { + CanMessage sysStat = CanMessage.parse("0x00 0x00 0x37 0x7f 0x06 0x63 0x73 0x45 0x8c 0x0b 0x02 0x00 0x00"); + sysStat.addResponse(CanMessage.parse("0x00 0x01 0x03 0x26 0x08 0x63 0x73 0x45 0x8c 0x0b 0x02 0x00 0x03")); + return sysStat; + } + + private CanMessage getSystemStatusMessageChannel3() { + CanMessage sysStat = CanMessage.parse("0x00 0x00 0x37 0x7f 0x06 0x63 0x73 0x45 0x8c 0x0b 0x03 0x00 0x00"); + sysStat.addResponse(CanMessage.parse("0x00 0x01 0x03 0x26 0x08 0x63 0x73 0x45 0x8c 0x0b 0x03 0x01 0x5e")); + return sysStat; + } + private CanMessage getSystemStatusMessageChannel4() { + CanMessage sysStat = CanMessage.parse("0x00 0x00 0x37 0x7f 0x06 0x63 0x73 0x45 0x8c 0x0b 0x04 0x00 0x00"); + sysStat.addResponse(CanMessage.parse("0x00 0x01 0x03 0x26 0x08 0x63 0x73 0x45 0x8c 0x0b 0x04 0x00 0x74")); return sysStat; + } + + @Test + public void testParseChannel1() { + System.out.println("parseChannel1"); + MeasuringChannel channel = new MeasuringChannel(); + channel.setNumber(1); + channel.setName("MAIN"); + channel.setScale(-3); + channel.setColorGreen(48); + channel.setColorYellow(240); + channel.setColorRed(224); + channel.setColorMax(192); + channel.setZeroPoint(0); + channel.setRangeGreen(552); + channel.setRangeRed(576); + channel.setRangeMax(660); + channel.setStartValue(0.0); + channel.setEndValue(5.5); + channel.setUnit("A"); + + CanMessage systemStatusmessage = getSystemStatusMessageChannel1(); + long now = System.currentTimeMillis(); + MeasurementBean expResult = new MeasurementBean(channel.getNumber(), channel.getName(), now, 0, channel.getUnit(), 0.0); + + MeasurementBean result = SystemStatusMessage.parse(channel, systemStatusmessage, now); + assertEquals(expResult, result); + } + + @Test + public void testParseChannel2() { + System.out.println("parseChannel2"); + MeasuringChannel channel = new MeasuringChannel(); + channel.setNumber(2); + channel.setName("PROG"); + channel.setScale(-3); + channel.setColorGreen(48); + channel.setColorYellow(240); + channel.setColorRed(224); + channel.setColorMax(192); + channel.setZeroPoint(0); + channel.setRangeGreen(330); + channel.setRangeRed(363); + channel.setRangeMax(759); + channel.setStartValue(0.0); + channel.setEndValue(2.3); + channel.setUnit("A"); + + CanMessage systemStatusmessage = getSystemStatusMessageChannel2(); + long now = System.currentTimeMillis(); + MeasurementBean expResult = new MeasurementBean(channel.getNumber(), channel.getName(), now, 3, channel.getUnit(), 0.009); + + MeasurementBean result = SystemStatusMessage.parse(channel, systemStatusmessage, now); + assertEquals(expResult, result); + } -// TRACE 2025-05-03 23:04:11.593 [main] CSTCPConnection.sendCanMessage(): #TX: 0x00 0x3a 0x37 0x7f 0x05 0x63 0x73 0x45 0x8c 0x01 0x00 0x00 0x00 -//TRACE 2025-05-03 23:04:11.593 [main] CSTCPConnection.sendCanMessage(): #RX 0: 0x00 0x3b 0x03 0x01 0x08 0x01 0xfd 0x30 0xf0 0xe0 0xc0 0x00 0x00 -//TRACE 2025-05-03 23:04:11.593 [main] CSTCPConnection.sendCanMessage(): #RX 1: 0x00 0x3b 0x03 0x02 0x08 0x02 0x28 0x02 0x40 0x02 0x58 0x02 0x94 -//TRACE 2025-05-03 23:04:11.593 [main] CSTCPConnection.sendCanMessage(): #RX 2: 0x00 0x3b 0x03 0x03 0x08 0x4d 0x41 0x49 0x4e 0x00 0x30 0x2e 0x30 -//TRACE 2025-05-03 23:04:11.593 [main] CSTCPConnection.sendCanMessage(): #RX 3: 0x00 0x3b 0x03 0x04 0x08 0x30 0x00 0x35 0x2e 0x35 0x30 0x00 0x41 -//TRACE 2025-05-03 23:04:11.593 [main] CSTCPConnection.sendCanMessage(): #RX 4: 0x00 0x3b 0x03 0x05 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 -//TRACE 2025-05-03 23:04:11.593 [main] CSTCPConnection.sendCanMessage(): #RX 5: 0x00 0x3b 0x03 0x26 0x06 0x63 0x73 0x45 0x8c 0x01 0x05 0x00 0x00 + @Test + public void testParseChannel3() { + System.out.println("parseChannel3"); + MeasuringChannel channel = new MeasuringChannel(); + channel.setNumber(3); + channel.setName("VOLT"); + channel.setScale(-3); + channel.setColorGreen(192); + channel.setColorYellow(12); + channel.setColorRed(48); + channel.setColorMax(192); + channel.setZeroPoint(0); + channel.setRangeGreen(194); + channel.setRangeYellow(252); + channel.setRangeRed(252); + channel.setRangeMax(659); + channel.setStartValue(10.0); + channel.setEndValue(27.0); + channel.setUnit("V"); + + CanMessage systemStatusmessage = getSystemStatusMessageChannel3(); + long now = System.currentTimeMillis(); + MeasurementBean expResult = new MeasurementBean(channel.getNumber(), channel.getName(), now, 350, channel.getUnit(), 19.0); + + MeasurementBean result = SystemStatusMessage.parse(channel, systemStatusmessage, now); + assertEquals(expResult, result); } @Test - public void testParse() { - System.out.println("parse"); - MeasuringChannel channel = null; - CanMessage systemStatusmessage = null; - MeasurementBean expResult = null; - MeasurementBean result = SystemStatusMessage.parse(channel, systemStatusmessage); + public void testParseChannel4() { + System.out.println("parseChannel4"); + MeasuringChannel channel = new MeasuringChannel(); + channel.setNumber(4); + channel.setName("TEMP"); + channel.setScale(-3); + channel.setColorGreen(12); + channel.setColorYellow(8); + channel.setColorRed(240); + channel.setColorMax(192); + channel.setZeroPoint(0); + channel.setRangeGreen(121); + channel.setRangeYellow(145); + channel.setRangeRed(145); + channel.setRangeMax(193); + channel.setStartValue(0.0); + channel.setEndValue(80.0); + channel.setUnit("C"); + + CanMessage systemStatusmessage = getSystemStatusMessageChannel4(); + long now = System.currentTimeMillis(); + MeasurementBean expResult = new MeasurementBean(channel.getNumber(), channel.getName(), now, 116, channel.getUnit(), 48.1); + + MeasurementBean result = SystemStatusMessage.parse(channel, systemStatusmessage, now); assertEquals(expResult, result); - fail("The test case is a prototype."); } + } diff --git a/src/test/java/jcs/persistence/PersistenceServiceTest.java b/src/test/java/jcs/persistence/PersistenceServiceTest.java index 87635b2c..80dd084c 100644 --- a/src/test/java/jcs/persistence/PersistenceServiceTest.java +++ b/src/test/java/jcs/persistence/PersistenceServiceTest.java @@ -39,6 +39,7 @@ import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; +import org.junit.jupiter.api.Order; import org.tinylog.Logger; public class PersistenceServiceTest { @@ -73,10 +74,19 @@ public PersistenceServiceTest() { @BeforeClass public static void setUpClass() throws Exception { +// System.setProperty("persistenceService", "jcs.persistence.H2PersistenceService"); +// PersistenceTestHelper.createDatabaseUsers(); +// PersistenceTestHelper.createDatabase(); +// PersistenceTestHelper.getInstance().insertTestData(); +// CommandStationBean csb = new CommandStationBean(); +// csb.setId("marklin.cs"); + //PersistenceFactory.getService().changeDefaultCommandStation(csb); + Logger.info("####### PersistenceService Test Start...."); } @AfterClass public static void tearDownClass() throws Exception { + Logger.info("####### PersistenceService Test END...."); } @Before @@ -252,6 +262,7 @@ public void tearDown() { * Test of getProperties method, of class PersistenceService. */ @Test + @Order(1) public void testGetProperties() { System.out.println("getProperties"); PersistenceService instance = PersistenceFactory.getService(); @@ -264,6 +275,7 @@ public void testGetProperties() { * Test of getProperty method, of class PersistenceService. */ @Test + @Order(2) public void testGetProperty() { System.out.println("getProperty"); String key = "k2"; @@ -277,8 +289,9 @@ public void testGetProperty() { * Test of persist method, of class PersistenceService. */ @Test - public void testPersist_JCSPropertyBean() { - System.out.println("persist"); + @Order(3) + public void testPersistJCSPropertyBean() { + System.out.println("persistJCSPropertyBean"); JCSPropertyBean propertyBean = new JCSPropertyBean("k3", "v3"); PersistenceService instance = PersistenceFactory.getService(); JCSPropertyBean expResult = propertyBean; @@ -300,8 +313,9 @@ public void testPersist_JCSPropertyBean() { * Test of remove method, of class PersistenceService. */ @Test - public void testRemove_JCSPropertyBean() { - System.out.println("remove"); + @Order(4) + public void testRemoveJCSPropertyBean() { + System.out.println("removeJCSPropertyBean"); JCSPropertyBean property = new JCSPropertyBean("k4", "v4"); PersistenceService instance = PersistenceFactory.getService(); @@ -318,11 +332,13 @@ public void testRemove_JCSPropertyBean() { * Test of getSensors method, of class PersistenceService. */ @Test + @Order(5) public void testGetSensors() { System.out.println("getSensors"); PersistenceService instance = PersistenceFactory.getService(); List expResult = this.sensors; List result = instance.getSensors(); + assertEquals(expResult, result); } @@ -330,8 +346,9 @@ public void testGetSensors() { * Test of getSensor method, of class PersistenceService. */ @Test - public void testGetSensor_Long() { - System.out.println("getSensor"); + @Order(6) + public void testGetSensorString() { + System.out.println("getSensorString"); String id = "65-1"; PersistenceService instance = PersistenceFactory.getService(); SensorBean expResult = sensors.get(0); @@ -343,8 +360,9 @@ public void testGetSensor_Long() { * Test of getSensor method, of class PersistenceService. */ @Test - public void testGetSensor_Integer_Integer() { - System.out.println("getSensor"); + @Order(7) + public void testGetSensorIntegerInteger() { + System.out.println("getSensorIntegerInteger"); Integer deviceId = 65; Integer contactId = 2; PersistenceService instance = PersistenceFactory.getService(); @@ -357,8 +375,9 @@ public void testGetSensor_Integer_Integer() { * Test of persist method, of class PersistenceService. */ @Test - public void testPersist_SensorBean() { - System.out.println("persist"); + @Order(8) + public void testPersistSensorBean() { + System.out.println("persistSensorBean"); SensorBean sensor = new SensorBean("M1P3", 65, 3, 0, 1, 0, null); PersistenceService instance = PersistenceFactory.getService(); @@ -381,8 +400,9 @@ public void testPersist_SensorBean() { * Test of remove method, of class PersistenceService. */ @Test - public void testRemove_SensorBean() { - System.out.println("remove"); + @Order(9) + public void testRemoveSensorBean() { + System.out.println("removeSensorBean"); SensorBean sensor = new SensorBean("M1P4", 65, 4, 0, 1, 0, null); PersistenceService instance = PersistenceFactory.getService(); @@ -403,6 +423,7 @@ public void testRemove_SensorBean() { * Test of getLocomotives method, of class PersistenceService. */ @Test + @Order(10) public void testGetLocomotives() { System.out.println("getLocomotives"); PersistenceService instance = PersistenceFactory.getService(); @@ -434,8 +455,9 @@ public void testGetLocomotives() { * Test of getLocomotive method, of class PersistenceService. */ @Test - public void testGetLocomotive_Integer_DecoderType() { - System.out.println("getLocomotive"); + @Order(11) + public void testGetLocomotiveIntegerDecoderType() { + System.out.println("getLocomotiveIntegerDecoderType"); Integer address = 8; DecoderType decoderType = DecoderType.MM_PRG; @@ -464,17 +486,15 @@ public void testGetLocomotive_Integer_DecoderType() { resFunctions.addAll(result.getFunctions().values()); assertEquals(2, resFunctions.size()); - - // List locomotiveFunctions = new LinkedList<>(); - // assertEquals(functions, locomotiveFunctions); } /** * Test of getLocomotive method, of class PersistenceService. */ @Test - public void testGetLocomotive_Integer() { - System.out.println("getLocomotive"); + @Order(12) + public void testGetLocomotiveInteger() { + System.out.println("getLocomotiveInteger"); Long id = 2L; PersistenceService instance = PersistenceFactory.getService(); LocomotiveBean expResult = this.locomotives.get(0); @@ -503,8 +523,9 @@ public void testGetLocomotive_Integer() { * Test of persist method, of class PersistenceService. */ @Test - public void testPersist_LocomotiveBean() { - System.out.println("persist"); + @Order(13) + public void testPersistLocomotiveBean() { + System.out.println("persistLocomotiveBean"); LocomotiveBean locomotive = new LocomotiveBean(80L, "DB BR 44 100", 16393L, 80, "DB BR 44 100", "mfx", 80, 5, 0, 0, false, true, false); locomotive.setCommandStationId("marklin.cs"); @@ -537,8 +558,6 @@ public void testPersist_LocomotiveBean() { FunctionBean function = locfunctions.get(0); fb80_0.setId(23L); assertEquals(fb80_0, function); - // expected: jcs.entities.FunctionBean - // but was: jcs.entities.FunctionBean loco.setIcon("new Icon"); instance.persist(loco); @@ -553,8 +572,9 @@ public void testPersist_LocomotiveBean() { * Test of remove method, of class PersistenceService. */ @Test - public void testRemove_LocomotiveBean() { - System.out.println("remove"); + @Order(14) + public void testRemoveLocomotiveBean() { + System.out.println("removeLocomotiveBean"); LocomotiveBean locomotiveBean = new LocomotiveBean(70L, "To Be Removed", 16370L, 70, "To Be Removed", "mfx", 80, 5, 0, 0, false, true, false); locomotiveBean.setCommandStationId("marklin.cs"); @@ -578,6 +598,7 @@ public void testRemove_LocomotiveBean() { * Test of getTurnouts method, of class PersistenceService. */ @Test + @Order(15) public void testGetTurnouts() { System.out.println("getTurnouts"); PersistenceService instance = PersistenceFactory.getService(); @@ -594,6 +615,7 @@ public void testGetTurnouts() { * Test of getSignals method, of class PersistenceService. */ @Test + @Order(16) public void testGetSignals() { System.out.println("getSignals"); PersistenceService instance = PersistenceFactory.getService(); @@ -613,6 +635,7 @@ public void testGetSignals() { * Test of getAccessory method, of class PersistenceService. */ @Test + @Order(17) public void testGetAccessoryById() { System.out.println("getAccessoryById"); String id = "25"; @@ -626,6 +649,7 @@ public void testGetAccessoryById() { * Test of getAccessoryByAddress method, of class PersistenceService. */ @Test + @Order(18) public void testGetAccessory() { System.out.println("getAccessory"); Integer address = 7; @@ -639,8 +663,9 @@ public void testGetAccessory() { * Test of persist method, of class PersistenceService. */ @Test - public void testPersist_AccessoryBean() { - System.out.println("persist"); + @Order(19) + public void testPersistAccessoryBean() { + System.out.println("persistAccessoryBean"); AccessoryBean accessory = new AccessoryBean("100", 100, "W 100", "rechtsweiche", 1, 2, 200, "mm", "ein_alt", "weichen", "005", "magicon_a_005_01.svg", "marklin.cs"); PersistenceService instance = PersistenceFactory.getService(); @@ -668,8 +693,9 @@ public void testPersist_AccessoryBean() { * Test of remove method, of class PersistenceService. */ @Test - public void testRemove_AccessoryBean() { - System.out.println("remove"); + @Order(20) + public void testRemoveAccessoryBean() { + System.out.println("removeAccessoryBean"); AccessoryBean accessory = new AccessoryBean("101", 101, "W 101", "rechtsweiche", 1, 2, 200, "mm", "ein_alt", "weichen", "005", "magicon_a_005_01.svg", "marklin.cs"); PersistenceService instance = PersistenceFactory.getService(); @@ -690,8 +716,9 @@ public void testRemove_AccessoryBean() { * Test of getTileBeans method, of class PersistenceService. */ @Test + @Order(21) public void testGetTileBeans() { - System.out.println("getTiles"); + System.out.println("getTileBeans"); PersistenceService instance = PersistenceFactory.getService(); List result = instance.getTileBeans(); @@ -704,6 +731,7 @@ public void testGetTileBeans() { * Test of getTileBean method, of class PersistenceService. */ @Test + @Order(22) public void testGetTile() { System.out.println("getTile"); Integer x = 300; @@ -718,8 +746,9 @@ public void testGetTile() { * Test of persist method, of class PersistenceService. */ @Test - public void testPersist_TileBean() { - System.out.println("persist"); + @Order(23) + public void testPersistTileBean() { + System.out.println("persistTileBean"); TileBean sw12 = new TileBean("sw-12", TileBean.TileType.SWITCH, Orientation.EAST, Direction.RIGHT, 50, 50, null, null, null); PersistenceService instance = PersistenceFactory.getService(); @@ -738,8 +767,9 @@ public void testPersist_TileBean() { } @Test - public void testRemove_TileBean() { - System.out.println("remove"); + @Order(24) + public void testRemoveTileBean() { + System.out.println("removeTileBean"); TileBean sw13 = new TileBean("sw-13", TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 80, 50, null, null, null); PersistenceService instance = PersistenceFactory.getService(); @@ -759,8 +789,9 @@ public void testRemove_TileBean() { * Test of persist method, of class PersistenceService. */ @Test - public void testPersist_List_TileBeans() { - System.out.println("persist list"); + @Order(25) + public void testPersistListTileBeans() { + System.out.println("persistListTileBeans"); PersistenceService instance = PersistenceFactory.getService(); List tbl = this.tiles; TileBean sw22 = new TileBean("sw-22", TileBean.TileType.CROSS, Orientation.EAST, Direction.CENTER, 100, 100, null, null, null); @@ -785,6 +816,7 @@ public void testPersist_List_TileBeans() { } @Test + @Order(26) public void testPersistLotsOfTileBeans() { System.out.println("persistLotsOfTileBeans"); PersistenceService instance = PersistenceFactory.getService(); @@ -810,6 +842,7 @@ public void testPersistLotsOfTileBeans() { } @Test + @Order(27) public void testGetRoutes() { System.out.println("getRoutes"); PersistenceService instance = PersistenceFactory.getService(); @@ -819,8 +852,9 @@ public void testGetRoutes() { } @Test - public void testGetRoute_String() { - System.out.println("getRoute_string"); + @Order(28) + public void testGetRouteString() { + System.out.println("getRouteString"); PersistenceService instance = PersistenceFactory.getService(); RouteBean expResult = this.routes.get(1); RouteBean result = instance.getRoute("[bk-2-]->[bk-1+]"); @@ -828,6 +862,7 @@ public void testGetRoute_String() { } @Test + @Order(29) public void testGetRoute_String_String_String_String() { System.out.println("getRoute_string_string_string_string"); PersistenceService instance = PersistenceFactory.getService(); @@ -842,6 +877,7 @@ public void testGetRoute_String_String_String_String() { } @Test + @Order(30) public void testLockRoute() { System.out.println("LockRoute"); PersistenceService instance = PersistenceFactory.getService(); @@ -871,8 +907,9 @@ public void testLockRoute() { } @Test - public void testPersist_RouteBean() { - System.out.println("persist"); + @Order(31) + public void testPersistRouteBean() { + System.out.println("persistRouteBean"); RouteBean route = new RouteBean("[ct-2]->[ct-5]", "ct-2", "*", "ct-5", "*", "blue"); List rel = new LinkedList<>(); @@ -908,8 +945,9 @@ public void testPersist_RouteBean() { } @Test - public void testRemove_RouteBean() { - System.out.println("remove"); + @Order(32) + public void testRemoveRouteBean() { + System.out.println("removeRouteBean"); RouteBean routeBean = new RouteBean("[ct-5]->[ct-2]", "ct-5", "*", "ct-2", "*", "orange"); PersistenceService instance = PersistenceFactory.getService(); @@ -927,6 +965,7 @@ public void testRemove_RouteBean() { } @Test + @Order(33) public void testGetBlocks() { System.out.println("getBlocks"); PersistenceService instance = PersistenceFactory.getService(); @@ -936,6 +975,7 @@ public void testGetBlocks() { } @Test + @Order(34) public void testGetBlock() { System.out.println("getBlock"); String id = "bk-1"; @@ -946,6 +986,7 @@ public void testGetBlock() { } @Test + @Order(35) public void testGetBlockByTileId() { System.out.println("getBlockByTileId"); String tileId = "bk-2"; @@ -956,8 +997,9 @@ public void testGetBlockByTileId() { } @Test - public void testPersist_BlockBean() { - System.out.println("persist"); + @Order(36) + public void testPersistBlockBean() { + System.out.println("persistBlockBean"); BlockBean block = new BlockBean(); block.setId("st-1"); block.setTileId("st-1"); @@ -978,8 +1020,9 @@ public void testPersist_BlockBean() { } @Test - public void testRemove_BlockBean() { - System.out.println("remove"); + @Order(37) + public void testRemoveBlockBean() { + System.out.println("removeBlockBean"); BlockBean block = new BlockBean(); block.setId("si-3"); block.setTileId("si-3"); @@ -1002,6 +1045,7 @@ public void testRemove_BlockBean() { } @Test + @Order(38) public void testRemoveAllBlocks() { System.out.println("removeAllBlocks"); PersistenceService instance = PersistenceFactory.getService(); @@ -1018,6 +1062,7 @@ public void testRemoveAllBlocks() { } @Test + @Order(39) public void testCommandStations() { System.out.println("commandStations"); PersistenceService instance = PersistenceFactory.getService(); diff --git a/src/test/resources/jcs-test-data-h2.sql b/src/test/resources/jcs-test-data-h2.sql index 56250c30..eb0d4e9a 100755 --- a/src/test/resources/jcs-test-data-h2.sql +++ b/src/test/resources/jcs-test-data-h2.sql @@ -1,12 +1,15 @@ -delete from blocks; -delete from jcs_properties; -delete from locomotive_functions; -delete from locomotives; delete from route_elements; delete from routes; +delete from blocks; delete from tiles; + +commit; + +delete from locomotive_functions; +delete from locomotives; delete from sensors; delete from accessories; +delete from jcs_properties; commit; From 20a13b877aabb17f587d372926e69016cce99614 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Mon, 5 May 2025 16:51:28 +0200 Subject: [PATCH 50/70] More refactoring and testing Measurement work now also in GUI --- nb-configuration.xml | 44 +- nbactions.xml | 7 + pom.xml | 4 +- .../commandStation/AbstractController.java | 2 +- .../jcs/commandStation/DecoderController.java | 4 - .../commandStation/JCSCommandStationImpl.java | 24 +- .../dccex/DccExCommandStationImpl.java | 260 ++++---- .../commandStation/entities/DeviceBean.java | 583 ------------------ .../entities/MeasuredChannels.java | 39 +- .../entities/MeasurementBeanOld.java | 54 -- .../esu/ecos/EsuEcosCommandStationImpl.java | 21 - .../marklin/cs/MarklinCentralStationImpl.java | 280 ++++----- .../marklin/cs/can/device/CanDevice.java | 52 +- .../marklin/cs/net/CSHTTPConnectionImpl.java | 114 ++-- .../marklin/cs/net/CSHTTPConnectionVirt.java | 15 +- .../marklin/cs/net/CSTCPConnection.java | 15 +- .../marklin/cs3/DeviceJSONParser.java | 73 --- .../marklin/parser/CanDeviceJSONParser.java | 136 ++++ .../CanDeviceParser.java} | 26 +- .../marklin/parser/GeraetParser.java | 4 +- .../virtual/VirtualCommandStationImpl.java | 6 - src/main/java/jcs/ui/StatusPanel.java | 28 +- .../ecos/EsuEcosCommandStationImplTest.java | 3 - .../parser/CanDeviceJSONParserTest.java | 149 +++++ .../CanDeviceParserTest.java} | 18 +- .../{cs/can => parser}/CanMessageTest.java | 4 +- .../parser/ChannelDataParserTest.java | 2 +- src/test/java/jcs/entities/DeviceTest.java | 104 ---- 28 files changed, 783 insertions(+), 1288 deletions(-) delete mode 100644 src/main/java/jcs/commandStation/entities/DeviceBean.java delete mode 100644 src/main/java/jcs/commandStation/entities/MeasurementBeanOld.java delete mode 100644 src/main/java/jcs/commandStation/marklin/cs3/DeviceJSONParser.java create mode 100644 src/main/java/jcs/commandStation/marklin/parser/CanDeviceJSONParser.java rename src/main/java/jcs/commandStation/marklin/{cs/can/parser/CanDevices.java => parser/CanDeviceParser.java} (97%) create mode 100644 src/test/java/jcs/commandStation/marklin/parser/CanDeviceJSONParserTest.java rename src/test/java/jcs/commandStation/marklin/{cs/can/parser/CanDevicesTest.java => parser/CanDeviceParserTest.java} (96%) rename src/test/java/jcs/commandStation/marklin/{cs/can => parser}/CanMessageTest.java (98%) rename src/test/java/jcs/commandStation/marklin/{cs3/can => }/parser/ChannelDataParserTest.java (99%) delete mode 100644 src/test/java/jcs/entities/DeviceTest.java diff --git a/nb-configuration.xml b/nb-configuration.xml index 5490e808..1b67107a 100644 --- a/nb-configuration.xml +++ b/nb-configuration.xml @@ -1 +1,43 @@ - apache20 true 4 2 4 2 2 none 2 2 true 2 200 true none 4 4 8 80 true project all true true LF false \ No newline at end of file + + + + + + apache20 + true + 4 + 2 + 4 + 2 + 2 + none + 2 + 2 + true + 2 + 200 + true + none + 4 + 4 + 8 + 80 + true + project + all + true + true + LF + false + + diff --git a/nbactions.xml b/nbactions.xml index 11d28733..b341619c 100644 --- a/nbactions.xml +++ b/nbactions.xml @@ -88,4 +88,11 @@ checkstyle:check + + CUSTOM-test + test + + test + + diff --git a/pom.xml b/pom.xml index 87a25e6f..0f320d38 100644 --- a/pom.xml +++ b/pom.xml @@ -22,7 +22,7 @@ jar jcs.JCS 21 - true + @@ -295,7 +295,7 @@ maven-surefire-plugin 3.5.2 - true + false -Dfile.encoding=UTF-8 junit.jupiter.execution.parallel.enabled=false diff --git a/src/main/java/jcs/commandStation/AbstractController.java b/src/main/java/jcs/commandStation/AbstractController.java index 0c2777c3..07df81f5 100644 --- a/src/main/java/jcs/commandStation/AbstractController.java +++ b/src/main/java/jcs/commandStation/AbstractController.java @@ -45,7 +45,7 @@ public abstract class AbstractController implements GenericController { protected final List connectionEventListeners; - private final List measurementEventListeners; + protected final List measurementEventListeners; protected ExecutorService executor; diff --git a/src/main/java/jcs/commandStation/DecoderController.java b/src/main/java/jcs/commandStation/DecoderController.java index 4ed96e7d..2cf3e5b7 100644 --- a/src/main/java/jcs/commandStation/DecoderController.java +++ b/src/main/java/jcs/commandStation/DecoderController.java @@ -17,13 +17,11 @@ import java.awt.Image; import java.util.List; -import java.util.Map; import jcs.commandStation.events.LocomotiveDirectionEventListener; import jcs.commandStation.events.LocomotiveFunctionEventListener; import jcs.commandStation.events.LocomotiveSpeedEventListener; import jcs.commandStation.events.MeasurementEventListener; import jcs.commandStation.events.PowerEventListener; -import jcs.entities.ChannelBean; import jcs.entities.LocomotiveBean; import jcs.entities.LocomotiveBean.Direction; @@ -63,8 +61,6 @@ public interface DecoderController extends GenericController { boolean isSupportTrackMeasurements(); - Map getTrackMeasurements(); - void addMeasurementEventListener(MeasurementEventListener listener); void removeMeasurementEventListener(MeasurementEventListener listener); diff --git a/src/main/java/jcs/commandStation/JCSCommandStationImpl.java b/src/main/java/jcs/commandStation/JCSCommandStationImpl.java index 9c5f8c68..2685b2fa 100755 --- a/src/main/java/jcs/commandStation/JCSCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/JCSCommandStationImpl.java @@ -30,8 +30,6 @@ import java.util.Map; import java.util.Objects; import java.util.Set; -import java.util.Timer; -import java.util.TimerTask; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.stream.Collectors; @@ -45,14 +43,12 @@ import jcs.commandStation.events.LocomotiveFunctionEventListener; import jcs.commandStation.events.LocomotiveSpeedEvent; import jcs.commandStation.events.LocomotiveSpeedEventListener; -import jcs.commandStation.events.MeasurementEvent; import jcs.commandStation.events.MeasurementEventListener; import jcs.commandStation.events.PowerEventListener; import jcs.commandStation.events.SensorEvent; import jcs.commandStation.events.SensorEventListener; import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.AccessoryValue; -import jcs.entities.ChannelBean; import jcs.entities.CommandStationBean; import jcs.entities.CommandStationBean.Protocol; import jcs.entities.FunctionBean; @@ -82,7 +78,6 @@ public class JCSCommandStationImpl implements JCSCommandStation { private final List locomotiveDirectionEventListeners; private final List locomotiveSpeedEventListeners; - //private final List measurementEventListeners; private final Set supportedProtocols; private CommandStationBean commandStation; @@ -109,7 +104,6 @@ private JCSCommandStationImpl(boolean autoConnectController) { locomotiveFunctionEventListeners = new LinkedList<>(); locomotiveDirectionEventListeners = new LinkedList<>(); locomotiveSpeedEventListeners = new LinkedList<>(); - //measurementEventListeners = new LinkedList<>(); supportedProtocols = new HashSet<>(); try { @@ -223,7 +217,7 @@ public final boolean connect() { Logger.trace("Connected Controllers: Decoder: " + (decoderControllerConnected ? "Yes" : "No") + " Accessory: " + accessoryCntrConnected + " Feedback: " + feedbackCntrConnected); if (decoderControllerConnected && !allreadyConnected && decoderController != null) { - decoderController.addConnectionEventListener(new DisconnectionListener(this)); + decoderController.addConnectionEventListener(new ConnectionListener(this)); decoderController.addLocomotiveFunctionEventListener(new LocomotiveFunctionChangeEventListener(this)); decoderController.addLocomotiveDirectionEventListener(new LocomotiveDirectionChangeEventListener(this)); @@ -253,7 +247,7 @@ public final boolean connect() { for (AccessoryController ac : accessoryControllers.values()) { if (ac.isConnected()) { ac.addAccessoryEventListener(new AccessoryChangeEventListener(this)); - ac.addConnectionEventListener(new DisconnectionListener(this)); + ac.addConnectionEventListener(new ConnectionListener(this)); } } } @@ -262,7 +256,7 @@ public final boolean connect() { for (FeedbackController fc : feedbackControllers.values()) { if (fc.isConnected()) { fc.addSensorEventListener(new SensorChangeEventListener(this)); - fc.addConnectionEventListener(new DisconnectionListener(this)); + fc.addConnectionEventListener(new ConnectionListener(this)); } } } @@ -949,18 +943,22 @@ public void onSpeedChange(LocomotiveSpeedEvent speedEvent) { } } - private class DisconnectionListener implements ConnectionEventListener { + private class ConnectionListener implements ConnectionEventListener { private final JCSCommandStationImpl jcsCommandStationImpl; - DisconnectionListener(JCSCommandStationImpl jcsCommandStationImpl) { + ConnectionListener(JCSCommandStationImpl jcsCommandStationImpl) { this.jcsCommandStationImpl = jcsCommandStationImpl; } @Override public void onConnectionChange(ConnectionEvent event) { - Logger.trace(event.getSource() + " is Disconnected!"); - jcsCommandStationImpl.disconnect(); + if (event.isConnected()) { + Logger.trace(event.getSource() + " has re-connected!"); + } else { + Logger.trace(event.getSource() + " is Disconnected!"); + //jcsCommandStationImpl.disconnect(); + } } } diff --git a/src/main/java/jcs/commandStation/dccex/DccExCommandStationImpl.java b/src/main/java/jcs/commandStation/dccex/DccExCommandStationImpl.java index 3c5d6731..e66ccf45 100644 --- a/src/main/java/jcs/commandStation/dccex/DccExCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/dccex/DccExCommandStationImpl.java @@ -16,9 +16,7 @@ package jcs.commandStation.dccex; import java.awt.Image; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.concurrent.Executors; import jcs.JCS; import jcs.commandStation.AbstractController; @@ -41,15 +39,12 @@ import jcs.commandStation.events.PowerEventListener; import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.AccessoryValue; -import jcs.entities.ChannelBean; import jcs.entities.CommandStationBean; import jcs.entities.CommandStationBean.ConnectionType; -import jcs.commandStation.entities.DeviceBean; import jcs.entities.FunctionBean; import jcs.commandStation.entities.InfoBean; import jcs.entities.LocomotiveBean; import jcs.entities.LocomotiveBean.Direction; -import jcs.util.KeyValuePair; import jcs.util.SerialPortUtil; import org.tinylog.Logger; import jcs.commandStation.events.ConnectionEventListener; @@ -61,7 +56,7 @@ public class DccExCommandStationImpl extends AbstractController implements Decod //private DeviceBean mainDevice; private boolean powerStatusSet = false; - Map measurementChannels; + //Map measurementChannels; public DccExCommandStationImpl(CommandStationBean commandStationBean) { this(commandStationBean, false); @@ -69,7 +64,7 @@ public DccExCommandStationImpl(CommandStationBean commandStationBean) { public DccExCommandStationImpl(CommandStationBean commandStationBean, boolean autoConnect) { super(autoConnect, commandStationBean); - measurementChannels = new HashMap<>(); + //measurementChannels = new HashMap<>(); this.executor = Executors.newCachedThreadPool(); if (commandStationBean != null) { @@ -82,25 +77,25 @@ public DccExCommandStationImpl(CommandStationBean commandStationBean, boolean au } } - private void initMeasurements() { - //Prepare the measurements as far as I know DCC-EX has only track current for both PROG and MAIN - String response = connection.sendMessage(DccExMessageFactory.trackManagerConfigRequest()); - if (response != null) { - DccExMeasurementEvent crq = new DccExMeasurementEvent(response); - handleMeasurement(crq); - } - response = connection.sendMessage(DccExMessageFactory.maxCurrentRequest()); - if (response != null) { - DccExMeasurementEvent mcrq = new DccExMeasurementEvent(response); - handleMeasurement(mcrq); - } - - response = this.connection.sendMessage(DccExMessageFactory.currentStatusRequest()); - if (response != null) { - DccExMeasurementEvent csrq = new DccExMeasurementEvent(response); - handleMeasurement(csrq); - } - } +// private void initMeasurements() { +// //Prepare the measurements as far as I know DCC-EX has only track current for both PROG and MAIN +// String response = connection.sendMessage(DccExMessageFactory.trackManagerConfigRequest()); +// if (response != null) { +// DccExMeasurementEvent crq = new DccExMeasurementEvent(response); +// handleMeasurement(crq); +// } +// response = connection.sendMessage(DccExMessageFactory.maxCurrentRequest()); +// if (response != null) { +// DccExMeasurementEvent mcrq = new DccExMeasurementEvent(response); +// handleMeasurement(mcrq); +// } +// +// response = this.connection.sendMessage(DccExMessageFactory.currentStatusRequest()); +// if (response != null) { +// DccExMeasurementEvent csrq = new DccExMeasurementEvent(response); +// handleMeasurement(csrq); +// } +// } @Override public final boolean connect() { @@ -243,7 +238,7 @@ public final boolean connect() { Logger.trace(response); } - initMeasurements(); + //initMeasurements(); //Logger.trace("Connected with: " + (this.mainDevice != null ? this.mainDevice.getName() : "Unknown")); JCS.logProgress("Power is " + (this.power ? "On" : "Off")); } else { @@ -331,16 +326,6 @@ public void changeFunctionValue(int address, int functionNumber, boolean flag) { } } - //Direct approach no feed back... - //maybe register the accessories and then via id? -// @Override -// public void switchAccessory(Integer address, AccessoryValue value) { -// switchAccessory(address, value, null); -// } -// @Override -// public void switchAccessory(Integer address, AccessoryValue value, Integer switchTime) { -// switchAccessory(address, "dcc", value, switchTime); -// } @Override public void switchAccessory(Integer address, String protocol, AccessoryValue value, Integer switchTime) { if (this.power && this.connected) { @@ -389,16 +374,6 @@ public List getAccessories() { throw new UnsupportedOperationException("Not supported yet."); } -// @Override -// public DeviceBean getDevice() { -// return this.mainDevice; -// } -// @Override -// public List getDevices() { -// List devices = new ArrayList<>(); -// devices.add(this.mainDevice); -// return devices; -// } @Override public InfoBean getCommandStationInfo() { return this.infoBean; @@ -406,19 +381,18 @@ public InfoBean getCommandStationInfo() { @Override public boolean isSupportTrackMeasurements() { - return true; + return false; // true; } - @Override - public Map getTrackMeasurements() { - //Measure the currents - if (connected) { - this.connection.sendMessage(DccExMessageFactory.currentStatusRequest()); - //TODO depends a bit on the connection SERIAL or NETWORK - this.pause(50); - } - return this.measurementChannels; - } +// public Map getTrackMeasurements() { +// //Measure the currents +// if (connected) { +// this.connection.sendMessage(DccExMessageFactory.currentStatusRequest()); +// //TODO depends a bit on the connection SERIAL or NETWORK +// this.pause(50); +// } +// return this.measurementChannels; +// } private void fireAllDisconnectionEventListeners(final ConnectionEvent disconnectionEvent) { for (ConnectionEventListener listener : this.connectionEventListeners) { @@ -491,75 +465,75 @@ private void fireAllAccessoryEventListeners(final AccessoryEvent accessoryEvent) } } - private void handleMeasurement(DccExMeasurementEvent measurementEvent) { - if ("=".equals(measurementEvent.getOpcode())) { - // config - KeyValuePair track = measurementEvent.getTrack(); - if (track != null && "A".equals(track.getKey())) { - //Main, or channel 1 - ChannelBean main = this.measurementChannels.get(1); - if (main == null) { - main = new ChannelBean(); - measurementChannels.put(1, main); - } - main.setName(track.getValue()); - main.setNumber(1); - main.setUnit("mA"); - main.setStartValue(0.0); - main.setScale(1000); - main.setHumanValue(0.0); - main.setValue(0); - } else if (track != null && "B".equals(track.getKey())) { - //Prog, or channel 0 - ChannelBean prog = this.measurementChannels.get(0); - if (prog == null) { - prog = new ChannelBean(); - measurementChannels.put(0, prog); - } - prog.setName(track.getValue()); - prog.setNumber(0); - prog.setUnit("mA"); - prog.setStartValue(0.0); - prog.setScale(1000); - prog.setHumanValue(0.0); - prog.setValue(0); - } - } else if ("j".equals(measurementEvent.getOpcode())) { - if (measurementEvent.isMeasurement()) { - ChannelBean main = this.measurementChannels.get(1); - if (main == null) { - main = new ChannelBean(); - measurementChannels.put(1, main); - } - main.setValue(measurementEvent.getCurrentMain()); - main.setHumanValue((double) measurementEvent.getCurrentMain()); - - ChannelBean prog = this.measurementChannels.get(0); - if (prog == null) { - prog = new ChannelBean(); - measurementChannels.put(0, prog); - } - prog.setValue(measurementEvent.getCurrentProg()); - prog.setHumanValue((double) measurementEvent.getCurrentProg()); - } else { - ChannelBean main = this.measurementChannels.get(1); - if (main == null) { - main = new ChannelBean(); - measurementChannels.put(1, main); - } - main.setRangeMax(measurementEvent.getCurrentMainMax()); - main.setEndValue((double) measurementEvent.getCurrentMainMax()); - - ChannelBean prog = this.measurementChannels.get(0); - if (prog == null) { - prog = new ChannelBean(); - measurementChannels.put(0, prog); - } - prog.setRangeMax(measurementEvent.getCurrentProgMax()); - prog.setEndValue((double) measurementEvent.getCurrentProgMax()); - } - } - } +// private void handleMeasurement(DccExMeasurementEvent measurementEvent) { +// if ("=".equals(measurementEvent.getOpcode())) { +// // config +// KeyValuePair track = measurementEvent.getTrack(); +// if (track != null && "A".equals(track.getKey())) { +// //Main, or channel 1 +// ChannelBean main = this.measurementChannels.get(1); +// if (main == null) { +// main = new ChannelBean(); +// measurementChannels.put(1, main); +// } +// main.setName(track.getValue()); +// main.setNumber(1); +// main.setUnit("mA"); +// main.setStartValue(0.0); +// main.setScale(1000); +// main.setHumanValue(0.0); +// main.setValue(0); +// } else if (track != null && "B".equals(track.getKey())) { +// //Prog, or channel 0 +// ChannelBean prog = this.measurementChannels.get(0); +// if (prog == null) { +// prog = new ChannelBean(); +// measurementChannels.put(0, prog); +// } +// prog.setName(track.getValue()); +// prog.setNumber(0); +// prog.setUnit("mA"); +// prog.setStartValue(0.0); +// prog.setScale(1000); +// prog.setHumanValue(0.0); +// prog.setValue(0); +// } +// } else if ("j".equals(measurementEvent.getOpcode())) { +// if (measurementEvent.isMeasurement()) { +// ChannelBean main = this.measurementChannels.get(1); +// if (main == null) { +// main = new ChannelBean(); +// measurementChannels.put(1, main); +// } +// main.setValue(measurementEvent.getCurrentMain()); +// main.setHumanValue((double) measurementEvent.getCurrentMain()); +// +// ChannelBean prog = this.measurementChannels.get(0); +// if (prog == null) { +// prog = new ChannelBean(); +// measurementChannels.put(0, prog); +// } +// prog.setValue(measurementEvent.getCurrentProg()); +// prog.setHumanValue((double) measurementEvent.getCurrentProg()); +// } else { +// ChannelBean main = this.measurementChannels.get(1); +// if (main == null) { +// main = new ChannelBean(); +// measurementChannels.put(1, main); +// } +// main.setRangeMax(measurementEvent.getCurrentMainMax()); +// main.setEndValue((double) measurementEvent.getCurrentMainMax()); +// +// ChannelBean prog = this.measurementChannels.get(0); +// if (prog == null) { +// prog = new ChannelBean(); +// measurementChannels.put(0, prog); +// } +// prog.setRangeMax(measurementEvent.getCurrentProgMax()); +// prog.setEndValue((double) measurementEvent.getCurrentProgMax()); +// } +// } +// } private void handleInfoMessage(String message) { //executor.execute(() -> fireAllPowerEventListeners(powerEvent)); @@ -618,21 +592,21 @@ public void onMessage(DccExMessage message) { } case "i" -> { // System information - DeviceBean d = new DeviceBean(); - String[] dccexdev = content.split(" "); - d.setName(content); - for (int i = 0; i < dccexdev.length; i++) { - switch (i) { - case 0 -> - d.setName(dccexdev[i]); - case 1 -> - d.setVersion(dccexdev[i]); - case 5 -> - d.setTypeName(dccexdev[i]); - case 6 -> - d.setSerial(dccexdev[i]); - } - } +// DeviceBean d = new DeviceBean(); +// String[] dccexdev = content.split(" "); +// d.setName(content); +// for (int i = 0; i < dccexdev.length; i++) { +// switch (i) { +// case 0 -> +// d.setName(dccexdev[i]); +// case 1 -> +// d.setVersion(dccexdev[i]); +// case 5 -> +// d.setTypeName(dccexdev[i]); +// case 6 -> +// d.setSerial(dccexdev[i]); +// } +// } // commandStation.mainDevice = d; //Logger.trace("Main Device set to: " + d); } @@ -650,7 +624,7 @@ public void onMessage(DccExMessage message) { } case "j" -> { DccExMeasurementEvent me2 = new DccExMeasurementEvent(opcode, content); - commandStation.handleMeasurement(me2); + //commandStation.handleMeasurement(me2); } case "H" -> { } diff --git a/src/main/java/jcs/commandStation/entities/DeviceBean.java b/src/main/java/jcs/commandStation/entities/DeviceBean.java deleted file mode 100644 index a0754c8b..00000000 --- a/src/main/java/jcs/commandStation/entities/DeviceBean.java +++ /dev/null @@ -1,583 +0,0 @@ -/* - * Copyright 2023 fransjacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.commandStation.entities; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import jcs.commandStation.marklin.cs.can.CanMessage; -import jcs.entities.ChannelBean; -import jcs.util.ByteUtil; -import org.json.JSONArray; -import org.json.JSONObject; -import org.tinylog.Logger; - -/** - * A Device is a Component which "lives" in side a Command Station.
- * It can be a Central Station (Marklin) ECos (ESU) etc. TODO: move away Command station specific code - */ -@Deprecated -public class DeviceBean { - - public static final String MAIN = "MAIN"; - public static final String PROG = "PROG"; - public static final String VOLT = "VOLT"; - public static final String TEMP = "TEMP"; - - public static final String BUS0 = "Auswertung 1 - 16"; - public static final String BUS1 = "Bus 1 (RJ45-1)"; - public static final String BUS2 = "Bus 2 (RJ45-2)"; - public static final String BUS3 = "Bus 3 (6-Polig)"; - - private String uid; - private String name; - private String typeName; - private String identifier; - private String type; - private String articleNumber; - private String serial; - private Integer queryInteval; - private Integer measureChannels; - private Integer configChannels; - - private String version; - private Boolean present; - private Integer available; - private String config; - private Boolean ready; - private String path; - private Boolean mounted; - - private final List channels; - private final Map analogChannels; - private final Map sensorBuses; - - public DeviceBean() { - this((String) null); - } - - public DeviceBean(String json) { - channels = new LinkedList<>(); - analogChannels = new HashMap<>(); - sensorBuses = new HashMap<>(); - - parse(json); - } - - public DeviceBean(CanMessage message) { - channels = new LinkedList<>(); - analogChannels = new HashMap<>(); - sensorBuses = new HashMap<>(); - - if (message != null) { - buildFromMessage(message); - } - } - - public String getUid() { - return uid; - } - - public void setUid(String uid) { - this.uid = uid; - } - - public Integer getUidAsInt() { - String ui = this.uid.replace("0x", ""); - return Integer.parseUnsignedInt(ui, 16); - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getTypeName() { - return typeName; - } - - public void setTypeName(String typeName) { - this.typeName = typeName; - } - - public String getIdentifier() { - return identifier; - } - - public void setIdentifier(String identifier) { - this.identifier = identifier; - } - - @SuppressWarnings("UnnecessaryTemporaryOnConversionFromString") - public Integer getIdentifierAsInt() { - String id = this.identifier.replace("0x", ""); - return Integer.parseInt(id, 16); - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - public String getArticleNumber() { - return articleNumber; - } - - public void setArticleNumber(String articleNumber) { - this.articleNumber = articleNumber; - } - - public String getSerial() { - return serial; - } - - public void setSerial(String serial) { - this.serial = serial; - } - - public Integer getQueryInteval() { - return queryInteval; - } - - public void setQueryInteval(Integer queryInteval) { - this.queryInteval = queryInteval; - } - - public String getVersion() { - return version; - } - - public void setVersion(String version) { - this.version = version; - } - - public Boolean getPresent() { - return present; - } - - public void setPresent(Boolean present) { - this.present = present; - } - - public Integer getAvailable() { - return available; - } - - public void setAvailable(Integer available) { - this.available = available; - } - - public String getConfig() { - return config; - } - - public void setConfig(String config) { - this.config = config; - } - - public Boolean getReady() { - return ready; - } - - public void setReady(Boolean ready) { - this.ready = ready; - } - - public String getPath() { - return path; - } - - public void setPath(String path) { - this.path = path; - } - - public Boolean getMounted() { - return mounted; - } - - public void setMounted(Boolean mounted) { - this.mounted = mounted; - } - - private void parse(String json) { - if (json == null) { - return; - } - JSONObject device = new JSONObject(json); - - this.uid = device.optString("_uid"); - this.name = device.optString("_name"); - this.typeName = device.optString("_typname"); - this.identifier = device.optString("_kennung"); - this.type = device.optString("_typ"); - this.articleNumber = device.optString("_artikelnr"); - this.serial = device.optString("_seriennr"); - this.queryInteval = device.optInt("_queryInterval"); - - JSONObject versionObj = device.optJSONObject("_version"); - if (versionObj != null) { - String major = versionObj.optString("major"); - String minor = versionObj.optString("minor"); - this.version = (major != null ? major : "") + (major != null ? "." : "") + (minor != null ? minor : ""); - } - - this.present = device.optBoolean("isPresent"); - this.available = device.optInt("present"); - this.config = device.optString("config"); - this.ready = device.optBoolean("_ready"); - this.path = device.optString("path"); - this.mounted = device.optBoolean("isMounted"); - - JSONArray channelsJA = device.optJSONArray("_kanal"); - if (channelsJA != null) { - for (int i = 0; i < channelsJA.length(); i++) { - JSONObject kanal = channelsJA.getJSONObject(i); - - ChannelBean cb = new ChannelBean(kanal.toString()); - this.channels.add(cb); - String n = cb.getName(); - if (n != null) { - switch (n) { - case MAIN -> - this.analogChannels.put(MAIN, cb); - case PROG -> - this.analogChannels.put(PROG, cb); - case TEMP -> - this.analogChannels.put(TEMP, cb); - case VOLT -> - this.analogChannels.put(VOLT, cb); - } - if ((n.contains(BUS0) || n.contains(BUS1) || n.contains(BUS2) || n.contains(BUS3)) && cb.isS88Bus()) { - Integer busNr = cb.getNumber() - 1; - this.sensorBuses.put(busNr, cb); - } - - } - } - } - } - - private void buildFromMessage(CanMessage message) { - CanMessage resp; - if (!message.isResponseMessage() && !message.getResponses().isEmpty()) { - resp = message.getResponse(); - } else { - resp = message; - } - - if (CanMessage.PING_RESP == resp.getCommand() && CanMessage.DLC_8 == resp.getDlc()) { - byte[] data = resp.getData(); - - byte[] uida = new byte[4]; - System.arraycopy(data, 0, uida, 0, uida.length); - - byte[] vera = new byte[2]; - System.arraycopy(data, 4, vera, 0, vera.length); - - byte[] deva = new byte[2]; - System.arraycopy(data, 6, deva, 0, deva.length); - - int uidAsInt = resp.getDeviceUidNumberFromMessage(); - uid = "0x" + Integer.toHexString(uidAsInt); - - //this.uid = resp.getDeviceUidNumberFromMessage(); - //TODO: Version is not same displayed in the CS - version = "" + CanMessage.toInt(vera); - //TODO: in case of a Link S88 it is offset by 1 so device ID + 1 - - int identifierAsInt = CanMessage.toInt(deva); - identifier = "0x" + Integer.toHexString(identifierAsInt); - //this.identifier = CanMessage.toInt(deva); - } - } - - public void updateFromMessage(CanMessage message) { - //Filter the responses - List responses = new ArrayList<>(message.getResponses().size()); - for (CanMessage resp : message.getResponses()) { - if (CanMessage.STATUS_CONFIG_RESP == resp.getCommand()) { - responses.add(resp); - } - } - if (!responses.isEmpty()) { - //The last response has the total response messages - CanMessage last = responses.get(responses.size() - 1); - int packets = 0; - - if (last.getDlc() == CanMessage.DLC_6) { - packets = last.getDataByte(5); - } else if (last.getDlc() == CanMessage.DLC_5) { - //CS-2 lets assume the number packets to be the size - packets = responses.size() - 1; - } - if (responses.size() - 1 != packets) { - Logger.warn("Config Data might be invalid. Packages expected: " + packets + " received: " + (responses.size() - 1)); - Logger.trace(message); - for (CanMessage m : responses) { - Logger.trace(m); - } - } else { - //Reset the device name - name = ""; - } - - for (int i = 0; i < responses.size(); i++) { - CanMessage msg = responses.get(i); - byte[] data = msg.getData(); - int packageNr = msg.getPackageNumber(); - - switch (i) { - case 0 -> { - if (CanMessage.DLC_5 == msg.getDlc()) { - } else if (CanMessage.DLC_8 == msg.getDlc()) { - //first packet? - if (packageNr == 1) { - //TODO! - int measureChannels = data[0]; - int configChannels = data[1]; - byte[] sn = new byte[2]; - System.arraycopy(data, 6, sn, 0, sn.length); - int serialnr = ((sn[0]) << 8) | (sn[1]); - serial = serialnr + ""; - } - } - } - case 1 -> { - if (CanMessage.DLC_8 == msg.getDlc()) { - if (packageNr == 2) { - //Article - articleNumber = ByteUtil.bytesToString(data); - articleNumber = articleNumber.trim(); - } - } - } - default -> { - if (CanMessage.DLC_8 == msg.getDlc()) { - String s = CanMessage.toString(data); - if (s != null && s.length() > 0) { - name = name + s; - } - - if (packageNr == packets) { - name = name.trim(); - } - } - } - } - } - } - } - - public boolean isDataComplete() { - return name != null && name.length() > 2 && articleNumber != null && articleNumber.length() > 4; - } - - public String getDevice() { - return switch (getIdentifierAsInt()) { - case 0x0000 -> - "GFP"; - case 0x0010 -> - "Gleisbox 60112 und 60113"; - case 0x0020 -> - "Connect 6021 Art-Nr.60128"; - case 0x0030 -> - "MS 2 60653, Txxxxx"; - case 0x0040 -> - "Link-S88"; - case 0xffe0 -> - "Wireless Devices"; - case 0xffff -> - "CS2/3-GUI (Master)"; - default -> - "Unknown " + this.name; - }; - } - - public List getChannels() { - return channels; - } - - public void addChannel(ChannelBean channel) { - this.channels.add(channel); - } - - public Map getAnalogChannels() { - return analogChannels; - } - - public void setAnalogChannel(ChannelBean channel) { - if (channel == null) { - return; - } - switch (channel.getName()) { - case MAIN -> - analogChannels.put(MAIN, channel); - case PROG -> - analogChannels.put(PROG, channel); - case VOLT -> - analogChannels.put(VOLT, channel); - case TEMP -> - analogChannels.put(TEMP, channel); - default -> { - } - } - } - - public Map getSensorBuses() { - return this.sensorBuses; - } - - public void addSensorBus(Integer busNr, ChannelBean sensorBus) { - this.sensorBuses.put(busNr, sensorBus); - } - - public int getBusLength(Integer busNr) { - if (this.isFeedbackDevice()) { - ChannelBean cb = this.sensorBuses.get(busNr); - if (cb != null) { - if (busNr == 0) { - return 1; - } else { - return cb.getValue(); - } - } else { - return 0; - } - } else { - return -1; - } - } - - public Integer getLinkS88ContactIdOffset(int busNr) { - return (busNr - 1) * 1000; - } - - public boolean isFeedbackDevice() { - return "Link S88".equals(typeName); - } - - @Override - public int hashCode() { - int hash = 3; - hash = 97 * hash + Objects.hashCode(this.uid); - hash = 97 * hash + Objects.hashCode(this.name); - hash = 97 * hash + Objects.hashCode(this.typeName); - hash = 97 * hash + Objects.hashCode(this.identifier); - hash = 97 * hash + Objects.hashCode(this.type); - hash = 97 * hash + Objects.hashCode(this.articleNumber); - hash = 97 * hash + Objects.hashCode(this.serial); - hash = 97 * hash + Objects.hashCode(this.queryInteval); - hash = 97 * hash + Objects.hashCode(this.version); - hash = 97 * hash + Objects.hashCode(this.present); - hash = 97 * hash + Objects.hashCode(this.available); - hash = 97 * hash + Objects.hashCode(this.config); - hash = 97 * hash + Objects.hashCode(this.ready); - hash = 97 * hash + Objects.hashCode(this.path); - hash = 97 * hash + Objects.hashCode(this.mounted); - return hash; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final DeviceBean other = (DeviceBean) obj; - if (!Objects.equals(this.name, other.name)) { - return false; - } - if (!Objects.equals(this.typeName, other.typeName)) { - return false; - } - if (!Objects.equals(this.type, other.type)) { - return false; - } - if (!Objects.equals(this.articleNumber, other.articleNumber)) { - return false; - } - if (!Objects.equals(this.serial, other.serial)) { - return false; - } - if (!Objects.equals(this.version, other.version)) { - return false; - } - if (!Objects.equals(this.config, other.config)) { - return false; - } - if (!Objects.equals(this.path, other.path)) { - return false; - } - if (!Objects.equals(this.uid, other.uid)) { - return false; - } - if (!Objects.equals(this.identifier, other.identifier)) { - return false; - } - if (!Objects.equals(this.queryInteval, other.queryInteval)) { - return false; - } - if (!Objects.equals(this.present, other.present)) { - return false; - } - if (!Objects.equals(this.available, other.available)) { - return false; - } - if (!Objects.equals(this.ready, other.ready)) { - return false; - } - return Objects.equals(this.mounted, other.mounted); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("DeviceBean{"); - sb.append("uid=").append(uid); - sb.append(", name=").append(name); - sb.append(", typeName=").append(typeName); - sb.append(", identifier=").append(identifier); - sb.append(", type=").append(type); - sb.append(", articleNumber=").append(articleNumber); - sb.append(", serial=").append(serial); - sb.append(", queryInteval=").append(queryInteval); - sb.append(", version=").append(version); - sb.append(", present=").append(present); - sb.append(", available=").append(available); - sb.append(", config=").append(config); - sb.append(", ready=").append(ready); - sb.append(", path=").append(path); - sb.append(", mounted=").append(mounted); - sb.append(", channels:").append(channels.size()); - sb.append("}"); - return sb.toString(); - } - -} diff --git a/src/main/java/jcs/commandStation/entities/MeasuredChannels.java b/src/main/java/jcs/commandStation/entities/MeasuredChannels.java index d333b44a..d065c2d6 100644 --- a/src/main/java/jcs/commandStation/entities/MeasuredChannels.java +++ b/src/main/java/jcs/commandStation/entities/MeasuredChannels.java @@ -37,13 +37,13 @@ public MeasuredChannels() { public MeasuredChannels(long measurementTime) { this.measurementTime = measurementTime; } - + public long getMeasurementTime() { return measurementTime; } public void addMeasurement(MeasurementBean measurement) { - switch(measurement.getName()) { + switch (measurement.getName()) { case "MAIN" -> this.main = measurement; case "PROG" -> @@ -53,10 +53,10 @@ public void addMeasurement(MeasurementBean measurement) { case "TEMP" -> this.temp = measurement; default -> - Logger.error("Unknown measurement "+measurement); + Logger.error("Unknown measurement " + measurement); } } - + public MeasurementBean getMain() { return main; } @@ -113,7 +113,36 @@ public boolean equals(Object obj) { @Override public String toString() { - return "MeasuredChanels{" + "measurementTime=" + new Date(measurementTime) + ", main=" + main.getDisplayValue() + " " + main.getUnit() + ", prog=" + prog.getDisplayValue() + " " + prog.getUnit() + ", volt=" + volt.getDisplayValue() + " " + volt.getUnit() + ", temp=" + temp.getDisplayValue() + " " + temp.getUnit() + "}"; + StringBuilder sb = new StringBuilder(); + sb.append("MeasuredChanels{measurementTime="); + sb.append(new Date(measurementTime)); + if (main != null) { + sb.append(", MAIN="); + sb.append(main.getDisplayValue()); + sb.append(" "); + sb.append(main.getUnit()); + } + if (prog != null) { + sb.append(", PROG="); + sb.append(prog.getDisplayValue()); + sb.append(" "); + sb.append(prog.getUnit()); + } + if (volt != null) { + sb.append(", VOLT="); + sb.append(volt.getDisplayValue()); + sb.append(" "); + sb.append(volt.getUnit()); + } + if (temp != null) { + sb.append(", TEMP="); + sb.append(temp.getDisplayValue()); + sb.append(" "); + sb.append(temp.getUnit()); + } + sb.append("}"); + + return sb.toString(); } } diff --git a/src/main/java/jcs/commandStation/entities/MeasurementBeanOld.java b/src/main/java/jcs/commandStation/entities/MeasurementBeanOld.java deleted file mode 100644 index 6409d84c..00000000 --- a/src/main/java/jcs/commandStation/entities/MeasurementBeanOld.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2025 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.commandStation.entities; - -import java.util.Date; - -/** - * Object to hold measured values - */ -@Deprecated -public class MeasurementBeanOld { - - private String name; - private Double value; - private String unit; - private Date measurementTime; - - private String selection; - private String config; - private Double endValue; - private Integer colorYellow; - private Integer colorGreen; - private Integer colorMax; - private Integer colorRed; - private Integer index; - private Boolean present; - private Integer min; - private Integer max; - private Integer number; - private Boolean ready; - private Integer rangeYellow; - private Integer rangeGreen; - private Integer rangeMax; - private Integer rangeRed; - private Integer scale; - private Double startValue; - private Integer type; - private Integer previousValue; - private Double humanValue; - -} diff --git a/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java b/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java index 6fba24a6..777e4e1f 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java @@ -21,7 +21,6 @@ import java.net.InetAddress; import java.util.ArrayList; import java.util.List; -import java.util.Map; import java.util.concurrent.Executors; import java.util.concurrent.TransferQueue; import jcs.JCS; @@ -36,9 +35,7 @@ import jcs.commandStation.events.PowerEventListener; import jcs.commandStation.events.SensorEvent; import jcs.entities.AccessoryBean; -import jcs.entities.ChannelBean; import jcs.entities.CommandStationBean; -import jcs.commandStation.entities.DeviceBean; import jcs.entities.FeedbackModuleBean; import jcs.commandStation.entities.InfoBean; import jcs.commandStation.esu.ecos.net.EcosHTTPConnection; @@ -474,24 +471,6 @@ public boolean isSupportTrackMeasurements() { return false; } - @Override - public Map getTrackMeasurements() { - throw new UnsupportedOperationException("Not supported yet."); - } - -// @Override -// public void switchAccessory(Integer address, AccessoryBean.AccessoryValue value) { -// switchAccessory(address, value, defaultSwitchTime); -// } -// @Override -// public void switchAccessory(Integer address, AccessoryBean.AccessoryValue value, Integer switchTime) { -// AccessoryBean ab = accessoryManager.getAccessory(address); -// if (ab != null) { -// switchAccessory(ab.getId(), value); -// } else { -// Logger.warn("Accessory with address " + address + " does not exist for the Ecos"); -// } -// } @Override public void switchAccessory(Integer address, String protocol, AccessoryBean.AccessoryValue value, Integer switchTime) { Logger.trace("Using Address " + address + " to find the AccessoryId..."); diff --git a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java index 29991350..185a25b2 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java +++ b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java @@ -59,7 +59,6 @@ import jcs.commandStation.marklin.cs3.LocomotiveBeanJSONParser; import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.AccessoryValue; -import jcs.entities.ChannelBean; import jcs.entities.CommandStationBean; import jcs.commandStation.entities.InfoBean; import jcs.commandStation.marklin.cs.can.parser.AccessoryMessage; @@ -76,7 +75,7 @@ import jcs.commandStation.events.ConnectionEvent; import jcs.commandStation.marklin.cs.can.device.ConfigChannel; import jcs.commandStation.marklin.cs.can.device.MeasuringChannel; -import jcs.commandStation.marklin.cs.can.parser.CanDevices; +import jcs.commandStation.marklin.parser.CanDeviceParser; import jcs.commandStation.marklin.cs.can.parser.LocomotiveEmergencyStopMessage; import jcs.entities.LocomotiveBean; import jcs.entities.LocomotiveBean.Direction; @@ -87,6 +86,9 @@ import jcs.commandStation.marklin.parser.GeraetParser; import jcs.commandStation.marklin.parser.SystemStatusMessage; import jcs.commandStation.events.ConnectionEventListener; +import jcs.commandStation.events.MeasurementEvent; +import jcs.commandStation.events.MeasurementEventListener; +import jcs.commandStation.marklin.parser.CanDeviceJSONParser; /** * @@ -184,27 +186,45 @@ public final synchronized boolean connect() { } if (connected) { - canBootLoaderLastCallMillis = System.currentTimeMillis(); - - JCS.logProgress("Obtaining Device information..."); CanDevice gfp = getGFP(); - csUid = Integer.parseUnsignedInt(gfp.getUid(), 16); - canDevices.put(gfp.getUidInt(), gfp); + csUid = gfp.getUidInt(); //Integer.parseUnsignedInt(gfp.getUid().replace("0x", ""), 16); - obtainDevices(); - infoBean = createInfoBean(canDevices); + canBootLoaderLastCallMillis = System.currentTimeMillis(); + + JCS.logProgress("Obtaining Device information..."); + if (virtual) { + List devices = getCS3Devices(); + for (CanDevice device : devices) { + if (CanDeviceJSONParser.GFP.equals(device.getName())) { + canDevices.put(device.getUidInt(), device); + } + } + } else { + csUid = Integer.parseUnsignedInt(gfp.getUid(), 16); + obtainDevices(); + } //The eventMessageHandler Thread is in charge to handle all event messages which are send from the CS to JCS eventMessageHandler = new EventMessageHandler(connection); eventMessageHandler.start(); - Logger.trace("Connected to " + infoBean.getProductName() + ", " + infoBean.getArticleNumber() + " SerialNumber: " + infoBean.getSerialNumber()); - csConnection.addDisconnectionEventListener(this); startWatchdog(); + power = isPower(); JCS.logProgress("Power is " + (power ? "On" : "Off")); + +// if (gfp.getMeasureChannelCount() != null && gfp.getMeasureChannelCount() > 0) { +// Logger.trace("Measurements are possible..."); +// } +// else { +// queryDevice(gfp); +// Logger.trace("GFP Measurement Count: " + gfp.getMeasureChannelCount()); +// } + startMeasurements(); + + Logger.trace("Connected to " + gfp.getName() + ", " + gfp.getArticleNumber() + " SerialNumber: " + gfp.getSerial()); } } else { Logger.warn("Can't connect with Central Station!"); @@ -228,17 +248,6 @@ CanDevice getGFP() { CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(virtual); String geraet = httpCon.getInfoFile(); CanDevice gfp = GeraetParser.parseFile(geraet); - csUid = Integer.parseUnsignedInt(gfp.getUid(), 16); - -// //CS3? -// if ("60126".equals(ib.getArticleNumber()) || "60226".equals(ib.getArticleNumber())) { -// String json = httpCon.getInfoJSON(); -// ib = GeraetParser.parseJson(json); -// httpCon.setCs3(true); -// } -// if (ib.getIpAddress() == null) { -// ib.setIpAddress(connection.getControllerAddress().getHostAddress()); -// } return gfp; } @@ -255,8 +264,8 @@ InfoBean createInfoBean(Map canDevices) { switch (name) { case "Central Station 3" -> { ib.setGfpUid(d.getUid()); - String uid = d.getUid(); - uid = uid.replace("0x", ""); + //String uid = d.getUid(); + //uid = uid.replace("0x", ""); //csUid = Integer.parseUnsignedInt(uid, 16); Logger.trace("GFP uid: " + d.getUid() + " -> " + csUid); @@ -264,9 +273,9 @@ InfoBean createInfoBean(Map canDevices) { ib.setProductName(d.getName()); ib.setSerialNumber(d.getSerial()); ib.setHardwareVersion(d.getVersion()); - ib.setSupportMeasurements(d.getMeasureChannelCount() > 0); + //ib.setSupportMeasurements(d.getMeasureChannelCount() > 0); - //TODO: Only CS 2 and CS3 plus... + //TODO: Only CS 2 and CS3 plus...? //ib.setFeedbackBus0ModuleCount(0); //ib.setFeedbackSupport(true); //Is the System property still needed? @@ -277,6 +286,17 @@ InfoBean createInfoBean(Map canDevices) { //System.setProperty("cs.cs3", (isCS3() ? "true" : "false")); //} } + case "GFP3-1" -> { + //Virtual + ib.setGfpUid(d.getUid()); + Logger.trace("GFP uid: " + d.getUid() + " -> " + csUid); + + ib.setArticleNumber(d.getArticleNumber()); + ib.setProductName(d.getName()); + ib.setSerialNumber(d.getSerial()); + ib.setHardwareVersion(d.getVersion()); + //ib.setSupportMeasurements(d.getMeasureChannelCount() > 0); + } case "Link S88" -> { ib.setFeedbackSupport(true); ConfigChannel bus1 = d.getConfigChannel(2); @@ -302,11 +322,10 @@ InfoBean createInfoBean(Map canDevices) { * Obtain information about the connected CAN Device in the Central Station */ void obtainDevices() { - //Map members = new HashMap<>(); CanMessage msg = CanMessageFactory.getMembersPing(); connection.sendCanMessage(msg); - List devices = CanDevices.parse(msg); + List devices = CanDeviceParser.parse(msg); Logger.trace("Found " + devices.size() + " CANDevices"); for (CanDevice d : devices) { if (!canDevices.containsKey(d.getUidInt())) { @@ -340,43 +359,53 @@ void obtainDevices() { //Lets get some info about these members for (CanDevice device : canDevices.values()) { - Logger.trace("Obtaining data for device " + device); - CanMessage updateMessage = sendMessage(CanMessageFactory.statusDataConfig(device.getUidInt(), 0)); - if (updateMessage.hasValidResponse()) { - CanDevices.parse(device, updateMessage); - - int measurementChannels; - if (device.getMeasureChannelCount() == null) { - measurementChannels = 0; - } else { - measurementChannels = device.getMeasureChannelCount(); - } - int configChannels; - if (device.getConfigChannelCount() == null) { - configChannels = 0; - } else { - configChannels = device.getConfigChannelCount(); - } + queryDevice(device); + } + } - int channels = measurementChannels + configChannels; - if (channels > 0) { - Logger.trace("Quering " + channels + " channels for device " + device); - for (int index = 1; index <= channels; index++) { - Logger.trace("Query channel " + index); - updateMessage = sendMessage(CanMessageFactory.statusDataConfig(device.getUidInt(), index)); - CanDevices.parse(device, updateMessage); - - if (index <= measurementChannels) { - Logger.trace("M#" + index + "; " + device.getMeasuringChannel(index)); - } else { - int configChannelNumber = index - measurementChannels; - Logger.trace("C#" + configChannelNumber + "; " + device.getConfigChannel(configChannelNumber)); - } + void queryDevice(CanDevice device) { + Logger.trace("Query for information about device " + device); + CanMessage updateMessage = sendMessage(CanMessageFactory.statusDataConfig(device.getUidInt(), 0)); + + if (!updateMessage.hasValidResponse() && device.getGuiUid() != null) { + Logger.trace("Trying fallback " + device.getGuiUid()); + updateMessage = sendMessage(CanMessageFactory.statusDataConfig(device.getGuiUidInt(), 0)); + } + + if (updateMessage.hasValidResponse()) { + CanDeviceParser.parse(device, updateMessage); + + int measurementChannels; + if (device.getMeasureChannelCount() == null) { + measurementChannels = 0; + } else { + measurementChannels = device.getMeasureChannelCount(); + } + int configChannels; + if (device.getConfigChannelCount() == null) { + configChannels = 0; + } else { + configChannels = device.getConfigChannelCount(); + } + + int channels = measurementChannels + configChannels; + if (channels > 0) { + Logger.trace("Quering " + channels + " channels for device " + device); + for (int index = 1; index <= channels; index++) { + Logger.trace("Query channel " + index); + updateMessage = sendMessage(CanMessageFactory.statusDataConfig(device.getUidInt(), index)); + CanDeviceParser.parse(device, updateMessage); + + if (index <= measurementChannels) { + Logger.trace("M#" + index + "; " + device.getMeasuringChannel(index)); + } else { + int configChannelNumber = index - measurementChannels; + Logger.trace("C#" + configChannelNumber + "; " + device.getConfigChannel(configChannelNumber)); } } - } else { - Logger.trace("No response data in query for " + device); } + } else { + Logger.trace("No response data in query for " + device); } } @@ -387,35 +416,19 @@ void obtainDevices() { * Most important is the GFP which is the heart of the CS 3 most CAN Commands need the GFP UID.
* This data can also be obtained using the CAN Member PING command, but The JSON gives a little more detail. */ -// private void getAppDevicesCs3() { -// CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(virtual); -// -// String devJson = httpCon.getDevicesJSON(); -// List devs = DeviceJSONParser.parse(devJson); -// //Update the devices -// for (DeviceBean d : devs) { -// if (devices.containsKey(d.getUidAsInt())) { -// devices.put(d.getUidAsInt(), d); -// } else { -// devices.put(d.getUidAsInt(), d); -// } -// String an = d.getArticleNumber(); -// if ("60213".equals(an) || "60214".equals(an) || "60215".equals(an) || "60126".equals(an) || "60226".equals(an)) { -// csUid = d.getUidAsInt(); -// mainDevice = d; -// Logger.trace("MainDevice: " + d.getName()); -// } -// -// if ("60883".equals(an)) { -// feedbackDevice = d; -// Logger.trace("FeedbackDevice: " + d.getName()); -// } -// -// } -// Logger.trace("Found " + devices.size() + " devices"); -// } + private List getCS3Devices() { + CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(virtual); + + String devJson = httpCon.getDevicesJSON(); + List devices = CanDeviceJSONParser.parse(devJson); + return devices; + } + @Override public InfoBean getCommandStationInfo() { + if (infoBean == null) { + infoBean = createInfoBean(canDevices); + } return infoBean; } @@ -465,6 +478,13 @@ public boolean power(boolean on) { @Override public void disconnect() { + //Signal listeners that there are no measurments + MeasuredChannels measuredChannels = new MeasuredChannels(System.currentTimeMillis()); + MeasurementEvent me = new MeasurementEvent(measuredChannels); + for (MeasurementEventListener listener : measurementEventListeners) { + listener.onMeasurement(me); + } + try { if (connection != null) { if (eventMessageHandler != null) { @@ -504,8 +524,12 @@ public void onConnectionChange(ConnectionEvent event) { @Override public boolean isSupportTrackMeasurements() { - CanDevice gfp = canDevices.get(csUid); - return gfp.getMeasureChannelCount() > 0; + if (!virtual) { + CanDevice gfp = canDevices.get(csUid); + return gfp != null && gfp.getMeasureChannelCount() != null && gfp.getMeasureChannelCount() > 0; + } else { + return false; + } } void performMeasurements() { @@ -513,9 +537,6 @@ void performMeasurements() { CanDevice gfp = canDevices.get(csUid); if (gfp != null) { List channels = gfp.getMeasuringChannels(); - - Logger.trace("Take a measurment on " + channels.size() + " channels"); - long now = System.currentTimeMillis(); MeasuredChannels measuredChannels = new MeasuredChannels(now); for (MeasuringChannel channel : channels) { @@ -525,15 +546,19 @@ void performMeasurements() { MeasurementBean measurement = SystemStatusMessage.parse(channel, message, now); measuredChannels.addMeasurement(measurement); //Logger.trace(measurement); - measuredValues.putLast(now, measuredChannels); + measuredValues.put(now, measuredChannels); if (measuredValues.size() > 100) { long first = measuredValues.firstKey(); measuredValues.remove(first); } + + MeasurementEvent me = new MeasurementEvent(measuredChannels); + for (MeasurementEventListener listener : measurementEventListeners) { + listener.onMeasurement(me); + } } - Logger.trace("Measurement: " + measuredChannels); } else { - Logger.warn("No measurable channels avalaible"); + Logger.warn("No measurable channels available"); } } @@ -545,39 +570,6 @@ public MeasuredChannels getLastMeasurment() { return measuredValues.firstEntry().getValue(); } - @Override - public synchronized Map getTrackMeasurements() { -// Logger.trace("Perform measurement..."); -// if (connected && mainDevice != null) { -// //main device -// int nrOfChannels = mainDevice.getAnalogChannels().size(); -// -// ChannelDataParser parser = new ChannelDataParser(); -// -// if (this.analogChannels.isEmpty()) { -// //No channels configured so let do this first -// for (int c = 1; c <= nrOfChannels; c++) { -// Logger.trace("Quering config for channel " + c); -// CanMessage message = sendMessage(CanMessageFactory.statusDataConfig(csUid, c)); -// -// ChannelBean ch = parser.parseConfigMessage(message); -// analogChannels.put(c, ch); -// } -// } -// -// for (int c = 1; c <= nrOfChannels; c++) { -// ChannelBean ch = this.analogChannels.get(c); -// if (ch != null) { -// CanMessage message = sendMessage(CanMessageFactory.systemStatus(c, csUid)); -// ch = parser.parseUpdateMessage(message, ch); -// analogChannels.put(c, ch); -// } -// } -// } -// return analogChannels; - return null; - } - /** * Blocking call to the message sender thread which send the message and await the response.
* When there is no response within 1s or 5s timeout the waiting is cancelled.
@@ -587,7 +579,7 @@ public synchronized Map getTrackMeasurements() { * @return the CanMessage with responses */ private CanMessage sendMessage(CanMessage canMessage) { - if (connection != null) { + if (connection != null && connected) { connection.sendCanMessage(canMessage); } else { Logger.warn("NOT connected!"); @@ -610,8 +602,6 @@ public void changeDirection(int locUid, Direction direction) { @Override public void changeVelocity(int locUid, int speed, Direction direction) { if (power && connected) { - //VelocityChange 0x00 0x09 0x03 0x26 0x06 0x00 0x00 0x40 0x0c 0x00 0x30 0x00 0x00 - //16396 CanMessage message = CanMessageFactory.setLocSpeed(locUid, speed, csUid); Logger.trace("Ch Velocity for uid: " + locUid + " -> " + message); message = sendMessage(message); @@ -879,8 +869,13 @@ public void run() { } case CanMessage.PING_RESP -> { if (CanMessage.DLC_8 == dlc) { - //Logger.trace("Ping Response RX: " + eventMessage); - +// Logger.trace("Ping Response RX: " + eventMessage); +// List devices = CanDeviceParser.parse(eventMessage); +// if (!devices.isEmpty()) { +// CanDevice deviceU = devices.get(0); +// CanDevice device = canDevices.get(deviceU.getUidInt()); +// Logger.trace("Found " + device+" GFP "+(csUid==deviceU.getUidInt()?"yes":"no")); +// } //updateDevice(eventMessage); } } @@ -1047,11 +1042,11 @@ private void startMeasurements() { if (measureInterval > 0 && !virtual) { measurementTask = new MeasurementTask(this); - measurementTimer = new Timer("WatchDogTimer"); - measurementTimer.schedule(watchdogTask, 0, measureInterval); - Logger.debug("Started Measurement Timer with an interval of " + measureInterval + "ms"); + measurementTimer = new Timer("MeasurementsTimer"); + measurementTimer.schedule(measurementTask, 10, measureInterval); + Logger.debug("Started Measurements Timer with an interval of " + measureInterval + "ms"); } else { - Logger.debug("Skipping Measurement Timer"); + Logger.debug("Skipping Measurements Timer"); } } @@ -1066,7 +1061,12 @@ private class MeasurementTask extends TimerTask { @Override public void run() { if (commandStation.isConnected() && !virtual) { - commandStation.performMeasurements(); + if (commandStation.isSupportTrackMeasurements()) { + commandStation.performMeasurements(); + } else { + Logger.debug("Track Measurement are not supported. Cancelling the Measurements schedule..."); + measurementTimer.cancel(); + } } } } @@ -1210,7 +1210,7 @@ public static void main(String[] a) { // Logger.trace(loc); // } //cs.pause(40000); - cs.pause(20000); + cs.pause(40000); cs.disconnect(); // cs.pause(100L); Logger.debug("DONE"); diff --git a/src/main/java/jcs/commandStation/marklin/cs/can/device/CanDevice.java b/src/main/java/jcs/commandStation/marklin/cs/can/device/CanDevice.java index e8cb2802..63563d0c 100644 --- a/src/main/java/jcs/commandStation/marklin/cs/can/device/CanDevice.java +++ b/src/main/java/jcs/commandStation/marklin/cs/can/device/CanDevice.java @@ -20,7 +20,6 @@ import java.util.List; import java.util.Map; import java.util.Objects; -import jcs.commandStation.marklin.cs.can.CanMessage; /** * A CanDevice is a Device inside or connected to the Marklin Central Station
@@ -31,16 +30,14 @@ */ public class CanDevice { - public static final String MAIN = "MAIN"; - public static final String PROG = "PROG"; - public static final String VOLT = "VOLT"; - public static final String TEMP = "TEMP"; - - public static final String BUS0 = "Auswertung 1 - 16"; - public static final String BUS1 = "Bus 1 (RJ45-1)"; - public static final String BUS2 = "Bus 2 (RJ45-2)"; - public static final String BUS3 = "Bus 3 (6-Polig)"; - +// public static final String MAIN = "MAIN"; +// public static final String PROG = "PROG"; +// public static final String VOLT = "VOLT"; +// public static final String TEMP = "TEMP"; +// public static final String BUS0 = "Auswertung 1 - 16"; +// public static final String BUS1 = "Bus 1 (RJ45-1)"; +// public static final String BUS2 = "Bus 2 (RJ45-2)"; +// public static final String BUS3 = "Bus 3 (6-Polig)"; // Absender Geräte UID // SW-Versionsnummer // Gerätekennung @@ -51,6 +48,7 @@ public class CanDevice { // 8 Byte Artikelnummer. // Gerätebezeichnung, \0 Terminiert private String uid; + private String guiUid; private String version; private String hwVersion; private String identifier; @@ -64,25 +62,6 @@ public class CanDevice { private final Map configChannels; public CanDevice() { - this((String) null); - } - - /** - * Constructor for CS 3 JSON - * - * @param json - */ - public CanDevice(String json) { - measuringChannels = new HashMap<>(); - configChannels = new HashMap<>(); - } - - /** - * Constructor for CAN - * - * @param message - */ - public CanDevice(CanMessage message) { measuringChannels = new HashMap<>(); configChannels = new HashMap<>(); } @@ -104,6 +83,19 @@ public void setUid(Integer uid) { this.uid = "0x" + uid; } + public String getGuiUid() { + return guiUid; + } + + public Integer getGuiUidInt() { + String ui = guiUid.replace("0x", ""); + return Integer.parseUnsignedInt(ui, 16); + } + + public void setGuiUid(String guiUid) { + this.guiUid = guiUid; + } + public String getName() { if (name == null && this.identifier != null && this.identifier.equals("0xffff")) { return getDeviceType(); diff --git a/src/main/java/jcs/commandStation/marklin/cs/net/CSHTTPConnectionImpl.java b/src/main/java/jcs/commandStation/marklin/cs/net/CSHTTPConnectionImpl.java index 90ac3453..b9f80745 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/net/CSHTTPConnectionImpl.java +++ b/src/main/java/jcs/commandStation/marklin/cs/net/CSHTTPConnectionImpl.java @@ -329,64 +329,64 @@ public Image getFunctionImageCS2(String imageName) { public void close() throws Exception { } - public static void main(String[] args) throws Exception { - boolean cs3 = true; - - InetAddress inetAddr; - if (cs3) { - inetAddr = InetAddress.getByName("192.168.178.180"); - } else { - inetAddr = InetAddress.getByName("192.168.178.86"); - } - CSHTTPConnectionImpl hc = new CSHTTPConnectionImpl(inetAddr); - hc.setCs3(cs3); - - String serial; - if (cs3) { - serial = "2374"; - } else { - serial = "13344"; - } - -// Path fPath = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "cache" + File.separator + "zfunctions"); -// if (!Files.exists(fPath)) { -// Files.createDirectories(fPath); -// Logger.trace("Created new directory " + fPath); +// public static void main(String[] args) throws Exception { +// boolean cs3 = true; +// +// InetAddress inetAddr; +// if (cs3) { +// inetAddr = InetAddress.getByName("192.168.178.180"); +// } else { +// inetAddr = InetAddress.getByName("192.168.178.86"); // } +// CSHTTPConnectionImpl hc = new CSHTTPConnectionImpl(inetAddr); +// hc.setCs3(cs3); // -// Path aPath = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "cache" + File.separator + "zaccessories"); -// if (!Files.exists(aPath)) { -// Files.createDirectories(aPath); -// Logger.trace("Created new directory " + aPath); +// String serial; +// if (cs3) { +// serial = "2374"; +// } else { +// serial = "13344"; // } - Path info = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "info.json"); - String json = hc.getInfoJSON(); - Files.writeString(info, json); - - Path devices = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "devices.json"); - json = hc.getDevicesJSON(); - Files.writeString(devices, json); - - Path locomotives = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "locomotives.json"); - json = hc.getLocomotivesJSON(); - Files.writeString(locomotives, json); - - Path accessories = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "mags.json"); - json = hc.getAccessoriesJSON(); - Files.writeString(accessories, json); - - Path fcticons = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "fcticons.json"); - json = hc.getFunctionsSvgJSON(); - Files.writeString(fcticons, json); - - Path magicons = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "magicons.json"); - json = hc.getAccessoriesSvgJSON(); - Files.writeString(magicons, json); - - Path accessoryFile = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "magnetartikel.cs2"); - String file = hc.getAccessoriesFile(); - Logger.trace(file); - Files.writeString(accessoryFile, file); - - } +// +//// Path fPath = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "cache" + File.separator + "zfunctions"); +//// if (!Files.exists(fPath)) { +//// Files.createDirectories(fPath); +//// Logger.trace("Created new directory " + fPath); +//// } +//// +//// Path aPath = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "cache" + File.separator + "zaccessories"); +//// if (!Files.exists(aPath)) { +//// Files.createDirectories(aPath); +//// Logger.trace("Created new directory " + aPath); +//// } +// Path info = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "info.json"); +// String json = hc.getInfoJSON(); +// Files.writeString(info, json); +// +// Path devices = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "devices.json"); +// json = hc.getDevicesJSON(); +// Files.writeString(devices, json); +// +// Path locomotives = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "locomotives.json"); +// json = hc.getLocomotivesJSON(); +// Files.writeString(locomotives, json); +// +// Path accessories = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "mags.json"); +// json = hc.getAccessoriesJSON(); +// Files.writeString(accessories, json); +// +// Path fcticons = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "fcticons.json"); +// json = hc.getFunctionsSvgJSON(); +// Files.writeString(fcticons, json); +// +// Path magicons = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "magicons.json"); +// json = hc.getAccessoriesSvgJSON(); +// Files.writeString(magicons, json); +// +// Path accessoryFile = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "magnetartikel.cs2"); +// String file = hc.getAccessoriesFile(); +// Logger.trace(file); +// Files.writeString(accessoryFile, file); +// +// } } diff --git a/src/main/java/jcs/commandStation/marklin/cs/net/CSHTTPConnectionVirt.java b/src/main/java/jcs/commandStation/marklin/cs/net/CSHTTPConnectionVirt.java index a3d9039f..d0a449d1 100644 --- a/src/main/java/jcs/commandStation/marklin/cs/net/CSHTTPConnectionVirt.java +++ b/src/main/java/jcs/commandStation/marklin/cs/net/CSHTTPConnectionVirt.java @@ -24,6 +24,7 @@ import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; +import java.net.UnknownHostException; import javax.imageio.IIOException; import javax.imageio.ImageIO; import org.tinylog.Logger; @@ -45,8 +46,7 @@ public class CSHTTPConnectionVirt implements CSHTTPConnection { private final static String MAGNETARTIKEL = "magnetartikel.cs2"; private final static String ACCESSORIES_URL = "/app/api/mags"; - private final static String DEVICE = "geraet.vrs"; - + //private final static String DEVICE = "geraet.vrs"; private final static String IMAGE_FOLDER_CS3 = "/app/assets/lok/"; private final static String IMAGE_FOLDER_CS2 = "/icons/"; private final static String FUNCTION_IMAGE_FOLDER = "/fcticons/"; @@ -54,8 +54,11 @@ public class CSHTTPConnectionVirt implements CSHTTPConnection { private final static String FUNCTION_SVG_URL = "/images/svgSprites/fcticons.json"; private final static String ACCESSORIES_SVG_URL = "/images/svgSprites/magicons.json"; - private final static String CS3_INFO_JSON = "/app/api/info"; - private final static String DEVICES = "/app/api/devs"; + //private final static String CS3_INFO_JSON = "/app/api/info"; + //private final static String DEVICES = "/app/api/devs"; + public CSHTTPConnectionVirt() throws UnknownHostException { + this(InetAddress.getLocalHost()); + } public CSHTTPConnectionVirt(InetAddress csAddress) { this.csAddress = csAddress; @@ -231,7 +234,7 @@ public String getDevicesJSON() { json.append("\"_queryInterval\": \"5\","); json.append("\"_version\": {"); json.append("\"major\": \"77\""); - json.append("},"); + json.append("},"); json.append("\"_kanal\": [],"); json.append("\"_ready\": true,"); json.append("\"path\": \"/media/usb1\","); @@ -405,7 +408,7 @@ public String getDevicesJSON() { json.append("\"farbeGelb\": \"240\","); json.append("\"farbeGruen\": \"48\","); json.append("\"farbeMax\": \"192\","); - json.append("\"farbeRot\": \"22\","); + json.append("\"farbeRot\": \"224\","); json.append("\"name\": \"MAIN\","); json.append("\"nr\": \"1\","); json.append("\"potenz\": \"253\","); diff --git a/src/main/java/jcs/commandStation/marklin/cs/net/CSTCPConnection.java b/src/main/java/jcs/commandStation/marklin/cs/net/CSTCPConnection.java index 88c5257b..f8acde90 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/net/CSTCPConnection.java +++ b/src/main/java/jcs/commandStation/marklin/cs/net/CSTCPConnection.java @@ -162,7 +162,7 @@ public synchronized CanMessage sendCanMessage(CanMessage message) { dos.write(bytes); dos.flush(); } catch (IOException ex) { - Logger.error(ex); + Logger.error(ex.getMessage()); } if (CanMessage.PING_RESP != message.getCommand()) { @@ -187,6 +187,11 @@ public synchronized CanMessage sendCanMessage(CanMessage message) { if (callback != null) { //Wait for the response boolean responseComplete = callback.isResponseComplete(); + + //the CS somtime is slow with replies, whic could lead to missing responses. + //Just wait a 10 milliseconds to be sure + pause(); + while (!responseComplete && now < timeout) { responseComplete = callback.isResponseComplete(); now = System.currentTimeMillis(); @@ -235,6 +240,13 @@ public boolean isConnected() { return messageReceiver != null && messageReceiver.isRunning(); } + private void pause() { + try { + Thread.sleep(10); + } catch (InterruptedException ex) { + } + } + private class ClientMessageReceiver extends Thread { private boolean quit = true; @@ -292,6 +304,7 @@ public void run() { //Logger.trace("RX: "+rx +"; "+ din.available()); if (this.callBack != null && this.callBack.isSubscribedfor(cmd)) { this.callBack.addResponse(rx, din.available()); + } else { eventQueue.offer(rx); //Logger.trace("Enqueued: " + rx + " QueueSize: " + eventQueue.size()); diff --git a/src/main/java/jcs/commandStation/marklin/cs3/DeviceJSONParser.java b/src/main/java/jcs/commandStation/marklin/cs3/DeviceJSONParser.java deleted file mode 100644 index b73893c2..00000000 --- a/src/main/java/jcs/commandStation/marklin/cs3/DeviceJSONParser.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2023 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.commandStation.marklin.cs3; - -import java.util.ArrayList; -import java.util.List; -import jcs.commandStation.entities.DeviceBean; -import org.json.JSONObject; - -/** - * - * @author Frans Jacobs - */ -public class DeviceJSONParser { - - public DeviceJSONParser() { - } - - public static List parse(String json) { - JSONObject devicesJO = new JSONObject(json); - String[] names = JSONObject.getNames(devicesJO); - List devices = new ArrayList<>(names.length); - for (String n : names) { - JSONObject dev = devicesJO.getJSONObject(n); - DeviceBean db = new DeviceBean(dev.toString()); - devices.add(db); - } - - return devices; - } - -// public static void main(String[] a) throws Exception { -// Path path = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "devices.json"); -// -// CSHTTPConnectionVirt virtC = new CSHTTPConnectionVirt(null); -// -// //String devicesFile = Files.readString(path); -// -// String devicesFile = virtC.getDevicesJSON(); -// -// Logger.trace(devicesFile); -// -// List devices = DeviceJSONParser.parse(devicesFile); -// -// for (DeviceBean dev : devices) { -// if (dev.isFeedbackDevice()) { -// Logger.trace(dev); -// -// List cbl = dev.getChannels(); -// for (ChannelBean cb : cbl) { -// if (cb.isS88Bus()) { -// Logger.debug(cb); -// } -// } -// -// } -// } -// -// } -} diff --git a/src/main/java/jcs/commandStation/marklin/parser/CanDeviceJSONParser.java b/src/main/java/jcs/commandStation/marklin/parser/CanDeviceJSONParser.java new file mode 100644 index 00000000..31823104 --- /dev/null +++ b/src/main/java/jcs/commandStation/marklin/parser/CanDeviceJSONParser.java @@ -0,0 +1,136 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.commandStation.marklin.parser; + +import java.util.ArrayList; +import java.util.List; +import jcs.commandStation.marklin.cs.can.device.CanDevice; +import jcs.commandStation.marklin.cs.can.device.ConfigChannel; +import jcs.commandStation.marklin.cs.can.device.MeasuringChannel; +import org.json.JSONArray; +import org.json.JSONObject; + +/** + * CS 3 supports JSON + */ +public class CanDeviceJSONParser { + + public static final String LINK_S88 = "LinkS88-1"; + public static final String GFP = "GFP3-1"; + public static final String CS3 = "CS3 0000"; + + public CanDeviceJSONParser() { + } + + public static List parse(String json) { + JSONObject devicesJO = new JSONObject(json); + String[] ids = JSONObject.getNames(devicesJO); + List devices = new ArrayList<>(); + for (String id : ids) { + JSONObject jo = devicesJO.getJSONObject(id); + String name = jo.optString("_name"); + if (name.equals(LINK_S88) || name.equals(GFP) || name.equals(CS3)) { + CanDevice d = parseDevice(devicesJO.getJSONObject(id)); + devices.add(d); + } + } + + return devices; + } + + private static CanDevice parseDevice(JSONObject jo) { + CanDevice d = new CanDevice(); + d.setUid(jo.optString("_uid")); + d.setName(jo.optString("_name")); + d.setIdentifier(jo.optString("_kennung")); + d.setArticleNumber(jo.optString("_artikelnr")); + d.setSerial(jo.optString("_seriennr")); + + JSONObject versionObj = jo.optJSONObject("_version"); + if (versionObj != null) { + String major = versionObj.optString("major"); + String minor = versionObj.optString("minor"); + d.setVersion((major != null ? major : "") + (major != null ? "." : "") + (minor != null ? minor : "")); + } + + JSONArray channelsJA = jo.optJSONArray("_kanal"); + if (channelsJA != null) { + for (int i = 0; i < channelsJA.length(); i++) { + JSONObject cjo = channelsJA.getJSONObject(i); + + if (cjo.has("auswahl")) { + ConfigChannel cc = parseConfigChannel(cjo); + d.addConfigChannel(cc); + } else { + MeasuringChannel mc = parseMeasuringChannel(cjo); + d.addMeasuringChannel(mc); + } + } + d.setMeasureChannelCount(d.getMeasuringChannels().size()); + d.setConfigChannelCount(d.getConfigChannels().size()); + } + return d; + } + + private static MeasuringChannel parseMeasuringChannel(JSONObject jo) { + MeasuringChannel mc = new MeasuringChannel(); + mc.setName(jo.optString("name")); + mc.setNumber(jo.optInt("nr")); + Integer scale = jo.optInt("potenz"); + if (scale > 0) { + scale = scale - 256; + } + mc.setScale(scale); + mc.setUnit(jo.optString("einheit")); + mc.setEndValue(jo.optDouble("endWert")); + mc.setStartValue(jo.optDouble("startWert")); + mc.setColorGreen(jo.optInt("farbeGruen")); + mc.setColorYellow(jo.optInt("farbeGelb")); + mc.setColorRed(jo.optInt("farbeRot")); + mc.setColorMax(jo.optInt("farbeMax")); + mc.setRangeGreen(jo.optInt("rangeGruen")); + mc.setRangeYellow(jo.optInt("rangeGelb")); + mc.setRangeRed(jo.optInt("rangeRot")); + mc.setRangeMax(jo.optInt("rangeMax")); + mc.setZeroPoint(jo.optInt("valueHuman")); + return mc; + } + + private static ConfigChannel parseConfigChannel(JSONObject jo) { + ConfigChannel cc = new ConfigChannel(); + + String choice = jo.optString("auswahl"); + String choices[] = choice.split(":"); + for (String c : choices) { + cc.addChoice(c); + } + cc.setChoicesCount(choices.length); + cc.setValueId(jo.optInt("index")); + + cc.setNumber(jo.optInt("nr")); + cc.setChoiceDescription(jo.optString("name")); + + String unit = jo.optString("einheit"); + if (!"".equals(unit)) { + cc.setUnit(unit); + } + cc.setHighValue(jo.optInt("endWert")); + cc.setLowValue(jo.optInt("startWert")); + cc.setActualValue(jo.optInt("wert")); + return cc; + } + +} diff --git a/src/main/java/jcs/commandStation/marklin/cs/can/parser/CanDevices.java b/src/main/java/jcs/commandStation/marklin/parser/CanDeviceParser.java similarity index 97% rename from src/main/java/jcs/commandStation/marklin/cs/can/parser/CanDevices.java rename to src/main/java/jcs/commandStation/marklin/parser/CanDeviceParser.java index c88d56f7..0053a204 100644 --- a/src/main/java/jcs/commandStation/marklin/cs/can/parser/CanDevices.java +++ b/src/main/java/jcs/commandStation/marklin/parser/CanDeviceParser.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package jcs.commandStation.marklin.cs.can.parser; +package jcs.commandStation.marklin.parser; import java.io.UnsupportedEncodingException; import java.util.ArrayList; @@ -28,17 +28,22 @@ * Parse the CS CAN Bus devices from the
* "Softwarestand Anfrage / Teilnehmer Ping" and "Statusdaten Konfiguration" messages */ -public class CanDevices { +public class CanDeviceParser { public static List parse(CanMessage memberPingmessage) { List devices = new ArrayList<>(); - for (CanMessage response : memberPingmessage.getResponses()) { + List responses = memberPingmessage.getResponses(); + if (responses.isEmpty() && memberPingmessage.isResponseMessage()) { + responses.add(memberPingmessage); + } + + for (CanMessage response : responses) { CanDevice device = parseResponse(response); if (device != null) { devices.add(device); } } - + return devices; } @@ -123,15 +128,6 @@ public static void parse(CanDevice canDevice, CanMessage statusConfigmessage) { } } - -//Anzahl der Messwerte im Gerät. -//Anzahl der Konfigurationskanäle -//frei. -//Seriennummer CS2. -//8 Byte Artikelnummer. -//Gerätebezeichnung, \0 Terminiert - - /** * In case the index equals zero (0) the responses contain a CAN Device Description. * @@ -152,10 +148,10 @@ private static void parseDeviceDescription(CanDevice canDevice, List int configChannels = Byte.toUnsignedInt(data[1]); canDevice.setMeasureChannelCount(measureChannels); canDevice.setConfigChannelCount(configChannels); - + byte[] free = new byte[2]; System.arraycopy(data, 2, free, 0, free.length); - + byte[] sn = new byte[4]; System.arraycopy(data, 4, sn, 0, sn.length); int serial = CanMessage.toInt(sn); diff --git a/src/main/java/jcs/commandStation/marklin/parser/GeraetParser.java b/src/main/java/jcs/commandStation/marklin/parser/GeraetParser.java index ecfea8e1..eeed9175 100644 --- a/src/main/java/jcs/commandStation/marklin/parser/GeraetParser.java +++ b/src/main/java/jcs/commandStation/marklin/parser/GeraetParser.java @@ -70,7 +70,7 @@ public static CanDevice parseFile(String geraetFile) { gfp.setUid(value); } case ".guiuid" -> { - //ib.setGuiUid(value); + gfp.setGuiUid(value); } case ".hardvers" -> { //ib.setHardwareVersion(value); @@ -101,7 +101,7 @@ public static CanDevice parseFile(String geraetFile) { } else { shortName = "CS2"; } - + gfp.setIdentifier("0x00"); return gfp; } diff --git a/src/main/java/jcs/commandStation/virtual/VirtualCommandStationImpl.java b/src/main/java/jcs/commandStation/virtual/VirtualCommandStationImpl.java index 5666cfb9..d861a454 100644 --- a/src/main/java/jcs/commandStation/virtual/VirtualCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/virtual/VirtualCommandStationImpl.java @@ -18,7 +18,6 @@ import jcs.commandStation.autopilot.DriveSimulator; import java.awt.Image; import java.util.List; -import java.util.Map; import jcs.JCS; import jcs.commandStation.AbstractController; import jcs.commandStation.AccessoryController; @@ -38,7 +37,6 @@ import jcs.commandStation.events.SensorEvent; import jcs.commandStation.events.SensorEventListener; import jcs.entities.AccessoryBean; -import jcs.entities.ChannelBean; import jcs.entities.CommandStationBean; import jcs.entities.FeedbackModuleBean; import jcs.commandStation.entities.InfoBean; @@ -257,10 +255,6 @@ public boolean isSupportTrackMeasurements() { return false; } - @Override - public Map getTrackMeasurements() { - throw new UnsupportedOperationException("Not supported yet."); - } // @Override // public void switchAccessory(Integer address, AccessoryBean.AccessoryValue value) { diff --git a/src/main/java/jcs/ui/StatusPanel.java b/src/main/java/jcs/ui/StatusPanel.java index 416051d2..20ba166c 100644 --- a/src/main/java/jcs/ui/StatusPanel.java +++ b/src/main/java/jcs/ui/StatusPanel.java @@ -48,19 +48,23 @@ private void postInit() { @Override public void onMeasurement(MeasurementEvent event) { -// switch (event.getCannel()) { -// case 1: -// this.currentLbl.setText(event.getFormattedValue()); -// break; -// case 3: -// this.voltageLbl.setText(event.getFormattedValue()); -// break; -// case 4: -// this.tempLbl.setText(event.getFormattedValue()); -// default: -// break; -// } + if (event.getMain() != null) { + this.currentLbl.setText(event.getMain().getDisplayValue() + " " + event.getMain().getUnit()); + } else { + this.currentLbl.setText("-"); + } + + if (event.getVolt() != null) { + this.voltageLbl.setText(event.getVolt().getDisplayValue() + " " + event.getVolt().getUnit()); + } else { + this.voltageLbl.setText("-"); + } + if (event.getTemp() != null) { + this.tempLbl.setText(event.getTemp().getDisplayValue() + " " + event.getTemp().getUnit()); + } else { + this.tempLbl.setText("-"); + } } /** diff --git a/src/test/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImplTest.java b/src/test/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImplTest.java index 1e4bb0d8..55d090c5 100644 --- a/src/test/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImplTest.java +++ b/src/test/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImplTest.java @@ -15,12 +15,9 @@ */ package jcs.commandStation.esu.ecos; -import java.util.ArrayList; import java.util.List; -import jcs.commandStation.entities.DeviceBean; import jcs.commandStation.entities.InfoBean; import jcs.entities.AccessoryBean; -import jcs.entities.ChannelBean; import jcs.entities.CommandStationBean; import jcs.entities.FeedbackModuleBean; import jcs.entities.LocomotiveBean; diff --git a/src/test/java/jcs/commandStation/marklin/parser/CanDeviceJSONParserTest.java b/src/test/java/jcs/commandStation/marklin/parser/CanDeviceJSONParserTest.java new file mode 100644 index 00000000..ae3b5bbe --- /dev/null +++ b/src/test/java/jcs/commandStation/marklin/parser/CanDeviceJSONParserTest.java @@ -0,0 +1,149 @@ +/* + * Copyright 2025 fransjacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.commandStation.marklin.parser; + +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.List; +import jcs.commandStation.marklin.cs.can.device.CanDevice; +import jcs.commandStation.marklin.cs.can.device.ConfigChannel; +import jcs.commandStation.marklin.cs.can.device.MeasuringChannel; +import jcs.commandStation.marklin.cs.net.CSHTTPConnectionVirt; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; +import org.tinylog.Logger; + +/** + * + * @author fransjacobs + */ +public class CanDeviceJSONParserTest { + + String deviceJson; + + public CanDeviceJSONParserTest() { + try { + deviceJson = new CSHTTPConnectionVirt().getDevicesJSON(); + } catch (UnknownHostException ex) { + Logger.error(ex); + } + } + + @BeforeEach + public void setUp() { + } + + @AfterEach + public void tearDown() { + } + + /** + * Test of parse method, of class CanDeviceJSONParser. + */ + @Test + public void testParse() { + System.out.println("parse"); + String json = deviceJson; + List expResult = new ArrayList<>(); + + CanDevice expGfp = new CanDevice(); + expGfp.setUid("0x6373458c"); + expGfp.setName("GFP3-1"); + expGfp.setIdentifier("0xffff"); + expGfp.setArticleNumber("60226"); + expGfp.setSerial("0000"); + expGfp.setVersion("12.113"); + expGfp.setMeasureChannelCount(3); + expGfp.setConfigChannelCount(1); + + MeasuringChannel mc1 = new MeasuringChannel(); + mc1.setNumber(1); + mc1.setName("MAIN"); + mc1.setScale(-3); + mc1.setColorGreen(48); + mc1.setColorYellow(240); + mc1.setColorRed(224); + mc1.setColorMax(192); + mc1.setZeroPoint(0); + mc1.setRangeGreen(552); + mc1.setRangeYellow(576); + mc1.setRangeRed(600); + mc1.setRangeMax(660); + mc1.setStartValue(0.0); + mc1.setEndValue(5.5); + mc1.setUnit("A"); + expGfp.addMeasuringChannel(mc1); + + MeasuringChannel mc2 = new MeasuringChannel(); + mc2.setNumber(2); + mc2.setName("PROG"); + mc2.setScale(-3); + mc2.setColorGreen(48); + mc2.setColorYellow(240); + mc2.setColorRed(224); + mc2.setColorMax(192); + mc2.setZeroPoint(0); + mc2.setRangeGreen(330); + mc2.setRangeYellow(363); + mc2.setRangeRed(561); + mc2.setRangeMax(759); + mc2.setStartValue(0.0); + mc2.setEndValue(2.3); + mc2.setUnit("A"); + expGfp.addMeasuringChannel(mc2); + + MeasuringChannel mc4 = new MeasuringChannel(); + mc4.setNumber(4); + mc4.setName("TEMP"); + mc4.setScale(0); + mc4.setColorGreen(12); + mc4.setColorYellow(8); + mc4.setColorRed(240); + mc4.setColorMax(192); + mc4.setZeroPoint(0); + mc4.setRangeGreen(121); + mc4.setRangeYellow(145); + mc4.setRangeRed(169); + mc4.setRangeMax(193); + mc4.setStartValue(0.0); + mc4.setEndValue(80.0); + mc4.setUnit("C"); + expGfp.addMeasuringChannel(mc4); + + ConfigChannel cc1 = new ConfigChannel(); + cc1.setNumber(1); + cc1.setChoicesCount(3); + cc1.setValueId(1); + cc1.setChoiceDescription("Netzteil:"); + cc1.addChoice("60061"); + cc1.addChoice("60101"); + cc1.addChoice("L51095"); + cc1.setLowValue(0); + cc1.setHighValue(0); + cc1.setActualValue(0); + expGfp.addConfigChannel(cc1); + + List result = CanDeviceJSONParser.parse(json); + for (CanDevice cs : result) { + Logger.trace(cs); + } + CanDevice resultGfp = result.get(0); + assertEquals(expGfp, resultGfp); + } + +} diff --git a/src/test/java/jcs/commandStation/marklin/cs/can/parser/CanDevicesTest.java b/src/test/java/jcs/commandStation/marklin/parser/CanDeviceParserTest.java similarity index 96% rename from src/test/java/jcs/commandStation/marklin/cs/can/parser/CanDevicesTest.java rename to src/test/java/jcs/commandStation/marklin/parser/CanDeviceParserTest.java index 340aaf94..5679b71a 100644 --- a/src/test/java/jcs/commandStation/marklin/cs/can/parser/CanDevicesTest.java +++ b/src/test/java/jcs/commandStation/marklin/parser/CanDeviceParserTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package jcs.commandStation.marklin.cs.can.parser; +package jcs.commandStation.marklin.parser; import java.util.ArrayList; import java.util.List; @@ -28,9 +28,9 @@ /** * */ -public class CanDevicesTest { +public class CanDeviceParserTest { - public CanDevicesTest() { + public CanDeviceParserTest() { } private CanMessage getMemberPing() { @@ -65,7 +65,7 @@ public void testParseMemberPingMessage() { gfp.setVersion("12.113"); expResult.add(gfp); - List result = CanDevices.parse(memberPingmessage); + List result = CanDeviceParser.parse(memberPingmessage); assertEquals(expResult, result); } @@ -100,7 +100,7 @@ public void testParseStatusDataConfigGFPIndex0() { expResult.setConfigChannelCount(2); expResult.setSerial(2374); - CanDevices.parse(canDevice, statusConfigmessage); + CanDeviceParser.parse(canDevice, statusConfigmessage); CanDevice result = canDevice; assertEquals(expResult, result); } @@ -129,7 +129,7 @@ public void testParseStatusDataConfigGFPIndex1() { canDevice.setConfigChannelCount(2); CanMessage statusConfigmessage = getStatusDataConfigGFPIndex1(); - CanDevices.parse(canDevice, statusConfigmessage); + CanDeviceParser.parse(canDevice, statusConfigmessage); CanDevice expDeviceResult = new CanDevice(); expDeviceResult.setUid("0x6373458c"); @@ -196,7 +196,7 @@ public void testParseStatusDataConfigLinkS88() { expResult.setVersion("1.1"); expResult.setSerial(9281); - CanDevices.parse(canDevice, statusConfigmessage); + CanDeviceParser.parse(canDevice, statusConfigmessage); CanDevice result = canDevice; assertEquals(expResult, result); } @@ -246,7 +246,7 @@ public void testParseStatusDataConfigLinkS88Index1() { expResult.addChoice("Tastaturmatrix"); expResultDev.addConfigChannel(expResult); - CanDevices.parse(canDevice, statusConfigmessage); + CanDeviceParser.parse(canDevice, statusConfigmessage); CanDevice resultDev = canDevice; @@ -306,7 +306,7 @@ public void testParseStatusDataConfigLinkS88Index2() { expResult.setEndName("31"); expResultDev.addConfigChannel(expResult); - CanDevices.parse(canDevice, statusConfigmessage); + CanDeviceParser.parse(canDevice, statusConfigmessage); CanDevice resultDev = canDevice; assertEquals(expResultDev, resultDev); diff --git a/src/test/java/jcs/commandStation/marklin/cs/can/CanMessageTest.java b/src/test/java/jcs/commandStation/marklin/parser/CanMessageTest.java similarity index 98% rename from src/test/java/jcs/commandStation/marklin/cs/can/CanMessageTest.java rename to src/test/java/jcs/commandStation/marklin/parser/CanMessageTest.java index d2f4a77a..6a9ad728 100755 --- a/src/test/java/jcs/commandStation/marklin/cs/can/CanMessageTest.java +++ b/src/test/java/jcs/commandStation/marklin/parser/CanMessageTest.java @@ -13,8 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package jcs.commandStation.marklin.cs.can; +package jcs.commandStation.marklin.parser; +import jcs.commandStation.marklin.cs.can.CanMessage; import org.junit.After; import org.junit.AfterClass; import org.junit.Assert; @@ -25,7 +26,6 @@ /** * - * @author Frans Jacobs */ public class CanMessageTest { diff --git a/src/test/java/jcs/commandStation/marklin/cs3/can/parser/ChannelDataParserTest.java b/src/test/java/jcs/commandStation/marklin/parser/ChannelDataParserTest.java similarity index 99% rename from src/test/java/jcs/commandStation/marklin/cs3/can/parser/ChannelDataParserTest.java rename to src/test/java/jcs/commandStation/marklin/parser/ChannelDataParserTest.java index fe620698..ad5c6c2a 100644 --- a/src/test/java/jcs/commandStation/marklin/cs3/can/parser/ChannelDataParserTest.java +++ b/src/test/java/jcs/commandStation/marklin/parser/ChannelDataParserTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package jcs.commandStation.marklin.cs3.can.parser; +package jcs.commandStation.marklin.parser; import jcs.entities.ChannelBean; import jcs.commandStation.marklin.cs.can.CanMessage; diff --git a/src/test/java/jcs/entities/DeviceTest.java b/src/test/java/jcs/entities/DeviceTest.java deleted file mode 100644 index 8392613f..00000000 --- a/src/test/java/jcs/entities/DeviceTest.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2023 frans. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.entities; - -import jcs.commandStation.entities.DeviceBean; -import jcs.commandStation.marklin.cs.can.CanMessage; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import static org.junit.Assert.*; - -/** - * - * @author frans - */ -public class DeviceTest { - - private CanMessage updateMessage; - private CanMessage updateMessage1; - private CanMessage message; - private CanMessage response; - - public DeviceTest() { - } - - @Before - public void setUp() { - updateMessage = new CanMessage(new byte[]{0x00, 0x3a, (byte) 0xcb, 0x13, 0x05, 0x43, 0x53, (byte) 0x9a, 0x40, 0x00, 0x00, 0x00, 0x00}); - updateMessage.addResponse(new CanMessage(new byte[]{0x00, 0x3b, 0x03, 0x01, 0x08, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x34, 0x20})); - updateMessage.addResponse(new CanMessage(new byte[]{0x00, 0x3b, 0x03, 0x02, 0x08, 0x36, 0x30, 0x32, 0x31, 0x34, 0x00, 0x00, 0x00})); - updateMessage.addResponse(new CanMessage(new byte[]{0x00, 0x3b, 0x03, 0x03, 0x08, 0x43, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x20})); - updateMessage.addResponse(new CanMessage(new byte[]{0x00, 0x3b, 0x03, 0x04, 0x08, 0x53, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20})); - updateMessage.addResponse(new CanMessage(new byte[]{0x00, 0x3b, 0x03, 0x05, 0x08, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})); - updateMessage.addResponse(new CanMessage(new byte[]{0x00, 0x3b, (byte) 0xcb, 0x13, 0x05, 0x43, 0x53, (byte) 0x9a, 0x40, 0x00, 0x00, 0x00, 0x00})); - - updateMessage1 = new CanMessage(new byte[]{0x00, 0x3a, (byte) 0xcb, 0x13, 0x05, 0x43, 0x53, (byte) 0x9a, 0x40, 0x00, 0x00, 0x00, 0x00}); - updateMessage1.addResponse(new CanMessage(new byte[]{0x00, 0x3b, 0x03, 0x01, 0x08, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x34, 0x20})); - updateMessage1.addResponse(new CanMessage(new byte[]{0x00, 0x3b, 0x03, 0x02, 0x08, 0x36, 0x30, 0x32, 0x31, 0x34, 0x00, 0x00, 0x00})); - updateMessage1.addResponse(new CanMessage(new byte[]{0x00, 0x3b, 0x03, 0x03, 0x08, 0x43, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x20})); - updateMessage1.addResponse(new CanMessage(new byte[]{0x00, 0x3b, 0x03, 0x04, 0x08, 0x53, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20})); - updateMessage1.addResponse(new CanMessage(new byte[]{0x00, 0x3b, 0x03, 0x05, 0x08, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})); - updateMessage1.addResponse(new CanMessage(new byte[]{0x00, 0x3b, (byte) 0xcb, 0x13, 0x05, 0x43, 0x53, (byte) 0x9a, 0x40, 0x00, 0x00, 0x00, 0x00})); - - message = new CanMessage(new byte[]{0x00, 0x30, 0x07, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}); - message.addResponse(new CanMessage(new byte[]{0x00, 0x31, (byte) 0xcb, 0x13, 0x08, 0x43, 0x53, (byte) 0x9a, 0x40, 0x03, 0x55, 0x00, 0x00})); - - response = new CanMessage(new byte[]{0x00, 0x31, 0x07, 0x69, 0x08, 0x43, 0x53, (byte) 0x9a, 0x41, 0x04, 0x03, (byte) 0xff, (byte) 0xff}); - - } - - @After - public void tearDown() { - } - - @Test - public void testUpdateFromMessage() { - System.out.println("updateFromMessage"); - DeviceBean instance = new DeviceBean(); - instance.updateFromMessage(updateMessage); - - assertEquals("60214", instance.getArticleNumber()); - assertEquals("Central Station 2", instance.getName()); - assertEquals("13344", instance.getSerial()); - //assertEquals(4, instance.getMeasureChannels()); - //assertEquals(2, instance.getConfigChannels()); - } - - @Test - public void testBuildFromMessage() { - System.out.println("buildFromMessage"); - DeviceBean instance = new DeviceBean(message); - System.out.println(instance); - assertEquals("0x43539a40", instance.getUid()); - assertEquals((Integer) 1129552448, instance.getUidAsInt()); - assertEquals("853", instance.getVersion()); - assertEquals((Integer) 0, instance.getIdentifierAsInt()); - } - - @Test - public void testBuildFromResponse() { - System.out.println("buildFromResponse"); - DeviceBean instance = new DeviceBean(response); - - System.out.println(instance); - - assertEquals((Integer)1129552449, instance.getUidAsInt()); - assertEquals("1027", instance.getVersion()); - assertEquals((Integer) 65535, instance.getIdentifierAsInt()); - } - -} From 1a8f6283c91ea65834803d861435925ee49f9601 Mon Sep 17 00:00:00 2001 From: Frans Jacobs <41232225+fransjacobs@users.noreply.github.com> Date: Thu, 8 May 2025 19:52:28 +0200 Subject: [PATCH 51/70] Fix testcases issue due to overun of the main db --- pom.xml | 2 +- .../commandStation/JCSCommandStationImpl.java | 1 - .../esu/ecos/EsuEcosCommandStationImpl.java | 39 ---- .../marklin/cs/MarklinCentralStationImpl.java | 87 +++++++- .../marklin/cs/can/device/CanDevice.java | 22 +- .../marklin/parser/CanDeviceJSONParser.java | 13 +- .../jcs/persistence/H2PersistenceService.java | 20 +- .../jcs/persistence/util/H2DatabaseUtil.java | 8 +- src/main/java/jcs/ui/JCSFrame.java | 5 +- src/main/java/jcs/ui/layout/LayoutPanel.java | 2 +- .../autopilot/AutoPilotTest.java | 2 +- .../state/StateMachineStepByStepTest.java | 2 +- .../state/StateMachineThreadTest.java | 2 +- .../dccex/DccExMessageTest.java | 2 +- .../esu/ecos/AccessoryManagerTest.java | 1 + .../ecos/EsuEcosCommandStationImplTest.java | 6 +- .../esu/ecos/FeedbackManagerTest.java | 1 + .../esu/ecos/LocomotiveManagerTest.java | 1 + .../marklin/cs/MarklinCSTest.java | 2 +- .../marklin/parser/ChannelDataParserTest.java | 188 ------------------ .../persistence/PersistenceServiceTest.java | 80 ++++---- .../persistence/TestH2PersistenceService.java | 53 +++++ .../java/jcs/ui/layout/LayoutUtilTest.java | 2 +- src/test/java/jcs/ui/layout/TileTest.java | 1 + .../pathfinding/astar/AStarCrossLeftEast.java | 2 +- .../astar/AStarCrossLeftSouth.java | 2 +- .../astar/AStarCrossRightEast.java | 2 +- .../astar/AStarCrossRightSouth.java | 2 +- .../pathfinding/astar/AStarCrossingTest.java | 2 +- .../astar/AStarSwitchLeftEast.java | 2 +- .../astar/AStarSwitchLeftNorth.java | 2 +- .../astar/AStarSwitchLeftSouth.java | 2 +- .../astar/AStarSwitchLeftWest.java | 2 +- .../layout/pathfinding/astar/AStarTest.java | 2 +- .../astar/AStarTestWithDirection.java | 2 +- 35 files changed, 236 insertions(+), 328 deletions(-) delete mode 100644 src/test/java/jcs/commandStation/marklin/parser/ChannelDataParserTest.java create mode 100644 src/test/java/jcs/persistence/TestH2PersistenceService.java diff --git a/pom.xml b/pom.xml index 0f320d38..631b45b8 100644 --- a/pom.xml +++ b/pom.xml @@ -212,7 +212,7 @@ --enable-preview 21 - false + true diff --git a/src/main/java/jcs/commandStation/JCSCommandStationImpl.java b/src/main/java/jcs/commandStation/JCSCommandStationImpl.java index 2685b2fa..ee4011c4 100755 --- a/src/main/java/jcs/commandStation/JCSCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/JCSCommandStationImpl.java @@ -304,7 +304,6 @@ public void disconnect() { decoderController = null; accessoryControllers.clear(); feedbackControllers.clear(); - commandStation = null; ControllerFactory.reset(); } diff --git a/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java b/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java index 777e4e1f..d978e99c 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java @@ -285,27 +285,6 @@ public InfoBean getCommandStationInfo() { return ib; } - //TODO: is the device in this form it is now really necessary? -// @Override -// public DeviceBean getDevice() { -// DeviceBean d = new DeviceBean(); -// if (ecosManager != null) { -// d.setName(ecosManager.getName()); -// d.setVersion(ecosManager.getHardwareVersion()); -// d.setTypeName(ecosManager.getCommandStationType()); -// d.setSerial(ecosManager.getSerialNumber()); -// } else { -// d.setName("Not Connected"); -// } -// return d; -// } - //TODO: is the device in this form it is now really necessary? -// @Override -// public List getDevices() { -// List devices = new ArrayList<>(); -// devices.add(getDevice()); -// return devices; -// } @Override public String getIp() { if (this.connection != null && this.connection.isConnected()) { @@ -533,24 +512,6 @@ EcosConnection getConnection() { return connection; } -// @Override -// public DeviceBean getFeedbackDevice() { -// DeviceBean db = new DeviceBean(); -// db.setArticleNumber(this.ecosManager.getName()); -// db.setIdentifier("0x0"); -// db.getBusLength(this.feedbackManager.getSize()); -// db.setVersion(this.ecosManager.getApplicationVersion()); -// db.setSerial(this.ecosManager.getSerialNumber()); -// db.setTypeName("Link S88"); -// -// ChannelBean cb = new ChannelBean(); -// cb.setName(DeviceBean.BUS0); -// cb.setNumber(0); -// -// db.addSensorBus(0, cb); -// -// return db; -// } @Override public List getFeedbackModules() { List feedbackModules = new ArrayList<>(this.feedbackManager.getModules().values()); diff --git a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java index 185a25b2..4d24f6a1 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java +++ b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java @@ -159,6 +159,15 @@ public void setVirtual(boolean flag) { connect(); } + CanDevice getCanDevice(String name) { + for (CanDevice d : canDevices.values()) { + if (name.equals(d.getName())) { + return d; + } + } + return null; + } + @Override public final synchronized boolean connect() { if (!connected) { @@ -432,12 +441,71 @@ public InfoBean getCommandStationInfo() { return infoBean; } - //TODO! @Override public List getFeedbackModules() { - return null; + //Feedbackmodules can be queried from the Link S88 if avalable. + //In case of a CS 3 Plus or CS 2 there should be a node "0" which could have max 32 S88 modules. + //TODO: Test with CS-3Plus and CS2. + //Link S88 + List feedbackModules = new ArrayList<>(); + + CanDevice links88 = getCanDevice("Link S88"); + int bus1Len = 0, bus2Len = 0, bus3Len = 0, nodeId = 0; + if (links88 != null) { + nodeId = links88.getIdentifierInt() + 1; + for (ConfigChannel cc : links88.getConfigChannels()) { + if (cc.getChoiceDescription().contains("Bus 1")) { + bus1Len = cc.getActualValue(); + } + if (cc.getChoiceDescription().contains("Bus 2")) { + bus2Len = cc.getActualValue(); + } + if (cc.getChoiceDescription().contains("Bus 3")) { + bus3Len = cc.getActualValue(); + } + + } + + //Link S88 has 16 sensors starting from 0 + //Bus 1 offset 1000, Bus 2 offset 2000 and Bus 3 offset 3000 + FeedbackModuleBean l = new FeedbackModuleBean(); + l.setAddressOffset(0); + l.setModuleNumber(0); + l.setIdentifier(nodeId); + feedbackModules.add(l); + + for (int i = 0; i < bus1Len; i++) { + FeedbackModuleBean b1 = new FeedbackModuleBean(); + b1.setAddressOffset(1000); + b1.setModuleNumber(i); + l.setIdentifier(nodeId); + feedbackModules.add(b1); + } + for (int i = 0; i < bus2Len; i++) { + FeedbackModuleBean b2 = new FeedbackModuleBean(); + b2.setAddressOffset(2000); + b2.setModuleNumber(i); + l.setIdentifier(nodeId); + feedbackModules.add(b2); + } + for (int i = 0; i < bus3Len; i++) { + FeedbackModuleBean b3 = new FeedbackModuleBean(); + b3.setAddressOffset(3000); + b3.setModuleNumber(i); + l.setIdentifier(nodeId); + feedbackModules.add(b3); + } + + } + + return feedbackModules; } +// @Override +// public List getFeedbackModules() { +// List feedbackModules = new ArrayList<>(this.feedbackManager.getModules().values()); +// return feedbackModules; +// } /** * Query the System Status * @@ -478,7 +546,16 @@ public boolean power(boolean on) { @Override public void disconnect() { - //Signal listeners that there are no measurments + Logger.trace("Start disconnecting..."); + //Stop all schedules + measurementTimer.cancel(); + watchDogTimer.cancel(); + //Stop Threads + if (executor != null) { + executor.shutdown(); + } + + //Signal listeners that there are no measurements MeasuredChannels measuredChannels = new MeasuredChannels(System.currentTimeMillis()); MeasurementEvent me = new MeasurementEvent(measuredChannels); for (MeasurementEventListener listener : measurementEventListeners) { @@ -490,13 +567,11 @@ public void disconnect() { if (eventMessageHandler != null) { eventMessageHandler.quit(); } + eventMessageHandler.join(2000); connection.close(); connected = false; } - if (executor != null) { - executor.shutdown(); - } executor = null; connection = null; diff --git a/src/main/java/jcs/commandStation/marklin/cs/can/device/CanDevice.java b/src/main/java/jcs/commandStation/marklin/cs/can/device/CanDevice.java index 63563d0c..587074f7 100644 --- a/src/main/java/jcs/commandStation/marklin/cs/can/device/CanDevice.java +++ b/src/main/java/jcs/commandStation/marklin/cs/can/device/CanDevice.java @@ -20,6 +20,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import jcs.util.ByteUtil; /** * A CanDevice is a Device inside or connected to the Marklin Central Station
@@ -30,23 +31,6 @@ */ public class CanDevice { -// public static final String MAIN = "MAIN"; -// public static final String PROG = "PROG"; -// public static final String VOLT = "VOLT"; -// public static final String TEMP = "TEMP"; -// public static final String BUS0 = "Auswertung 1 - 16"; -// public static final String BUS1 = "Bus 1 (RJ45-1)"; -// public static final String BUS2 = "Bus 2 (RJ45-2)"; -// public static final String BUS3 = "Bus 3 (6-Polig)"; -// Absender Geräte UID -// SW-Versionsnummer -// Gerätekennung -// Anzahl der Messwerte im Gerät. -// Anzahl der Konfigurationskanäle -// frei. -// Seriennummer CS2. -// 8 Byte Artikelnummer. -// Gerätebezeichnung, \0 Terminiert private String uid; private String guiUid; private String version; @@ -115,6 +99,10 @@ public void setIdentifier(String identifier) { this.identifier = identifier; } + public void setIdentifier(Integer identifier) { + this.identifier = ByteUtil.toHexString(identifier); + } + public Integer getIdentifierInt() { String id = identifier.replace("0x", ""); return Integer.parseUnsignedInt(id, 16); diff --git a/src/main/java/jcs/commandStation/marklin/parser/CanDeviceJSONParser.java b/src/main/java/jcs/commandStation/marklin/parser/CanDeviceJSONParser.java index 31823104..10704670 100644 --- a/src/main/java/jcs/commandStation/marklin/parser/CanDeviceJSONParser.java +++ b/src/main/java/jcs/commandStation/marklin/parser/CanDeviceJSONParser.java @@ -55,7 +55,18 @@ private static CanDevice parseDevice(JSONObject jo) { CanDevice d = new CanDevice(); d.setUid(jo.optString("_uid")); d.setName(jo.optString("_name")); - d.setIdentifier(jo.optString("_kennung")); + + //Links S88 JSON appears to have 1 more, CAN bus is zero base and has 1 less. + //To come to the same node id as can subtract 1 + if (LINK_S88.equals(jo.optString("_name"))) { + String id = jo.optString("_kennung"); + id = id.replaceAll("0x", ""); + int idi = Integer.parseUnsignedInt(id, 16); + d.setIdentifier(idi - 1); + } else { + d.setIdentifier(jo.optString("_kennung")); + } + d.setArticleNumber(jo.optString("_artikelnr")); d.setSerial(jo.optString("_seriennr")); diff --git a/src/main/java/jcs/persistence/H2PersistenceService.java b/src/main/java/jcs/persistence/H2PersistenceService.java index 98464ca2..6d567ac0 100755 --- a/src/main/java/jcs/persistence/H2PersistenceService.java +++ b/src/main/java/jcs/persistence/H2PersistenceService.java @@ -46,30 +46,36 @@ public class H2PersistenceService implements PersistenceService { - private Database database; + protected Database database; - private final HashMap imageCache; - private final HashMap functionImageCache; - private final PropertyChangeSupport changeSupport; + protected final HashMap imageCache; + protected final HashMap functionImageCache; + protected final PropertyChangeSupport changeSupport; public H2PersistenceService() { - connect(); + initConnect(); imageCache = new HashMap<>(); functionImageCache = new HashMap<>(); changeSupport = new PropertyChangeSupport(this); setJCSPropertiesAsSystemProperties(); } - private void connect() { + private void initConnect() { + connect(); + } + + protected void connect() { Logger.debug("Connecting to: " + System.getProperty("norm.jdbcUrl") + " with db user: " + System.getProperty("norm.user")); database = new Database(); database.setSqlMaker(new H2SqlMaker()); } + @Override public void addPropertyChangeListener(PropertyChangeListener listener) { changeSupport.addPropertyChangeListener(listener); } + @Override public void removePropertyChangeListener(PropertyChangeListener listener) { changeSupport.removePropertyChangeListener(listener); } @@ -848,7 +854,7 @@ public synchronized void removeAllRoutes() { changeSupport.firePropertyChange("data.routes.deleted", null, null); } - private void setJCSPropertiesAsSystemProperties() { + protected void setJCSPropertiesAsSystemProperties() { List props = getProperties(); props.forEach(p -> { System.setProperty(p.getKey(), p.getValue()); diff --git a/src/main/java/jcs/persistence/util/H2DatabaseUtil.java b/src/main/java/jcs/persistence/util/H2DatabaseUtil.java index 924bb222..439c12b7 100644 --- a/src/main/java/jcs/persistence/util/H2DatabaseUtil.java +++ b/src/main/java/jcs/persistence/util/H2DatabaseUtil.java @@ -38,16 +38,16 @@ public class H2DatabaseUtil { - protected static final String JCS_DB_NAME = "jcs-db"; + public static final String JCS_DB_NAME = "jcs-db"; - protected static final String SCHEMA = ";SCHEMA=jcs"; - protected static final String DB_MODE = ";AUTO_SERVER=TRUE;DATABASE_TO_LOWER=TRUE"; + public static final String SCHEMA = ";SCHEMA=jcs"; + public static final String DB_MODE = ";AUTO_SERVER=TRUE;DATABASE_TO_LOWER=TRUE"; protected static final String ADMIN_USER = "SA"; protected static final String ADMIN_PWD = "jcs"; protected static final String JCS_USER = "jcs"; protected static final String JCS_PWD = "repo"; - protected static final String JDBC_PRE = "jdbc:h2:"; + public static final String JDBC_PRE = "jdbc:h2:"; protected static final String DB_CREATE_DDL = "jcs-db.sql"; diff --git a/src/main/java/jcs/ui/JCSFrame.java b/src/main/java/jcs/ui/JCSFrame.java index b4225329..7ed6e4d9 100755 --- a/src/main/java/jcs/ui/JCSFrame.java +++ b/src/main/java/jcs/ui/JCSFrame.java @@ -946,13 +946,14 @@ private boolean QuitApp() { int result = JOptionPane.showConfirmDialog(this, "Are you sure you want to exit JCS?", "Exit JCS", JOptionPane.YES_NO_OPTION); if (result == JOptionPane.YES_OPTION) { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - setVisible(false); - dispose(); //Disconnect Command stations JCS.getJcsCommandStation().switchPower(false); JCS.getJcsCommandStation().disconnect(); + setVisible(false); + dispose(); + //Force close ports SerialPortUtil.closeAllPorts(); Logger.debug("Shutting down"); diff --git a/src/main/java/jcs/ui/layout/LayoutPanel.java b/src/main/java/jcs/ui/layout/LayoutPanel.java index 46c58f4a..4f14ede6 100755 --- a/src/main/java/jcs/ui/layout/LayoutPanel.java +++ b/src/main/java/jcs/ui/layout/LayoutPanel.java @@ -966,7 +966,7 @@ private class Powerlistener implements PowerEventListener { @Override public void onPowerChange(PowerEvent event) { - Logger.info("Track Power is " + (event.isPower() ? "on" : "off")); + //Logger.info("Track Power is " + (event.isPower() ? "on" : "off")); if (!event.isPower() && autoPilotBtn.isSelected()) { autoPilotBtn.doClick(); diff --git a/src/test/java/jcs/commandStation/autopilot/AutoPilotTest.java b/src/test/java/jcs/commandStation/autopilot/AutoPilotTest.java index 0d8af3d2..d77be21c 100644 --- a/src/test/java/jcs/commandStation/autopilot/AutoPilotTest.java +++ b/src/test/java/jcs/commandStation/autopilot/AutoPilotTest.java @@ -60,7 +60,7 @@ public class AutoPilotTest { private List sensorHandlerEvents; public AutoPilotTest() { - System.setProperty("persistenceService", "jcs.persistence.H2PersistenceService"); + System.setProperty("persistenceService", "jcs.persistence.TestH2PersistenceService"); System.setProperty("do.not.simulate.virtual.drive", "true"); System.setProperty("state.machine.stepTest", "false"); testHelper = PersistenceTestHelper.getInstance(); diff --git a/src/test/java/jcs/commandStation/autopilot/state/StateMachineStepByStepTest.java b/src/test/java/jcs/commandStation/autopilot/state/StateMachineStepByStepTest.java index bde9a609..8176abf4 100644 --- a/src/test/java/jcs/commandStation/autopilot/state/StateMachineStepByStepTest.java +++ b/src/test/java/jcs/commandStation/autopilot/state/StateMachineStepByStepTest.java @@ -50,7 +50,7 @@ public class StateMachineStepByStepTest { private Dispatcher dispatcher; public StateMachineStepByStepTest() { - System.setProperty("persistenceService", "jcs.persistence.H2PersistenceService"); + System.setProperty("persistenceService", "jcs.persistence.TestH2PersistenceService"); //Switch the Virtual Simulator OFF as it will interfeare with this step test System.setProperty("do.not.simulate.virtual.drive", "true"); System.setProperty("state.machine.stepTest", "true"); diff --git a/src/test/java/jcs/commandStation/autopilot/state/StateMachineThreadTest.java b/src/test/java/jcs/commandStation/autopilot/state/StateMachineThreadTest.java index 84859fdb..04760a8f 100644 --- a/src/test/java/jcs/commandStation/autopilot/state/StateMachineThreadTest.java +++ b/src/test/java/jcs/commandStation/autopilot/state/StateMachineThreadTest.java @@ -56,7 +56,7 @@ public class StateMachineThreadTest { private final ExecutorService executor; public StateMachineThreadTest() { - System.setProperty("persistenceService", "jcs.persistence.H2PersistenceService"); + System.setProperty("persistenceService", "jcs.persistence.TestH2PersistenceService"); System.setProperty("do.not.simulate.virtual.drive", "true"); System.setProperty("state.machine.stepTest", "false"); diff --git a/src/test/java/jcs/commandStation/dccex/DccExMessageTest.java b/src/test/java/jcs/commandStation/dccex/DccExMessageTest.java index d2f11623..a479466c 100644 --- a/src/test/java/jcs/commandStation/dccex/DccExMessageTest.java +++ b/src/test/java/jcs/commandStation/dccex/DccExMessageTest.java @@ -15,7 +15,6 @@ */ package jcs.commandStation.dccex; -import jcs.commandStation.dccex.DccExMessage; import org.junit.After; import static org.junit.Assert.assertEquals; import org.junit.Before; @@ -28,6 +27,7 @@ public class DccExMessageTest { public DccExMessageTest() { + System.setProperty("persistenceService", "jcs.persistence.TestH2PersistenceService"); } @Before diff --git a/src/test/java/jcs/commandStation/esu/ecos/AccessoryManagerTest.java b/src/test/java/jcs/commandStation/esu/ecos/AccessoryManagerTest.java index b37faa9f..0f5bffb2 100644 --- a/src/test/java/jcs/commandStation/esu/ecos/AccessoryManagerTest.java +++ b/src/test/java/jcs/commandStation/esu/ecos/AccessoryManagerTest.java @@ -29,6 +29,7 @@ public class AccessoryManagerTest { public AccessoryManagerTest() { + System.setProperty("persistenceService", "jcs.persistence.TestH2PersistenceService"); } @BeforeEach diff --git a/src/test/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImplTest.java b/src/test/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImplTest.java index 55d090c5..44319049 100644 --- a/src/test/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImplTest.java +++ b/src/test/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImplTest.java @@ -43,7 +43,7 @@ public class EsuEcosCommandStationImplTest { public EsuEcosCommandStationImplTest() { System.setProperty("message.debug", "true"); - System.setProperty("persistenceService", "jcs.persistence.H2PersistenceService"); + System.setProperty("persistenceService", "jcs.persistence.TestH2PersistenceService"); System.setProperty("connection.always.virtual", "true"); testHelper = PersistenceTestHelper.getInstance(); @@ -68,6 +68,7 @@ public void tearDown() { } private CommandStationBean getEcosAsDefaultCommandStationBean() { + CommandStationBean ecosCommandStationBean = PersistenceFactory.getService().getDefaultCommandStation(); if (ecosCommandStationBean == null) { @@ -162,7 +163,6 @@ public void testGetCommandStationInfo() { // assertEquals(expResult, result); // } // } - /** * Test of getDevices method, of class EsuEcosCommandStationImpl. */ @@ -185,7 +185,6 @@ public void testGetCommandStationInfo() { // assertEquals(expResult, result); // } // } - /** * Test of getIp method, of class EsuEcosCommandStationImpl. */ @@ -410,7 +409,6 @@ public void testGetAccessories() { // assertEquals(expResult, result); // } // } - /** * Test of getFeedbackModules method, of class EsuEcosCommandStationImpl. */ diff --git a/src/test/java/jcs/commandStation/esu/ecos/FeedbackManagerTest.java b/src/test/java/jcs/commandStation/esu/ecos/FeedbackManagerTest.java index a5799bed..142fdf4e 100644 --- a/src/test/java/jcs/commandStation/esu/ecos/FeedbackManagerTest.java +++ b/src/test/java/jcs/commandStation/esu/ecos/FeedbackManagerTest.java @@ -28,6 +28,7 @@ public class FeedbackManagerTest { public FeedbackManagerTest() { + System.setProperty("persistenceService", "jcs.persistence.TestH2PersistenceService"); } @BeforeEach diff --git a/src/test/java/jcs/commandStation/esu/ecos/LocomotiveManagerTest.java b/src/test/java/jcs/commandStation/esu/ecos/LocomotiveManagerTest.java index 5f56f21f..a15e2c86 100644 --- a/src/test/java/jcs/commandStation/esu/ecos/LocomotiveManagerTest.java +++ b/src/test/java/jcs/commandStation/esu/ecos/LocomotiveManagerTest.java @@ -36,6 +36,7 @@ public class LocomotiveManagerTest { public LocomotiveManagerTest() { + System.setProperty("persistenceService", "jcs.persistence.TestH2PersistenceService"); } @BeforeEach diff --git a/src/test/java/jcs/commandStation/marklin/cs/MarklinCSTest.java b/src/test/java/jcs/commandStation/marklin/cs/MarklinCSTest.java index 0b603de2..20537f71 100644 --- a/src/test/java/jcs/commandStation/marklin/cs/MarklinCSTest.java +++ b/src/test/java/jcs/commandStation/marklin/cs/MarklinCSTest.java @@ -36,7 +36,7 @@ public class MarklinCSTest { //controller.skip.init public MarklinCSTest() { - + System.setProperty("persistenceService", "jcs.persistence.TestH2PersistenceService"); //JCS.getJcsCommandStation().disconnect(); //When running in a batch the default command station could be different.. //CommandStationBean marklinCs = PersistenceFactory.getService().getCommandStation("marklin.cs"); diff --git a/src/test/java/jcs/commandStation/marklin/parser/ChannelDataParserTest.java b/src/test/java/jcs/commandStation/marklin/parser/ChannelDataParserTest.java deleted file mode 100644 index ad5c6c2a..00000000 --- a/src/test/java/jcs/commandStation/marklin/parser/ChannelDataParserTest.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright 2023 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.commandStation.marklin.parser; - -import jcs.entities.ChannelBean; -import jcs.commandStation.marklin.cs.can.CanMessage; -import org.junit.Before; - -/** - * - * @author frans - */ -public class ChannelDataParserTest { - - private CanMessage chan1; - private CanMessage chan2; - private CanMessage chan3; - private CanMessage chan4; - private ChannelBean channel1; - private ChannelBean channel2; - private ChannelBean channel3; - private ChannelBean channel4; - - public ChannelDataParserTest() { - } - - @Before - public void setUp() { - chan1 = new CanMessage(new byte[]{0x00, 0x3a, 0x37, 0x7f, 0x05, 0x63, 0x73, 0x45, (byte) 0x8c, 0x01, 0x00, 0x00, 0x00}); - chan1.addResponse(new CanMessage(new byte[]{0x00, 0x3b, 0x03, 0x01, 0x08, 0x01, (byte) 0xfd, 0x30, (byte) 0xf0, (byte) 0xe0, (byte) 0xc0, 0x00, 0x00})); - chan1.addResponse(new CanMessage(new byte[]{0x00, 0x3b, 0x03, 0x02, 0x08, 0x02, 0x28, 0x02, 0x40, 0x02, 0x58, 0x02, (byte) 0x94})); - chan1.addResponse(new CanMessage(new byte[]{0x00, 0x3b, 0x03, 0x03, 0x08, 0x4d, 0x41, 0x49, 0x4e, 0x00, 0x30, 0x2e, 0x30})); - chan1.addResponse(new CanMessage(new byte[]{0x00, 0x3b, 0x03, 0x04, 0x08, 0x30, 0x00, 0x35, 0x2e, 0x35, 0x30, 0x00, 0x41})); - chan1.addResponse(new CanMessage(new byte[]{0x00, 0x3b, 0x03, 0x05, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})); - chan1.addResponse(new CanMessage(new byte[]{0x00, 0x3b, 0x03, 0x26, 0x06, 0x63, 0x73, 0x45, (byte) 0x8c, 0x01, 0x05, 0x00, 0x00})); - - this.channel1 = new ChannelBean(); - this.channel1.setNumber(1); - this.channel1.setScale(-3); - this.channel1.setColorMax(48); - this.channel1.setColorGreen(240); - this.channel1.setColorYellow(224); - this.channel1.setColorRed(192); - this.channel1.setStartValue(0.0); - this.channel1.setRangeMax(552); - this.channel1.setRangeGreen(576); - this.channel1.setRangeYellow(600); - this.channel1.setRangeRed(660); - this.channel1.setName("MAIN"); - this.channel1.setEndValue(5.5); - this.channel1.setUnit("A"); - - chan2 = new CanMessage(new byte[]{0x00, 0x3a, 0x37, 0x7f, 0x05, 0x63, 0x73, 0x45, (byte) 0x8c, 0x02, 0x00, 0x00, 0x00}); - chan2.addResponse(new CanMessage(new byte[]{0x00, 0x3b, 0x03, 0x01, 0x08, 0x02, (byte) 0xfd, 0x30, (byte) 0xf0, (byte) 0xe0, (byte) 0xc0, 0x00, 0x00})); - chan2.addResponse(new CanMessage(new byte[]{0x00, 0x3b, 0x03, 0x02, 0x08, 0x01, 0x4a, 0x01, 0x6b, 0x02, 0x31, 0x02, (byte) 0xf7})); - chan2.addResponse(new CanMessage(new byte[]{0x00, 0x3b, 0x03, 0x03, 0x08, 0x50, 0x52, 0x4f, 0x47, 0x00, 0x30, 0x2e, 0x30})); - chan2.addResponse(new CanMessage(new byte[]{0x00, 0x3b, 0x03, 0x04, 0x08, 0x30, 0x00, 0x32, 0x2e, 0x33, 0x30, 0x00, 0x41})); - chan2.addResponse(new CanMessage(new byte[]{0x00, 0x3b, 0x03, 0x05, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})); - chan2.addResponse(new CanMessage(new byte[]{0x00, 0x3b, 0x03, 0x26, 0x06, 0x63, 0x73, 0x45, (byte) 0x8c, 0x02, 0x05, 0x00, 0x00})); - - this.channel2 = new ChannelBean(); - this.channel2.setNumber(2); - this.channel2.setScale(-3); - this.channel2.setColorMax(48); - this.channel2.setColorGreen(240); - this.channel2.setColorYellow(224); - this.channel2.setColorRed(192); - this.channel2.setStartValue(0.0); - this.channel2.setRangeMax(330); - this.channel2.setRangeGreen(363); - this.channel2.setRangeYellow(561); - this.channel2.setRangeRed(759); - this.channel2.setName("PROG"); - this.channel2.setEndValue(2.3); - this.channel2.setUnit("A"); - - chan3 = new CanMessage(new byte[]{0x00, 0x3a, 0x37, 0x7f, 0x05, 0x63, 0x73, 0x45, (byte) 0x8c, 0x03, 0x00, 0x00, 0x00}); - chan3.addResponse(new CanMessage(new byte[]{0x00, 0x3b, 0x03, 0x01, 0x08, 0x03, (byte) 0xfd, (byte) 0xc0, 0x0c, 0x30, (byte) 0xc0, 0x00, 0x00})); - chan3.addResponse(new CanMessage(new byte[]{0x00, 0x3b, 0x03, 0x02, 0x08, 0x00, (byte) 0xc2, 0x00, (byte) 0xfc, 0x02, 0x1f, 0x02, (byte) 0x93})); - chan3.addResponse(new CanMessage(new byte[]{0x00, 0x3b, 0x03, 0x03, 0x08, 0x56, 0x4f, 0x4c, 0x54, 0x00, 0x31, 0x30, 0x2e})); - chan3.addResponse(new CanMessage(new byte[]{0x00, 0x3b, 0x03, 0x04, 0x08, 0x30, 0x30, 0x00, 0x32, 0x37, 0x2e, 0x30, 0x30})); - chan3.addResponse(new CanMessage(new byte[]{0x00, 0x3b, 0x03, 0x05, 0x08, 0x00, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})); - chan3.addResponse(new CanMessage(new byte[]{0x00, 0x3b, 0x03, 0x26, 0x06, 0x63, 0x73, 0x45, (byte) 0x8c, 0x03, 0x05, 0x00, 0x00})); - - this.channel3 = new ChannelBean(); - this.channel3.setNumber(3); - this.channel3.setScale(-3); - this.channel3.setColorMax(192); - this.channel3.setColorGreen(12); - this.channel3.setColorYellow(48); - this.channel3.setColorRed(192); - this.channel3.setStartValue(10.0); - this.channel3.setRangeMax(194); - this.channel3.setRangeGreen(252); - this.channel3.setRangeYellow(543); - this.channel3.setRangeRed(659); - this.channel3.setName("VOLT"); - this.channel3.setEndValue(27.0); - this.channel3.setUnit("V"); - - chan4 = new CanMessage(new byte[]{0x00, 0x3a, 0x37, 0x7f, 0x05, 0x63, 0x73, 0x45, (byte) 0x8c, 0x04, 0x00, 0x00, 0x00}); - chan4.addResponse(new CanMessage(new byte[]{0x00, 0x3b, 0x03, 0x01, 0x08, 0x04, 0x00, 0x0c, 0x08, (byte) 0xf0, (byte) 0xc0, 0x00, 0x00})); - chan4.addResponse(new CanMessage(new byte[]{0x00, 0x3b, 0x03, 0x02, 0x08, 0x00, 0x79, 0x00, (byte) 0x91, 0x00, (byte) 0xa9, 0x00, (byte) 0xc1})); - chan4.addResponse(new CanMessage(new byte[]{0x00, 0x3b, 0x03, 0x03, 0x08, 0x54, 0x45, 0x4d, 0x50, 0x00, 0x30, 0x2e, 0x30})); - chan4.addResponse(new CanMessage(new byte[]{0x00, 0x3b, 0x03, 0x04, 0x08, 0x00, 0x38, 0x30, 0x2e, 0x30, 0x00, 0x43, 0x00})); - chan4.addResponse(new CanMessage(new byte[]{0x00, 0x3b, 0x03, 0x26, 0x06, 0x63, 0x73, 0x45, (byte) 0x8c, 0x04, 0x04, 0x00, 0x00})); - - this.channel4 = new ChannelBean(); - this.channel4.setNumber(4); - this.channel4.setScale(0); - this.channel4.setColorMax(12); - this.channel4.setColorGreen(8); - this.channel4.setColorYellow(240); - this.channel4.setColorRed(192); - this.channel4.setStartValue(0.0); - this.channel4.setRangeMax(121); - this.channel4.setRangeGreen(145); - this.channel4.setRangeYellow(169); - this.channel4.setRangeRed(193); - this.channel4.setName("TEMP"); - this.channel4.setEndValue(80.0); - this.channel4.setUnit("C"); - } - - //@Test -// public void testGetChannel1() { -// System.out.println("getChannel1"); -//// ChannelDataParser instance = new ChannelDataParser(chan1); -// Logger.debug(instance); -// -// ChannelBean expResult = channel1; -// ChannelBean result = instance.getChannel(); -// assertEquals(expResult, result); -// -////expected: -//// but was: -// } - - //@Test -// public void testGetChannel2() { -// System.out.println("getChannel2"); -// //ChannelDataParser instance = new ChannelDataParser(chan2); -// Logger.debug(instance); -// -// ChannelBean expResult = channel2; -// ChannelBean result = instance.getChannel(); -// assertEquals(expResult, result); -// -////expected: -//// but was: -// } - - //@Test -// public void testGetChannel3() { -// System.out.println("getChannel3"); -// //ChannelDataParser instance = new ChannelDataParser(chan3); -// //Logger.debug(instance); -// -// ChannelBean expResult = channel3; -// ChannelBean result = instance.getChannel(); -// assertEquals(expResult, result); -// } - - //@Test -// public void testGetChannel4() { -// System.out.println("getChannel4"); -// // ChannelDataParser instance = new ChannelDataParser(chan4); -// //Logger.debug(instance); -// -// ChannelBean expResult = channel4; -// ChannelBean result = instance.getChannel(); -// assertEquals(expResult, result); -// } - -} diff --git a/src/test/java/jcs/persistence/PersistenceServiceTest.java b/src/test/java/jcs/persistence/PersistenceServiceTest.java index 80dd084c..5c16c652 100644 --- a/src/test/java/jcs/persistence/PersistenceServiceTest.java +++ b/src/test/java/jcs/persistence/PersistenceServiceTest.java @@ -57,7 +57,7 @@ public class PersistenceServiceTest { private final List blocks; public PersistenceServiceTest() { - System.setProperty("persistenceService", "jcs.persistence.H2PersistenceService"); + System.setProperty("persistenceService", "jcs.persistence.TestH2PersistenceService"); testHelper = PersistenceTestHelper.getInstance(); @@ -262,7 +262,7 @@ public void tearDown() { * Test of getProperties method, of class PersistenceService. */ @Test - @Order(1) + @Order(1) public void testGetProperties() { System.out.println("getProperties"); PersistenceService instance = PersistenceFactory.getService(); @@ -275,7 +275,7 @@ public void testGetProperties() { * Test of getProperty method, of class PersistenceService. */ @Test - @Order(2) + @Order(2) public void testGetProperty() { System.out.println("getProperty"); String key = "k2"; @@ -289,7 +289,7 @@ public void testGetProperty() { * Test of persist method, of class PersistenceService. */ @Test - @Order(3) + @Order(3) public void testPersistJCSPropertyBean() { System.out.println("persistJCSPropertyBean"); JCSPropertyBean propertyBean = new JCSPropertyBean("k3", "v3"); @@ -313,7 +313,7 @@ public void testPersistJCSPropertyBean() { * Test of remove method, of class PersistenceService. */ @Test - @Order(4) + @Order(4) public void testRemoveJCSPropertyBean() { System.out.println("removeJCSPropertyBean"); JCSPropertyBean property = new JCSPropertyBean("k4", "v4"); @@ -332,7 +332,7 @@ public void testRemoveJCSPropertyBean() { * Test of getSensors method, of class PersistenceService. */ @Test - @Order(5) + @Order(5) public void testGetSensors() { System.out.println("getSensors"); PersistenceService instance = PersistenceFactory.getService(); @@ -346,7 +346,7 @@ public void testGetSensors() { * Test of getSensor method, of class PersistenceService. */ @Test - @Order(6) + @Order(6) public void testGetSensorString() { System.out.println("getSensorString"); String id = "65-1"; @@ -360,7 +360,7 @@ public void testGetSensorString() { * Test of getSensor method, of class PersistenceService. */ @Test - @Order(7) + @Order(7) public void testGetSensorIntegerInteger() { System.out.println("getSensorIntegerInteger"); Integer deviceId = 65; @@ -375,7 +375,7 @@ public void testGetSensorIntegerInteger() { * Test of persist method, of class PersistenceService. */ @Test - @Order(8) + @Order(8) public void testPersistSensorBean() { System.out.println("persistSensorBean"); SensorBean sensor = new SensorBean("M1P3", 65, 3, 0, 1, 0, null); @@ -400,7 +400,7 @@ public void testPersistSensorBean() { * Test of remove method, of class PersistenceService. */ @Test - @Order(9) + @Order(9) public void testRemoveSensorBean() { System.out.println("removeSensorBean"); SensorBean sensor = new SensorBean("M1P4", 65, 4, 0, 1, 0, null); @@ -423,7 +423,7 @@ public void testRemoveSensorBean() { * Test of getLocomotives method, of class PersistenceService. */ @Test - @Order(10) + @Order(10) public void testGetLocomotives() { System.out.println("getLocomotives"); PersistenceService instance = PersistenceFactory.getService(); @@ -455,7 +455,7 @@ public void testGetLocomotives() { * Test of getLocomotive method, of class PersistenceService. */ @Test - @Order(11) + @Order(11) public void testGetLocomotiveIntegerDecoderType() { System.out.println("getLocomotiveIntegerDecoderType"); Integer address = 8; @@ -492,7 +492,7 @@ public void testGetLocomotiveIntegerDecoderType() { * Test of getLocomotive method, of class PersistenceService. */ @Test - @Order(12) + @Order(12) public void testGetLocomotiveInteger() { System.out.println("getLocomotiveInteger"); Long id = 2L; @@ -523,7 +523,7 @@ public void testGetLocomotiveInteger() { * Test of persist method, of class PersistenceService. */ @Test - @Order(13) + @Order(13) public void testPersistLocomotiveBean() { System.out.println("persistLocomotiveBean"); LocomotiveBean locomotive = new LocomotiveBean(80L, "DB BR 44 100", 16393L, 80, "DB BR 44 100", "mfx", 80, 5, 0, 0, false, true, false); @@ -572,7 +572,7 @@ public void testPersistLocomotiveBean() { * Test of remove method, of class PersistenceService. */ @Test - @Order(14) + @Order(14) public void testRemoveLocomotiveBean() { System.out.println("removeLocomotiveBean"); LocomotiveBean locomotiveBean = new LocomotiveBean(70L, "To Be Removed", 16370L, 70, "To Be Removed", "mfx", 80, 5, 0, 0, false, true, false); @@ -598,7 +598,7 @@ public void testRemoveLocomotiveBean() { * Test of getTurnouts method, of class PersistenceService. */ @Test - @Order(15) + @Order(15) public void testGetTurnouts() { System.out.println("getTurnouts"); PersistenceService instance = PersistenceFactory.getService(); @@ -615,7 +615,7 @@ public void testGetTurnouts() { * Test of getSignals method, of class PersistenceService. */ @Test - @Order(16) + @Order(16) public void testGetSignals() { System.out.println("getSignals"); PersistenceService instance = PersistenceFactory.getService(); @@ -635,7 +635,7 @@ public void testGetSignals() { * Test of getAccessory method, of class PersistenceService. */ @Test - @Order(17) + @Order(17) public void testGetAccessoryById() { System.out.println("getAccessoryById"); String id = "25"; @@ -649,7 +649,7 @@ public void testGetAccessoryById() { * Test of getAccessoryByAddress method, of class PersistenceService. */ @Test - @Order(18) + @Order(18) public void testGetAccessory() { System.out.println("getAccessory"); Integer address = 7; @@ -663,7 +663,7 @@ public void testGetAccessory() { * Test of persist method, of class PersistenceService. */ @Test - @Order(19) + @Order(19) public void testPersistAccessoryBean() { System.out.println("persistAccessoryBean"); AccessoryBean accessory = new AccessoryBean("100", 100, "W 100", "rechtsweiche", 1, 2, 200, "mm", "ein_alt", "weichen", "005", "magicon_a_005_01.svg", "marklin.cs"); @@ -693,7 +693,7 @@ public void testPersistAccessoryBean() { * Test of remove method, of class PersistenceService. */ @Test - @Order(20) + @Order(20) public void testRemoveAccessoryBean() { System.out.println("removeAccessoryBean"); AccessoryBean accessory = new AccessoryBean("101", 101, "W 101", "rechtsweiche", 1, 2, 200, "mm", "ein_alt", "weichen", "005", "magicon_a_005_01.svg", "marklin.cs"); @@ -716,7 +716,7 @@ public void testRemoveAccessoryBean() { * Test of getTileBeans method, of class PersistenceService. */ @Test - @Order(21) + @Order(21) public void testGetTileBeans() { System.out.println("getTileBeans"); PersistenceService instance = PersistenceFactory.getService(); @@ -731,7 +731,7 @@ public void testGetTileBeans() { * Test of getTileBean method, of class PersistenceService. */ @Test - @Order(22) + @Order(22) public void testGetTile() { System.out.println("getTile"); Integer x = 300; @@ -746,7 +746,7 @@ public void testGetTile() { * Test of persist method, of class PersistenceService. */ @Test - @Order(23) + @Order(23) public void testPersistTileBean() { System.out.println("persistTileBean"); TileBean sw12 = new TileBean("sw-12", TileBean.TileType.SWITCH, Orientation.EAST, Direction.RIGHT, 50, 50, null, null, null); @@ -767,7 +767,7 @@ public void testPersistTileBean() { } @Test - @Order(24) + @Order(24) public void testRemoveTileBean() { System.out.println("removeTileBean"); TileBean sw13 = new TileBean("sw-13", TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 80, 50, null, null, null); @@ -789,7 +789,7 @@ public void testRemoveTileBean() { * Test of persist method, of class PersistenceService. */ @Test - @Order(25) + @Order(25) public void testPersistListTileBeans() { System.out.println("persistListTileBeans"); PersistenceService instance = PersistenceFactory.getService(); @@ -816,7 +816,7 @@ public void testPersistListTileBeans() { } @Test - @Order(26) + @Order(26) public void testPersistLotsOfTileBeans() { System.out.println("persistLotsOfTileBeans"); PersistenceService instance = PersistenceFactory.getService(); @@ -842,7 +842,7 @@ public void testPersistLotsOfTileBeans() { } @Test - @Order(27) + @Order(27) public void testGetRoutes() { System.out.println("getRoutes"); PersistenceService instance = PersistenceFactory.getService(); @@ -852,7 +852,7 @@ public void testGetRoutes() { } @Test - @Order(28) + @Order(28) public void testGetRouteString() { System.out.println("getRouteString"); PersistenceService instance = PersistenceFactory.getService(); @@ -862,7 +862,7 @@ public void testGetRouteString() { } @Test - @Order(29) + @Order(29) public void testGetRoute_String_String_String_String() { System.out.println("getRoute_string_string_string_string"); PersistenceService instance = PersistenceFactory.getService(); @@ -877,7 +877,7 @@ public void testGetRoute_String_String_String_String() { } @Test - @Order(30) + @Order(30) public void testLockRoute() { System.out.println("LockRoute"); PersistenceService instance = PersistenceFactory.getService(); @@ -907,7 +907,7 @@ public void testLockRoute() { } @Test - @Order(31) + @Order(31) public void testPersistRouteBean() { System.out.println("persistRouteBean"); RouteBean route = new RouteBean("[ct-2]->[ct-5]", "ct-2", "*", "ct-5", "*", "blue"); @@ -945,7 +945,7 @@ public void testPersistRouteBean() { } @Test - @Order(32) + @Order(32) public void testRemoveRouteBean() { System.out.println("removeRouteBean"); RouteBean routeBean = new RouteBean("[ct-5]->[ct-2]", "ct-5", "*", "ct-2", "*", "orange"); @@ -965,7 +965,7 @@ public void testRemoveRouteBean() { } @Test - @Order(33) + @Order(33) public void testGetBlocks() { System.out.println("getBlocks"); PersistenceService instance = PersistenceFactory.getService(); @@ -975,7 +975,7 @@ public void testGetBlocks() { } @Test - @Order(34) + @Order(34) public void testGetBlock() { System.out.println("getBlock"); String id = "bk-1"; @@ -986,7 +986,7 @@ public void testGetBlock() { } @Test - @Order(35) + @Order(35) public void testGetBlockByTileId() { System.out.println("getBlockByTileId"); String tileId = "bk-2"; @@ -997,7 +997,7 @@ public void testGetBlockByTileId() { } @Test - @Order(36) + @Order(36) public void testPersistBlockBean() { System.out.println("persistBlockBean"); BlockBean block = new BlockBean(); @@ -1020,7 +1020,7 @@ public void testPersistBlockBean() { } @Test - @Order(37) + @Order(37) public void testRemoveBlockBean() { System.out.println("removeBlockBean"); BlockBean block = new BlockBean(); @@ -1045,7 +1045,7 @@ public void testRemoveBlockBean() { } @Test - @Order(38) + @Order(38) public void testRemoveAllBlocks() { System.out.println("removeAllBlocks"); PersistenceService instance = PersistenceFactory.getService(); @@ -1062,7 +1062,7 @@ public void testRemoveAllBlocks() { } @Test - @Order(39) + @Order(39) public void testCommandStations() { System.out.println("commandStations"); PersistenceService instance = PersistenceFactory.getService(); diff --git a/src/test/java/jcs/persistence/TestH2PersistenceService.java b/src/test/java/jcs/persistence/TestH2PersistenceService.java new file mode 100644 index 00000000..92677bf5 --- /dev/null +++ b/src/test/java/jcs/persistence/TestH2PersistenceService.java @@ -0,0 +1,53 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.persistence; + +import com.dieselpoint.norm.Database; +import java.io.File; +import jcs.persistence.sqlmakers.H2SqlMaker; +import jcs.persistence.util.H2DatabaseUtil; +import org.tinylog.Logger; + +/** + * Persistence service to use during unit testing + */ +public class TestH2PersistenceService extends H2PersistenceService { + + public TestH2PersistenceService() { + super(); + } + + /** + * Overridden to make sure it connects to the test database + */ + @Override + protected void connect() { + String jdbcUrl = H2DatabaseUtil.JDBC_PRE + System.getProperty("user.home") + File.separator + "jcs" + File.separator + "test-" + H2DatabaseUtil.JCS_DB_NAME + H2DatabaseUtil.DB_MODE + H2DatabaseUtil.SCHEMA; + System.setProperty("norm.jdbcUrl", jdbcUrl); + + Logger.info("TESTMODE Connecting to: " + System.getProperty("norm.jdbcUrl") + " with db user: " + System.getProperty("norm.user")); + database = new Database(); + database.setSqlMaker(new H2SqlMaker()); + } + +// protected void setJCSPropertiesAsSystemProperties() { +// List props = getProperties(); +// props.forEach(p -> { +// System.setProperty(p.getKey(), p.getValue()); +// }); +// } + +} diff --git a/src/test/java/jcs/ui/layout/LayoutUtilTest.java b/src/test/java/jcs/ui/layout/LayoutUtilTest.java index 34cdba50..e8be15b1 100644 --- a/src/test/java/jcs/ui/layout/LayoutUtilTest.java +++ b/src/test/java/jcs/ui/layout/LayoutUtilTest.java @@ -30,7 +30,7 @@ public class LayoutUtilTest { public LayoutUtilTest() { System.setProperty("trackServiceSkipControllerInit", "true"); - + System.setProperty("persistenceService", "jcs.persistence.TestH2PersistenceService"); } /** diff --git a/src/test/java/jcs/ui/layout/TileTest.java b/src/test/java/jcs/ui/layout/TileTest.java index 75c2fd1a..24a09f45 100644 --- a/src/test/java/jcs/ui/layout/TileTest.java +++ b/src/test/java/jcs/ui/layout/TileTest.java @@ -34,6 +34,7 @@ public class TileTest { public TileTest() { + System.setProperty("persistenceService", "jcs.persistence.TestH2PersistenceService"); } @Test diff --git a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossLeftEast.java b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossLeftEast.java index f388fdb0..5b1bfed4 100644 --- a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossLeftEast.java +++ b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossLeftEast.java @@ -34,7 +34,7 @@ public class AStarCrossLeftEast { private final PersistenceTestHelper testHelper; public AStarCrossLeftEast() { - System.setProperty("persistenceService", "jcs.persistence.H2PersistenceService"); + System.setProperty("persistenceService", "jcs.persistence.TestH2PersistenceService"); testHelper = PersistenceTestHelper.getInstance(); } diff --git a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossLeftSouth.java b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossLeftSouth.java index aa13a460..0733722e 100644 --- a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossLeftSouth.java +++ b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossLeftSouth.java @@ -33,7 +33,7 @@ public class AStarCrossLeftSouth { private final PersistenceTestHelper testHelper; public AStarCrossLeftSouth() { - System.setProperty("persistenceService", "jcs.persistence.H2PersistenceService"); + System.setProperty("persistenceService", "jcs.persistence.TestH2PersistenceService"); testHelper = PersistenceTestHelper.getInstance(); } diff --git a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossRightEast.java b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossRightEast.java index 53b2a7e8..630d360d 100644 --- a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossRightEast.java +++ b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossRightEast.java @@ -33,7 +33,7 @@ public class AStarCrossRightEast { private final PersistenceTestHelper testHelper; public AStarCrossRightEast() { - System.setProperty("persistenceService", "jcs.persistence.H2PersistenceService"); + System.setProperty("persistenceService", "jcs.persistence.TestH2PersistenceService"); testHelper = PersistenceTestHelper.getInstance(); } diff --git a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossRightSouth.java b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossRightSouth.java index 4ad7e132..326fc061 100644 --- a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossRightSouth.java +++ b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossRightSouth.java @@ -33,7 +33,7 @@ public class AStarCrossRightSouth { private final PersistenceTestHelper testHelper; public AStarCrossRightSouth() { - System.setProperty("persistenceService", "jcs.persistence.H2PersistenceService"); + System.setProperty("persistenceService", "jcs.persistence.TestH2PersistenceService"); testHelper = PersistenceTestHelper.getInstance(); } diff --git a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossingTest.java b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossingTest.java index ca7e2626..3ec3ee44 100644 --- a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossingTest.java +++ b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossingTest.java @@ -33,7 +33,7 @@ public class AStarCrossingTest { private final PersistenceTestHelper testHelper; public AStarCrossingTest() { - System.setProperty("persistenceService", "jcs.persistence.H2PersistenceService"); + System.setProperty("persistenceService", "jcs.persistence.TestH2PersistenceService"); testHelper = PersistenceTestHelper.getInstance(); } diff --git a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftEast.java b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftEast.java index 83ab13a6..ed4cfd57 100644 --- a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftEast.java +++ b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftEast.java @@ -33,7 +33,7 @@ public class AStarSwitchLeftEast { private final PersistenceTestHelper testHelper; public AStarSwitchLeftEast() { - System.setProperty("persistenceService", "jcs.persistence.H2PersistenceService"); + System.setProperty("persistenceService", "jcs.persistence.TestH2PersistenceService"); testHelper = PersistenceTestHelper.getInstance(); } diff --git a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftNorth.java b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftNorth.java index cf091c8f..131af219 100644 --- a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftNorth.java +++ b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftNorth.java @@ -33,7 +33,7 @@ public class AStarSwitchLeftNorth { private final PersistenceTestHelper testHelper; public AStarSwitchLeftNorth() { - System.setProperty("persistenceService", "jcs.persistence.H2PersistenceService"); + System.setProperty("persistenceService", "jcs.persistence.TestH2PersistenceService"); testHelper = PersistenceTestHelper.getInstance(); } diff --git a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftSouth.java b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftSouth.java index 772669e6..fd4af1b1 100644 --- a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftSouth.java +++ b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftSouth.java @@ -33,7 +33,7 @@ public class AStarSwitchLeftSouth { private final PersistenceTestHelper testHelper; public AStarSwitchLeftSouth() { - System.setProperty("persistenceService", "jcs.persistence.H2PersistenceService"); + System.setProperty("persistenceService", "jcs.persistence.TestH2PersistenceService"); testHelper = PersistenceTestHelper.getInstance(); } diff --git a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftWest.java b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftWest.java index f980b320..92823c15 100644 --- a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftWest.java +++ b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftWest.java @@ -33,7 +33,7 @@ public class AStarSwitchLeftWest { private final PersistenceTestHelper testHelper; public AStarSwitchLeftWest() { - System.setProperty("persistenceService", "jcs.persistence.H2PersistenceService"); + System.setProperty("persistenceService", "jcs.persistence.TestH2PersistenceService"); testHelper = PersistenceTestHelper.getInstance(); } diff --git a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarTest.java b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarTest.java index f7d905d2..7ed0f5de 100644 --- a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarTest.java +++ b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarTest.java @@ -34,7 +34,7 @@ public class AStarTest { private final PersistenceTestHelper testHelper; public AStarTest() { - System.setProperty("persistenceService", "jcs.persistence.H2PersistenceService"); + System.setProperty("persistenceService", "jcs.persistence.TestH2PersistenceService"); testHelper = PersistenceTestHelper.getInstance(); } diff --git a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarTestWithDirection.java b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarTestWithDirection.java index ccd8b00a..dda4c26e 100644 --- a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarTestWithDirection.java +++ b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarTestWithDirection.java @@ -34,7 +34,7 @@ public class AStarTestWithDirection { private final PersistenceTestHelper testHelper; public AStarTestWithDirection() { - System.setProperty("persistenceService", "jcs.persistence.H2PersistenceService"); + System.setProperty("persistenceService", "jcs.persistence.TestH2PersistenceService"); testHelper = PersistenceTestHelper.getInstance(); } From 8561432aa0e5948444ec9299b7ce8573bbe682ee Mon Sep 17 00:00:00 2001 From: Frans Jacobs <41232225+fransjacobs@users.noreply.github.com> Date: Thu, 8 May 2025 20:58:21 +0200 Subject: [PATCH 52/70] Test on GitHub still fail adding -verbose tocheck --- pom.xml | 4 +- .../marklin/cs/net/CSHTTPConnectionImpl.java | 89 +++---------------- .../marklin/cs/net/CSHTTPConnectionVirt.java | 19 ++-- .../java/jcs/persistence/util/EntityInfo.java | 4 +- src/main/java/jcs/ui/layout/tiles/Tile.java | 8 +- .../jcs/ui/settings/CommandStationPanel.java | 10 ++- .../table/model/AbstractBeanTableModel.java | 11 +-- .../marklin/cs/MarklinCSTest.java | 4 +- .../persistence/PersistenceServiceTest.java | 14 +-- 9 files changed, 53 insertions(+), 110 deletions(-) diff --git a/pom.xml b/pom.xml index 631b45b8..7a8f7a8e 100644 --- a/pom.xml +++ b/pom.xml @@ -210,7 +210,8 @@ maven-compiler-plugin 3.13.0 - --enable-preview + + --enable-preview,-verbose 21 true @@ -239,6 +240,7 @@ 3.3.1 UTF-8 + ${project.build.sourceEncoding} db:encryptable db diff --git a/src/main/java/jcs/commandStation/marklin/cs/net/CSHTTPConnectionImpl.java b/src/main/java/jcs/commandStation/marklin/cs/net/CSHTTPConnectionImpl.java index b9f80745..53e2d47c 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/net/CSHTTPConnectionImpl.java +++ b/src/main/java/jcs/commandStation/marklin/cs/net/CSHTTPConnectionImpl.java @@ -18,16 +18,13 @@ import java.awt.Image; import java.awt.image.BufferedImage; import java.io.BufferedReader; -import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.net.InetAddress; import java.net.MalformedURLException; +import java.net.URI; import java.net.URL; import java.net.URLConnection; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; import javax.imageio.IIOException; import javax.imageio.ImageIO; import org.tinylog.Logger; @@ -92,7 +89,7 @@ private static String fixURL(String url) { public String getLocomotivesFile() { StringBuilder locs = new StringBuilder(); try { - URL cs = new URL(HTTP + csAddress.getHostAddress() + CONFIG + LOCOMOTIVE); + URL cs = URI.create(HTTP + csAddress.getHostAddress() + CONFIG + LOCOMOTIVE).toURL(); URLConnection lc = cs.openConnection(); try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { String inputLine; @@ -113,7 +110,7 @@ public String getLocomotivesFile() { public String getLocomotivesJSON() { StringBuilder loks = new StringBuilder(); try { - URL url = new URL(HTTP + csAddress.getHostAddress() + LOCOMOTIVE_JSON); + URL url = URI.create(HTTP + csAddress.getHostAddress() + LOCOMOTIVE_JSON).toURL(); URLConnection lc = url.openConnection(); try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { String inputLine; @@ -134,7 +131,7 @@ public String getLocomotivesJSON() { public String getAccessoriesFile() { StringBuilder locs = new StringBuilder(); try { - URL url = new URL(HTTP + csAddress.getHostAddress() + CONFIG + MAGNETARTIKEL); + URL url = URI.create(HTTP + csAddress.getHostAddress() + CONFIG + MAGNETARTIKEL).toURL(); URLConnection lc = url.openConnection(); try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { String inputLine; @@ -155,7 +152,7 @@ public String getAccessoriesFile() { public String getFunctionsSvgJSON() { StringBuilder json = new StringBuilder(); try { - URL url = new URL(HTTP + csAddress.getHostAddress() + FUNCTION_SVG_URL); + URL url = URI.create(HTTP + csAddress.getHostAddress() + FUNCTION_SVG_URL).toURL(); URLConnection lc = url.openConnection(); try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { String inputLine; @@ -176,7 +173,7 @@ public String getFunctionsSvgJSON() { public String getAccessoriesSvgJSON() { StringBuilder json = new StringBuilder(); try { - URL url = new URL(HTTP + csAddress.getHostAddress() + ACCESSORIES_SVG_URL); + URL url = URI.create(HTTP + csAddress.getHostAddress() + ACCESSORIES_SVG_URL).toURL(); URLConnection lc = url.openConnection(); try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { String inputLine; @@ -197,7 +194,7 @@ public String getAccessoriesSvgJSON() { public String getAccessoriesJSON() { StringBuilder json = new StringBuilder(); try { - URL url = new URL(HTTP + csAddress.getHostAddress() + ACCESSORIES_URL); + URL url = URI.create(HTTP + csAddress.getHostAddress() + ACCESSORIES_URL).toURL(); URLConnection lc = url.openConnection(); try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { String inputLine; @@ -219,7 +216,7 @@ public String getDevicesJSON() { StringBuilder device = new StringBuilder(); if (this.csAddress != null && csAddress.getHostAddress() != null) { try { - URL url = new URL(HTTP + csAddress.getHostAddress() + DEVICES); + URL url = URI.create(HTTP + csAddress.getHostAddress() + DEVICES).toURL(); URLConnection lc = url.openConnection(); try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { String inputLine; @@ -243,7 +240,7 @@ public String getDevicesJSON() { public String getInfoFile() { StringBuilder device = new StringBuilder(); try { - URL url = new URL(HTTP + csAddress.getHostAddress() + CONFIG + DEVICE); + URL url = URI.create(HTTP + csAddress.getHostAddress() + CONFIG + DEVICE).toURL(); URLConnection lc = url.openConnection(); try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { String inputLine; @@ -265,7 +262,7 @@ public String getInfoJSON() { StringBuilder device = new StringBuilder(); if (this.csAddress != null && csAddress.getHostAddress() != null) { try { - URL url = new URL(HTTP + csAddress.getHostAddress() + CS3_INFO_JSON); + URL url = URI.create(HTTP + csAddress.getHostAddress() + CS3_INFO_JSON).toURL(); URLConnection lc = url.openConnection(); try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { String inputLine; @@ -291,9 +288,9 @@ public Image getLocomotiveImage(String imageName) { try { URL url; if (cs3) { - url = new URL(fixURL(HTTP + csAddress.getHostAddress() + IMAGE_FOLDER_CS3 + imageName + ".png")); + url = URI.create(fixURL(HTTP + csAddress.getHostAddress() + IMAGE_FOLDER_CS3 + imageName + ".png")).toURL(); } else { - url = new URL(fixURL(HTTP + csAddress.getHostAddress() + IMAGE_FOLDER_CS2 + imageName + ".png")); + url = URI.create(fixURL(HTTP + csAddress.getHostAddress() + IMAGE_FOLDER_CS2 + imageName + ".png")).toURL(); } Logger.trace("image URL: " + url); @@ -312,7 +309,7 @@ public Image getFunctionImageCS2(String imageName) { String iurl = fixURL(HTTP + csAddress.getHostAddress() + FUNCTION_IMAGE_FOLDER + imageName + ".png"); try { - URL url = new URL(iurl); + URL url = URI.create(iurl).toURL(); image = ImageIO.read(url); } catch (IIOException iio) { //Image not avalable @@ -329,64 +326,4 @@ public Image getFunctionImageCS2(String imageName) { public void close() throws Exception { } -// public static void main(String[] args) throws Exception { -// boolean cs3 = true; -// -// InetAddress inetAddr; -// if (cs3) { -// inetAddr = InetAddress.getByName("192.168.178.180"); -// } else { -// inetAddr = InetAddress.getByName("192.168.178.86"); -// } -// CSHTTPConnectionImpl hc = new CSHTTPConnectionImpl(inetAddr); -// hc.setCs3(cs3); -// -// String serial; -// if (cs3) { -// serial = "2374"; -// } else { -// serial = "13344"; -// } -// -//// Path fPath = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "cache" + File.separator + "zfunctions"); -//// if (!Files.exists(fPath)) { -//// Files.createDirectories(fPath); -//// Logger.trace("Created new directory " + fPath); -//// } -//// -//// Path aPath = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "cache" + File.separator + "zaccessories"); -//// if (!Files.exists(aPath)) { -//// Files.createDirectories(aPath); -//// Logger.trace("Created new directory " + aPath); -//// } -// Path info = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "info.json"); -// String json = hc.getInfoJSON(); -// Files.writeString(info, json); -// -// Path devices = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "devices.json"); -// json = hc.getDevicesJSON(); -// Files.writeString(devices, json); -// -// Path locomotives = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "locomotives.json"); -// json = hc.getLocomotivesJSON(); -// Files.writeString(locomotives, json); -// -// Path accessories = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "mags.json"); -// json = hc.getAccessoriesJSON(); -// Files.writeString(accessories, json); -// -// Path fcticons = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "fcticons.json"); -// json = hc.getFunctionsSvgJSON(); -// Files.writeString(fcticons, json); -// -// Path magicons = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "magicons.json"); -// json = hc.getAccessoriesSvgJSON(); -// Files.writeString(magicons, json); -// -// Path accessoryFile = Paths.get(System.getProperty("user.home") + File.separator + "jcs" + File.separator + "magnetartikel.cs2"); -// String file = hc.getAccessoriesFile(); -// Logger.trace(file); -// Files.writeString(accessoryFile, file); -// -// } } diff --git a/src/main/java/jcs/commandStation/marklin/cs/net/CSHTTPConnectionVirt.java b/src/main/java/jcs/commandStation/marklin/cs/net/CSHTTPConnectionVirt.java index d0a449d1..e18a0080 100644 --- a/src/main/java/jcs/commandStation/marklin/cs/net/CSHTTPConnectionVirt.java +++ b/src/main/java/jcs/commandStation/marklin/cs/net/CSHTTPConnectionVirt.java @@ -22,6 +22,7 @@ import java.io.InputStreamReader; import java.net.InetAddress; import java.net.MalformedURLException; +import java.net.URI; import java.net.URL; import java.net.URLConnection; import java.net.UnknownHostException; @@ -85,7 +86,7 @@ private static String fixURL(String url) { public String getLocomotivesFile() { StringBuilder locs = new StringBuilder(); try { - URL cs = new URL(HTTP + csAddress.getHostAddress() + CONFIG + LOCOMOTIVE); + URL cs = URI.create(HTTP + csAddress.getHostAddress() + CONFIG + LOCOMOTIVE).toURL(); URLConnection lc = cs.openConnection(); try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { String inputLine; @@ -106,7 +107,7 @@ public String getLocomotivesFile() { public String getLocomotivesJSON() { StringBuilder loks = new StringBuilder(); try { - URL url = new URL(HTTP + csAddress.getHostAddress() + LOCOMOTIVE_JSON); + URL url = URI.create(HTTP + csAddress.getHostAddress() + LOCOMOTIVE_JSON).toURL(); URLConnection lc = url.openConnection(); try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { String inputLine; @@ -127,7 +128,7 @@ public String getLocomotivesJSON() { public String getAccessoriesFile() { StringBuilder locs = new StringBuilder(); try { - URL url = new URL(HTTP + csAddress.getHostAddress() + CONFIG + MAGNETARTIKEL); + URL url = URI.create(HTTP + csAddress.getHostAddress() + CONFIG + MAGNETARTIKEL).toURL(); URLConnection lc = url.openConnection(); try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { String inputLine; @@ -148,7 +149,7 @@ public String getAccessoriesFile() { public String getFunctionsSvgJSON() { StringBuilder json = new StringBuilder(); try { - URL url = new URL(HTTP + csAddress.getHostAddress() + FUNCTION_SVG_URL); + URL url = URI.create(HTTP + csAddress.getHostAddress() + FUNCTION_SVG_URL).toURL(); URLConnection lc = url.openConnection(); try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { String inputLine; @@ -169,7 +170,7 @@ public String getFunctionsSvgJSON() { public String getAccessoriesSvgJSON() { StringBuilder json = new StringBuilder(); try { - URL url = new URL(HTTP + csAddress.getHostAddress() + ACCESSORIES_SVG_URL); + URL url = URI.create(HTTP + csAddress.getHostAddress() + ACCESSORIES_SVG_URL).toURL(); URLConnection lc = url.openConnection(); try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { String inputLine; @@ -190,7 +191,7 @@ public String getAccessoriesSvgJSON() { public String getAccessoriesJSON() { StringBuilder json = new StringBuilder(); try { - URL url = new URL(HTTP + csAddress.getHostAddress() + ACCESSORIES_URL); + URL url = URI.create(HTTP + csAddress.getHostAddress() + ACCESSORIES_URL).toURL(); URLConnection lc = url.openConnection(); try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { String inputLine; @@ -549,9 +550,9 @@ public Image getLocomotiveImage(String imageName) { try { URL url; if (cs3) { - url = new URL(fixURL(HTTP + csAddress.getHostAddress() + IMAGE_FOLDER_CS3 + imageName + ".png")); + url = URI.create(fixURL(HTTP + csAddress.getHostAddress() + IMAGE_FOLDER_CS3 + imageName + ".png")).toURL(); } else { - url = new URL(fixURL(HTTP + csAddress.getHostAddress() + IMAGE_FOLDER_CS2 + imageName + ".png")); + url = URI.create(fixURL(HTTP + csAddress.getHostAddress() + IMAGE_FOLDER_CS2 + imageName + ".png")).toURL(); } Logger.trace("image URL: " + url); @@ -570,7 +571,7 @@ public Image getFunctionImageCS2(String imageName) { String iurl = fixURL(HTTP + csAddress.getHostAddress() + FUNCTION_IMAGE_FOLDER + imageName + ".png"); try { - URL url = new URL(iurl); + URL url = URI.create(iurl).toURL(); image = ImageIO.read(url); } catch (IIOException iio) { //Image not avalable diff --git a/src/main/java/jcs/persistence/util/EntityInfo.java b/src/main/java/jcs/persistence/util/EntityInfo.java index 3943bd90..fed7074a 100644 --- a/src/main/java/jcs/persistence/util/EntityInfo.java +++ b/src/main/java/jcs/persistence/util/EntityInfo.java @@ -54,11 +54,11 @@ public class EntityInfo { List displayColumnList; public EntityInfo(Class clazz) { - this(clazz, Collections.EMPTY_LIST, false); + this(clazz, Collections.emptyList(), false); } public EntityInfo(Class clazz, boolean ignoreTransient) { - this(clazz, Collections.EMPTY_LIST, ignoreTransient); + this(clazz, Collections.emptyList(), ignoreTransient); } public EntityInfo(Class clazz, String[] displayColumns) { diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java index e5ed6a7d..5ca5e808 100755 --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -86,6 +86,7 @@ public abstract class Tile extends JComponent { // implements ChangeListener public static final String MODEL_CHANGED_PROPERTY = "model"; // public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled"; + private static final long serialVersionUID = -8117888635518142366L; /** * The data model that determines the Tile state. @@ -650,7 +651,7 @@ public void setShowRoute(boolean drawRoute) { public abstract Map getEdgePoints(); Set getAltPoints(Point center) { - return Collections.EMPTY_SET; + return Collections.emptySet(); } public Set getAllPoints() { @@ -699,8 +700,7 @@ public void flipVertical() { } } - @Override - public void move(int newX, int newY) { + public void moveTile(int newX, int newY) { Point cs = LayoutUtil.snapToGrid(newX, newY); setCenter(cs); } @@ -730,7 +730,7 @@ public static BufferedImage flipVertically(BufferedImage source) { } public Set getAltPoints() { - return Collections.EMPTY_SET; + return Collections.emptySet(); } public int getCenterX() { diff --git a/src/main/java/jcs/ui/settings/CommandStationPanel.java b/src/main/java/jcs/ui/settings/CommandStationPanel.java index 02f9ced1..4739e3fb 100644 --- a/src/main/java/jcs/ui/settings/CommandStationPanel.java +++ b/src/main/java/jcs/ui/settings/CommandStationPanel.java @@ -89,6 +89,8 @@ private void initModels(CommandStationBean selected) { } List commandStations = PersistenceFactory.getService().getCommandStations(); + CommandStationBean[] cmdSts = new CommandStationBean[commandStations.size()]; + commandStations.toArray(cmdSts); if (selectedCommandStation == null) { selectedCommandStation = new CommandStationBean(); @@ -96,7 +98,7 @@ private void initModels(CommandStationBean selected) { commandStations.add(selectedCommandStation); } - commandStationComboBoxModel = new DefaultComboBoxModel(commandStations.toArray()); + commandStationComboBoxModel = new DefaultComboBoxModel(cmdSts); commandStationComboBoxModel.setSelectedItem(selectedCommandStation); commandStationComboBox.setModel(commandStationComboBoxModel); @@ -106,7 +108,7 @@ private void initModels(CommandStationBean selected) { ports[i] = comPorts[i].getSystemPortName(); } - serialPortComboBoxModel = new DefaultComboBoxModel(ports); + serialPortComboBoxModel = new DefaultComboBoxModel<>(ports); this.serialPortCB.setModel(serialPortComboBoxModel); setFieldValues(); @@ -1174,7 +1176,7 @@ private void newBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_newBtnAct this.selectedCommandStation.setId("new.cs"); this.selectedCommandStation.setConnectionType(ConnectionType.NETWORK); - ((DefaultComboBoxModel) commandStationComboBoxModel).addElement(selectedCommandStation); + ((DefaultComboBoxModel) commandStationComboBoxModel).addElement(selectedCommandStation); this.commandStationComboBoxModel.setSelectedItem(selectedCommandStation); setFieldValues(); }//GEN-LAST:event_newBtnActionPerformed @@ -1280,7 +1282,7 @@ private void serialPortRefreshBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:e for (int i = 0; i < comPorts.length; i++) { ports[i] = comPorts[i].getSystemPortName(); } - serialPortComboBoxModel = new DefaultComboBoxModel(ports); + serialPortComboBoxModel = new DefaultComboBoxModel<>(ports); serialPortCB.setModel(serialPortComboBoxModel); String portName = selectedCommandStation.getSerialPort(); diff --git a/src/main/java/jcs/ui/table/model/AbstractBeanTableModel.java b/src/main/java/jcs/ui/table/model/AbstractBeanTableModel.java index d2503d99..f7635175 100644 --- a/src/main/java/jcs/ui/table/model/AbstractBeanTableModel.java +++ b/src/main/java/jcs/ui/table/model/AbstractBeanTableModel.java @@ -29,15 +29,17 @@ */ public abstract class AbstractBeanTableModel extends AbstractTableModel { + private static final long serialVersionUID = 1606361017089479085L; + protected List beans; - protected EntityInfo beanInfo; + protected EntityInfo beanInfo; public AbstractBeanTableModel(Class T) { this(T, null); } public AbstractBeanTableModel(Class T, String[] displayColumnNames) { - beanInfo = new EntityInfo(T, displayColumnNames, true); + beanInfo = new EntityInfo<>(T, displayColumnNames, true); } public List getBeans() { @@ -48,7 +50,7 @@ public void setBeans(List beans) { if (beans != null && !beans.isEmpty()) { this.beans = beans; } else { - this.beans = Collections.EMPTY_LIST; + this.beans = Collections.emptyList(); } this.fireTableDataChanged(); } @@ -156,8 +158,7 @@ public String getColumnName(int column) { } /** - * Returns true if the specified cell can be modified, and false otherwise. For this implementation, the - * method always returns true. + * Returns true if the specified cell can be modified, and false otherwise. For this implementation, the method always returns true. * * @param row the row index. * @param column the column index. diff --git a/src/test/java/jcs/commandStation/marklin/cs/MarklinCSTest.java b/src/test/java/jcs/commandStation/marklin/cs/MarklinCSTest.java index 20537f71..acbda537 100644 --- a/src/test/java/jcs/commandStation/marklin/cs/MarklinCSTest.java +++ b/src/test/java/jcs/commandStation/marklin/cs/MarklinCSTest.java @@ -93,7 +93,7 @@ public void tearDown() { /** * Test of connect method, of class MarklinCentralStationImpl. */ - @Test + //@Test public void testConnect() { if (csAvailable) { System.out.println("connect"); @@ -168,7 +168,7 @@ public static void setDefaultCommandStation() { JCS.getJcsCommandStation().disconnect(); CommandStationBean virt = PersistenceFactory.getService().getCommandStation("virtual"); - PersistenceFactory.getService().changeDefaultCommandStation(virt); + //PersistenceFactory.getService().changeDefaultCommandStation(virt); } } diff --git a/src/test/java/jcs/persistence/PersistenceServiceTest.java b/src/test/java/jcs/persistence/PersistenceServiceTest.java index 5c16c652..ce711a59 100644 --- a/src/test/java/jcs/persistence/PersistenceServiceTest.java +++ b/src/test/java/jcs/persistence/PersistenceServiceTest.java @@ -74,13 +74,13 @@ public PersistenceServiceTest() { @BeforeClass public static void setUpClass() throws Exception { -// System.setProperty("persistenceService", "jcs.persistence.H2PersistenceService"); -// PersistenceTestHelper.createDatabaseUsers(); -// PersistenceTestHelper.createDatabase(); -// PersistenceTestHelper.getInstance().insertTestData(); -// CommandStationBean csb = new CommandStationBean(); -// csb.setId("marklin.cs"); - //PersistenceFactory.getService().changeDefaultCommandStation(csb); + System.setProperty("persistenceService", "jcs.persistence.TestH2PersistenceService"); + PersistenceTestHelper.createDatabaseUsers(); + PersistenceTestHelper.createDatabase(); + PersistenceTestHelper.getInstance().insertTestData(); + CommandStationBean csb = new CommandStationBean(); + csb.setId("marklin.cs"); + PersistenceFactory.getService().changeDefaultCommandStation(csb); Logger.info("####### PersistenceService Test Start...."); } From 47fdda4bc706220663e51eefeb1f1fcc01cab41f Mon Sep 17 00:00:00 2001 From: Frans Jacobs <41232225+fransjacobs@users.noreply.github.com> Date: Thu, 8 May 2025 21:39:10 +0200 Subject: [PATCH 53/70] Retrieving feedback modules via CS 3, added test template WIP --- pom.xml | 4 +- .../marklin/cs/MarklinCentralStationImpl.java | 90 ++---- .../jcs/entities/FeedbackModuleBeanTest.java | 258 ++++++++++++++++++ .../ui/layout/tiles/UnscaledBlockTester.form | 10 +- .../ui/layout/tiles/UnscaledBlockTester.java | 8 +- 5 files changed, 299 insertions(+), 71 deletions(-) create mode 100644 src/test/java/jcs/entities/FeedbackModuleBeanTest.java diff --git a/pom.xml b/pom.xml index 7a8f7a8e..f5c7be0a 100644 --- a/pom.xml +++ b/pom.xml @@ -210,8 +210,8 @@ maven-compiler-plugin 3.13.0 - - --enable-preview,-verbose + + -verbose 21 true diff --git a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java index 4d24f6a1..eff082ef 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java +++ b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java @@ -454,23 +454,27 @@ public List getFeedbackModules() { if (links88 != null) { nodeId = links88.getIdentifierInt() + 1; for (ConfigChannel cc : links88.getConfigChannels()) { - if (cc.getChoiceDescription().contains("Bus 1")) { + //if (cc.getChoiceDescription().contains("Bus 1 (RJ45-1)")) { + if (cc.getNumber() == 2) { bus1Len = cc.getActualValue(); } - if (cc.getChoiceDescription().contains("Bus 2")) { + //if (cc.getChoiceDescription().contains("Bus 2 RJ45-2)")) { + if (cc.getNumber() == 3) { bus2Len = cc.getActualValue(); } - if (cc.getChoiceDescription().contains("Bus 3")) { + //if (cc.getChoiceDescription().contains("Bus 3 (6-Polig)")) { + if (cc.getNumber() == 4) { bus3Len = cc.getActualValue(); } - } + Logger.trace("nodeId: " + nodeId + ", bus1Len: " + bus1Len + ", bus2Len: " + bus2Len + ", bus3Len: " + bus3Len); //Link S88 has 16 sensors starting from 0 //Bus 1 offset 1000, Bus 2 offset 2000 and Bus 3 offset 3000 FeedbackModuleBean l = new FeedbackModuleBean(); l.setAddressOffset(0); l.setModuleNumber(0); + l.setPortCount(16); l.setIdentifier(nodeId); feedbackModules.add(l); @@ -478,21 +482,24 @@ public List getFeedbackModules() { FeedbackModuleBean b1 = new FeedbackModuleBean(); b1.setAddressOffset(1000); b1.setModuleNumber(i); - l.setIdentifier(nodeId); + b1.setPortCount(16); + b1.setIdentifier(nodeId); feedbackModules.add(b1); } for (int i = 0; i < bus2Len; i++) { FeedbackModuleBean b2 = new FeedbackModuleBean(); b2.setAddressOffset(2000); b2.setModuleNumber(i); - l.setIdentifier(nodeId); + b2.setPortCount(16); + b2.setIdentifier(nodeId); feedbackModules.add(b2); } for (int i = 0; i < bus3Len; i++) { FeedbackModuleBean b3 = new FeedbackModuleBean(); b3.setAddressOffset(3000); b3.setModuleNumber(i); - l.setIdentifier(nodeId); + b3.setPortCount(16); + b3.setIdentifier(nodeId); feedbackModules.add(b3); } @@ -732,11 +739,11 @@ public void switchAccessory(Integer address, String protocol, AccessoryValue val } } - private void sendJCSUIDMessage() { + void sendJCSUIDMessage() { sendMessage(CanMessageFactory.getMemberPingResponse(CanMessage.JCS_UID, 1, CanMessage.JCS_DEVICE_ID)); } - private void sentJCSInformationMessage() { + void sentJCSInformationMessage() { List messages = getStatusDataConfigResponse(CanMessage.JCS_SERIAL, 0, 0, "JCS", "Java Central Station", CanMessage.JCS_UID); for (CanMessage msg : messages) { sendMessage(msg); @@ -1186,6 +1193,12 @@ public static void main(String[] a) { // // Logger.debug("Switch Accessory 2 to Green"); //cs.switchAccessory(2, AccessoryValue.GREEN, 250); + List fbml = cs.getFeedbackModules(); + for (FeedbackModuleBean fbm : fbml) { + Logger.trace(fbm); + Logger.trace("p-1 "+fbm.getSensor(0).getId()); + Logger.trace("p-15 "+fbm.getSensor(15).getId()); + } //cs.getLocomotivesViaCAN(); //cs.getAccessoriesViaCan(); @@ -1210,64 +1223,7 @@ public static void main(String[] a) { //Logger.debug("Power is " + (cs.isPower() ? "ON" : "Off")); //cs3.sendJCSInfo(); //SystemConfiguration data -// Map measurements = cs.getTrackMeasurements(); -// for (ChannelBean ch : measurements.values()) { -// if (ch != null) { -// Logger.trace("Channel " + ch.getNumber() + ": " + ch.getHumanValue() + " " + ch.getUnit()); -// } -// } -// Logger.debug("Channel 1: " + cs.channelData1.getChannel().getHumanValue() + " " + cs.channelData1.getChannel().getUnit()); -// Logger.debug("Channel 2: " + cs.channelData2.getChannel().getHumanValue() + " " + cs.channelData2.getChannel().getUnit()); -// Logger.debug("Channel 3: " + cs.channelData3.getChannel().getHumanValue() + " " + cs.channelData3.getChannel().getUnit()); -// Logger.debug("Channel 4: " + cs.channelData4.getChannel().getHumanValue() + " " + cs.channelData4.getChannel().getUnit()); - //cs.getSystemStatus(1); - cs.performMeasurements(); -// -// Logger.debug("Channel 4...."); -// cs.getSystemStatus(4); -//Now get the systemstatus for all devices -//First the status data config must be called to get the channels - //cs3.getSystemStatus() - // SystemStatus ss = cs.getSystemStatus(); - // Logger.debug("1: "+ss); - // - // - // ss = cs.power(true); - // Logger.debug("3: "+ss); - // - // cs.pause(1000); - // ss = cs.power(false); - // Logger.debug("4: "+ss); - // List sml = cs.querySensors(48); - // for (SensorEvent sme : sml) { - // Sensor s = new Sensor(sme.getContactId(), sme.isNewValue() ? 1 : 0, sme.isOldValue() ? 1 : 0, sme.getDeviceIdBytes(), sme.getMillis(), new Date()); - // Logger.debug(s.toLogString()); - // } - //List asl = cs.getAccessoryStatuses(); - //for (AccessoryStatus as : asl) { - // Logger.debug(as.toString()); - //} - // for (int i = 0; i < 30; i++) { - // cs.sendIdle(); - // pause(500); - // } - // Logger.debug("Sending member ping\n"); - // List prl = cs.membersPing(); - // //Logger.info("Query direction of loc 12"); - // //DirectionInfo info = cs.getDirectionMarkin(12, DecoderType.MM); - // Logger.debug("got " + prl.size() + " responses"); - // for (PingResponseParser device : prl) { - // Logger.debug(device); - // } - // List sel = cs.querySensors(48); - // - // for (SensorEvent se : sel) { - // Logger.debug(se.toString()); - // } - // FeedbackModule fm2 = new FeedbackModule(2); - // cs.queryAllPorts(fm2); - // Logger.debug(fm2.toLogString()); - //cs2.querySensor(1); +// cs.performMeasurements(); } //PingResponse pr2 = cs.memberPing(); diff --git a/src/test/java/jcs/entities/FeedbackModuleBeanTest.java b/src/test/java/jcs/entities/FeedbackModuleBeanTest.java new file mode 100644 index 00000000..f5e04d1a --- /dev/null +++ b/src/test/java/jcs/entities/FeedbackModuleBeanTest.java @@ -0,0 +1,258 @@ +/* + * Copyright 2025 Frans Jacobs + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.entities; + +import java.util.List; +import jcs.commandStation.events.SensorEvent; +import jcs.entities.FeedbackModuleBean; +import jcs.entities.SensorBean; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +/** + * + * @author frans + */ +public class FeedbackModuleBeanTest { + + public FeedbackModuleBeanTest() { + } + + @BeforeEach + public void setUp() { + } + + @AfterEach + public void tearDown() { + } + + //@Test + public void testGetId() { + System.out.println("getId"); + FeedbackModuleBean instance = new FeedbackModuleBean(); + Integer expResult = null; + Integer result = instance.getId(); + assertEquals(expResult, result); + fail("The test case is a prototype."); + } + + //@Test + public void testSetId() { + System.out.println("setId"); + Integer id = null; + FeedbackModuleBean instance = new FeedbackModuleBean(); + instance.setId(id); + fail("The test case is a prototype."); + } + + //@Test + public void testGetModuleNumber() { + System.out.println("getModuleNumber"); + FeedbackModuleBean instance = new FeedbackModuleBean(); + Integer expResult = null; + Integer result = instance.getModuleNumber(); + assertEquals(expResult, result); + fail("The test case is a prototype."); + } + + //@Test + public void testSetModuleNumber() { + System.out.println("setModuleNumber"); + Integer moduleNumber = null; + FeedbackModuleBean instance = new FeedbackModuleBean(); + instance.setModuleNumber(moduleNumber); + fail("The test case is a prototype."); + } + + //@Test + public void testGetPortCount() { + System.out.println("getPortCount"); + FeedbackModuleBean instance = new FeedbackModuleBean(); + Integer expResult = null; + Integer result = instance.getPortCount(); + assertEquals(expResult, result); + fail("The test case is a prototype."); + } + + //@Test + public void testSetPortCount() { + System.out.println("setPortCount"); + Integer portCount = null; + FeedbackModuleBean instance = new FeedbackModuleBean(); + instance.setPortCount(portCount); + fail("The test case is a prototype."); + } + + //@Test + public void testGetAddressOffset() { + System.out.println("getAddressOffset"); + FeedbackModuleBean instance = new FeedbackModuleBean(); + Integer expResult = null; + Integer result = instance.getAddressOffset(); + assertEquals(expResult, result); + fail("The test case is a prototype."); + } + + //@Test + public void testSetAddressOffset() { + System.out.println("setAddressOffset"); + Integer addressOffset = null; + FeedbackModuleBean instance = new FeedbackModuleBean(); + instance.setAddressOffset(addressOffset); + fail("The test case is a prototype."); + } + + //@Test + public void testGetIdentifier() { + System.out.println("getIdentifier"); + FeedbackModuleBean instance = new FeedbackModuleBean(); + Integer expResult = null; + Integer result = instance.getIdentifier(); + assertEquals(expResult, result); + fail("The test case is a prototype."); + } + + //@Test + public void testSetIdentifier() { + System.out.println("setIdentifier"); + Integer identifier = null; + FeedbackModuleBean instance = new FeedbackModuleBean(); + instance.setIdentifier(identifier); + fail("The test case is a prototype."); + } + + //@Test + public void testGetPorts() { + System.out.println("getPorts"); + FeedbackModuleBean instance = new FeedbackModuleBean(); + int[] expResult = null; + int[] result = instance.getPorts(); + assertArrayEquals(expResult, result); + fail("The test case is a prototype."); + } + + //@Test + public void testSetPorts() { + System.out.println("setPorts"); + int[] ports = null; + FeedbackModuleBean instance = new FeedbackModuleBean(); + instance.setPorts(ports); + fail("The test case is a prototype."); + } + + //@Test + public void testSetPortValue() { + System.out.println("setPortValue"); + int port = 0; + boolean active = false; + FeedbackModuleBean instance = new FeedbackModuleBean(); + instance.setPortValue(port, active); + fail("The test case is a prototype."); + } + + //@Test + public void testGetAccumulatedPortsValue() { + System.out.println("getAccumulatedPortsValue"); + FeedbackModuleBean instance = new FeedbackModuleBean(); + int expResult = 0; + int result = instance.getAccumulatedPortsValue(); + assertEquals(expResult, result); + fail("The test case is a prototype."); + } + + //@Test + public void testGetPrevPorts() { + System.out.println("getPrevPorts"); + FeedbackModuleBean instance = new FeedbackModuleBean(); + int[] expResult = null; + int[] result = instance.getPrevPorts(); + assertArrayEquals(expResult, result); + fail("The test case is a prototype."); + } + + //@Test + public void testSetPrevPorts() { + System.out.println("setPrevPorts"); + int[] prevPorts = null; + FeedbackModuleBean instance = new FeedbackModuleBean(); + instance.setPrevPorts(prevPorts); + fail("The test case is a prototype."); + } + + //@Test + public void testGetSensor() { + System.out.println("getSensor"); + int port = 0; + FeedbackModuleBean instance = new FeedbackModuleBean(); + SensorBean expResult = null; + SensorBean result = instance.getSensor(port); + assertEquals(expResult, result); + fail("The test case is a prototype."); + } + + //@Test + public void testIsPort() { + System.out.println("isPort"); + int port = 0; + FeedbackModuleBean instance = new FeedbackModuleBean(); + boolean expResult = false; + boolean result = instance.isPort(port); + assertEquals(expResult, result); + fail("The test case is a prototype."); + } + + //@Test + public void testGetChangedSensors() { + System.out.println("getChangedSensors"); + FeedbackModuleBean instance = new FeedbackModuleBean(); + List expResult = null; + List result = instance.getChangedSensors(); + assertEquals(expResult, result); + fail("The test case is a prototype."); + } + + //@Test + public void testGetSensors() { + System.out.println("getSensors"); + FeedbackModuleBean instance = new FeedbackModuleBean(); + List expResult = null; + List result = instance.getSensors(); + assertEquals(expResult, result); + fail("The test case is a prototype."); + } + + //@Test + public void testPortToString() { + System.out.println("portToString"); + FeedbackModuleBean instance = new FeedbackModuleBean(); + String expResult = ""; + String result = instance.portToString(); + assertEquals(expResult, result); + fail("The test case is a prototype."); + } + + //@Test + public void testToString() { + System.out.println("toString"); + FeedbackModuleBean instance = new FeedbackModuleBean(); + String expResult = ""; + String result = instance.toString(); + assertEquals(expResult, result); + fail("The test case is a prototype."); + } +} diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.form b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.form index 9c565600..7855dc53 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.form +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.form @@ -132,12 +132,20 @@ - + + + + + + + + + diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.java b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.java index 6c0ecff4..2cc8ea92 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.java +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.java @@ -156,6 +156,7 @@ private void initComponents() { departureSideCB = new javax.swing.JComboBox<>(); reverseArrivalCB = new javax.swing.JCheckBox(); showLocCB = new javax.swing.JCheckBox(); + jLabel1 = new javax.swing.JLabel(); backwardsRB = new javax.swing.JRadioButton(); forwardsRB = new javax.swing.JRadioButton(); showCenterCB = new javax.swing.JCheckBox(); @@ -222,7 +223,7 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { }); nPanel.add(reverseArrivalCB); - showLocCB.setLabel("Show Locomotive"); + showLocCB.setText(""); showLocCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { showLocCBActionPerformed(evt); @@ -230,6 +231,10 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { }); nPanel.add(showLocCB); + jLabel1.setLabelFor(showLocCB); + jLabel1.setText("Show Locomotive"); + nPanel.add(jLabel1); + locDirectionBG.add(backwardsRB); backwardsRB.setText("Backwards"); backwardsRB.addActionListener(new java.awt.event.ActionListener() { @@ -421,6 +426,7 @@ public static void main(String args[]) { private javax.swing.JComboBox departureSideCB; private javax.swing.JRadioButton forwardsRB; private javax.swing.JLabel incomingSuffix; + private javax.swing.JLabel jLabel1; private javax.swing.ButtonGroup locDirectionBG; private javax.swing.JPanel nPanel; private javax.swing.JComboBox orientationCB; From 1cb412517b83cf4c28707133dcaa82a352fdaac8 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Fri, 9 May 2025 21:57:13 +0200 Subject: [PATCH 54/70] Minor update in tcp connection for marklin remove skip tests from pom --- pom.xml | 3 +-- .../commandStation/marklin/cs/net/CSTCPConnection.java | 10 ++++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index f5c7be0a..ec56d1c3 100644 --- a/pom.xml +++ b/pom.xml @@ -22,7 +22,6 @@ jar jcs.JCS 21 - @@ -297,7 +296,7 @@ maven-surefire-plugin 3.5.2 - false + -Dfile.encoding=UTF-8 junit.jupiter.execution.parallel.enabled=false diff --git a/src/main/java/jcs/commandStation/marklin/cs/net/CSTCPConnection.java b/src/main/java/jcs/commandStation/marklin/cs/net/CSTCPConnection.java index f8acde90..41bcda64 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/net/CSTCPConnection.java +++ b/src/main/java/jcs/commandStation/marklin/cs/net/CSTCPConnection.java @@ -188,9 +188,11 @@ public synchronized CanMessage sendCanMessage(CanMessage message) { //Wait for the response boolean responseComplete = callback.isResponseComplete(); - //the CS somtime is slow with replies, whic could lead to missing responses. - //Just wait a 10 milliseconds to be sure - pause(); + //When querying the CS CAN Bus sometimes the responses have a little delay. This could sometimes lead to missing responses. + //Therefor just wait for 10 milliseconds to be sure with queries where this has been observed... + if (message.getCommand() == CanMessage.STATUS_CONFIG || message.getCommand() == CanMessage.PING_REQ) { + pause10Millis(); + } while (!responseComplete && now < timeout) { responseComplete = callback.isResponseComplete(); @@ -240,7 +242,7 @@ public boolean isConnected() { return messageReceiver != null && messageReceiver.isRunning(); } - private void pause() { + private void pause10Millis() { try { Thread.sleep(10); } catch (InterruptedException ex) { From a19a2882d9236d971a7b30a66de1fc5c3c18abf3 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Sat, 10 May 2025 19:35:15 +0200 Subject: [PATCH 55/70] Added id's to feedbackmodule creation --- .../jcs/commandStation/esu/ecos/Ecos.java | 1 + .../esu/ecos/EsuEcosCommandStationImpl.java | 9 ++- .../esu/ecos/FeedbackManager.java | 9 ++- .../marklin/cs/MarklinCentralStationImpl.java | 27 ++++---- .../jcs/ui/settings/CommandStationDialog.java | 60 ++++++++--------- .../jcs/ui/settings/CommandStationPanel.java | 65 +++++++++++-------- 6 files changed, 97 insertions(+), 74 deletions(-) diff --git a/src/main/java/jcs/commandStation/esu/ecos/Ecos.java b/src/main/java/jcs/commandStation/esu/ecos/Ecos.java index fe4c626e..d7b5e69d 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/Ecos.java +++ b/src/main/java/jcs/commandStation/esu/ecos/Ecos.java @@ -97,4 +97,5 @@ public interface Ecos { public static final String VARIANT = "variant"; public static final String MSG = "msg"; + } diff --git a/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java b/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java index d978e99c..5311a171 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java @@ -234,7 +234,7 @@ private void initFeedbackManager() { for (int i = 0; i < feedbackManager.getSize(); i++) { int moduleId = i + FeedbackManager.S88_OFFSET; //reply = - connection.sendMessage(EcosMessageFactory.getFeedbackModuleInfo(moduleId)); + //connection.sendMessage(EcosMessageFactory.getFeedbackModuleInfo(moduleId)); //TODO: Start of day... //feedbackManager.update(reply); @@ -709,6 +709,13 @@ public static void main(String[] a) { // // cs.pause(1000); // + List feedbackModules = cs.getFeedbackModules(); + Logger.trace("There are "+feedbackModules+" Feedback Modules"); + for(FeedbackModuleBean fm : feedbackModules) { + Logger.trace("Module id: "+fm.getId()+" nr: "+fm.getModuleNumber()+" ports: "+fm.getPortCount()); + Logger.trace("Module id: "+fm.getId()+" S 1 id:"+fm.getSensor(0).getId()+" cid: "+fm.getSensor(0).getContactId()+" did: "+fm.getSensor(0).getDeviceId()); + Logger.trace("Module id: "+fm.getId()+" S 15 id:"+fm.getSensor(15).getId()+" cid: "+fm.getSensor(15).getContactId()+" did: "+fm.getSensor(15).getDeviceId()); + } // power = cs.power(true); // Logger.trace("4 Power is " + (power ? "On" : "Off")); //EcosMessage reply = cs.connection.sendMessage(new EcosMessage("queryObjects(26)")); diff --git a/src/main/java/jcs/commandStation/esu/ecos/FeedbackManager.java b/src/main/java/jcs/commandStation/esu/ecos/FeedbackManager.java index d55e6f72..63087025 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/FeedbackManager.java +++ b/src/main/java/jcs/commandStation/esu/ecos/FeedbackManager.java @@ -31,6 +31,7 @@ class FeedbackManager { public static final int ID = Ecos.FEEDBACK_MANAGER_ID; public static final int S88_OFFSET = 100; + public static final int S88_DEFAULT_PORT_COUNT = 16; private final EsuEcosCommandStationImpl ecosCommandStation; private final Map modules; @@ -58,6 +59,9 @@ private List parse(EcosMessage message) { feedbackModule.setId(objectId); feedbackModule.setAddressOffset(S88_OFFSET); feedbackModule.setModuleNumber(objectId - S88_OFFSET); + //ESU ECoS has 1 bus + feedbackModule.setIdentifier(0); + feedbackModule.setPortCount(16); } if (values.containsKey(Ecos.PORTS)) { @@ -90,11 +94,12 @@ private List parse(EcosMessage message) { FeedbackModuleBean fbmb = new FeedbackModuleBean(); fbmb.setAddressOffset(S88_OFFSET); fbmb.setModuleNumber(i); - fbmb.setId(S88_OFFSET+i); + fbmb.setId(S88_OFFSET + i); + fbmb.setPortCount(S88_DEFAULT_PORT_COUNT); + fbmb.setIdentifier(0); this.modules.put(fbmb.getId(), fbmb); } } - } changedSensors = Collections.EMPTY_LIST; } diff --git a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java index eff082ef..e23bc35e 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java +++ b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java @@ -91,8 +91,7 @@ import jcs.commandStation.marklin.parser.CanDeviceJSONParser; /** - * - * @author Frans Jacobs + * Command Station Implementation for Marklin CS-2/3 */ public class MarklinCentralStationImpl extends AbstractController implements DecoderController, AccessoryController, FeedbackController, ConnectionEventListener { @@ -138,7 +137,7 @@ int getCsUid() { return csUid; } - private boolean isCS3() { + boolean isCS3() { if (infoBean != null && infoBean.getArticleNumber() != null) { return "60216".equals(infoBean.getArticleNumber()) || "60226".equals(infoBean.getArticleNumber()); } else { @@ -448,21 +447,17 @@ public List getFeedbackModules() { //TODO: Test with CS-3Plus and CS2. //Link S88 List feedbackModules = new ArrayList<>(); - CanDevice links88 = getCanDevice("Link S88"); int bus1Len = 0, bus2Len = 0, bus3Len = 0, nodeId = 0; if (links88 != null) { nodeId = links88.getIdentifierInt() + 1; for (ConfigChannel cc : links88.getConfigChannels()) { - //if (cc.getChoiceDescription().contains("Bus 1 (RJ45-1)")) { if (cc.getNumber() == 2) { bus1Len = cc.getActualValue(); } - //if (cc.getChoiceDescription().contains("Bus 2 RJ45-2)")) { if (cc.getNumber() == 3) { bus2Len = cc.getActualValue(); } - //if (cc.getChoiceDescription().contains("Bus 3 (6-Polig)")) { if (cc.getNumber() == 4) { bus3Len = cc.getActualValue(); } @@ -472,6 +467,7 @@ public List getFeedbackModules() { //Link S88 has 16 sensors starting from 0 //Bus 1 offset 1000, Bus 2 offset 2000 and Bus 3 offset 3000 FeedbackModuleBean l = new FeedbackModuleBean(); + l.setId(0); l.setAddressOffset(0); l.setModuleNumber(0); l.setPortCount(16); @@ -480,6 +476,7 @@ public List getFeedbackModules() { for (int i = 0; i < bus1Len; i++) { FeedbackModuleBean b1 = new FeedbackModuleBean(); + b1.setId(1000+i); b1.setAddressOffset(1000); b1.setModuleNumber(i); b1.setPortCount(16); @@ -488,6 +485,7 @@ public List getFeedbackModules() { } for (int i = 0; i < bus2Len; i++) { FeedbackModuleBean b2 = new FeedbackModuleBean(); + b2.setId(2000+i); b2.setAddressOffset(2000); b2.setModuleNumber(i); b2.setPortCount(16); @@ -496,6 +494,7 @@ public List getFeedbackModules() { } for (int i = 0; i < bus3Len; i++) { FeedbackModuleBean b3 = new FeedbackModuleBean(); + b3.setId(3000+i); b3.setAddressOffset(3000); b3.setModuleNumber(i); b3.setPortCount(16); @@ -896,7 +895,6 @@ private void notifyLocomotiveSpeedEventListeners(final LocomotiveSpeedEvent spee } } - //TODO measurements als a kind of data table... /** * Handle Event Message, which are unsolicited messages from the CS. */ @@ -1193,12 +1191,13 @@ public static void main(String[] a) { // // Logger.debug("Switch Accessory 2 to Green"); //cs.switchAccessory(2, AccessoryValue.GREEN, 250); - List fbml = cs.getFeedbackModules(); - for (FeedbackModuleBean fbm : fbml) { - Logger.trace(fbm); - Logger.trace("p-1 "+fbm.getSensor(0).getId()); - Logger.trace("p-15 "+fbm.getSensor(15).getId()); - } + List feedbackModules = cs.getFeedbackModules(); + Logger.trace("There are "+feedbackModules+" Feedback Modules"); + for(FeedbackModuleBean fm : feedbackModules) { + Logger.trace("Module id: "+fm.getId()+" nr: "+fm.getModuleNumber()+" ports: "+fm.getPortCount()); + Logger.trace("Module id: "+fm.getId()+" S 1 id:"+fm.getSensor(0).getId()+" cid: "+fm.getSensor(0).getContactId()+" did: "+fm.getSensor(0).getDeviceId()); + Logger.trace("Module id: "+fm.getId()+" S 15 id:"+fm.getSensor(15).getId()+" cid: "+fm.getSensor(15).getContactId()+" did: "+fm.getSensor(15).getDeviceId()); + } //cs.getLocomotivesViaCAN(); //cs.getAccessoriesViaCan(); diff --git a/src/main/java/jcs/ui/settings/CommandStationDialog.java b/src/main/java/jcs/ui/settings/CommandStationDialog.java index d0889b59..5bdae197 100644 --- a/src/main/java/jcs/ui/settings/CommandStationDialog.java +++ b/src/main/java/jcs/ui/settings/CommandStationDialog.java @@ -27,6 +27,8 @@ public class CommandStationDialog extends javax.swing.JDialog { /** * Creates new form CommandStationDialog + * @param parent + * @param modal */ public CommandStationDialog(java.awt.Frame parent, boolean modal) { super(parent, modal); @@ -37,36 +39,36 @@ public CommandStationDialog(java.awt.Frame parent, boolean modal) { * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") - // //GEN-BEGIN:initComponents - private void initComponents() { + // //GEN-BEGIN:initComponents + private void initComponents() { - commandStationPanel1 = new jcs.ui.settings.CommandStationPanel(); - southPanel = new javax.swing.JPanel(); - exitBtn = new javax.swing.JButton(); + commandStationPanel1 = new jcs.ui.settings.CommandStationPanel(); + southPanel = new javax.swing.JPanel(); + exitBtn = new javax.swing.JButton(); - setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); - setPreferredSize(new java.awt.Dimension(1080, 750)); - getContentPane().add(commandStationPanel1, java.awt.BorderLayout.CENTER); + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + setPreferredSize(new java.awt.Dimension(1080, 750)); + getContentPane().add(commandStationPanel1, java.awt.BorderLayout.CENTER); - southPanel.setPreferredSize(new java.awt.Dimension(1024, 50)); - java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.RIGHT); - flowLayout1.setAlignOnBaseline(true); - southPanel.setLayout(flowLayout1); + southPanel.setPreferredSize(new java.awt.Dimension(1024, 50)); + java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.RIGHT); + flowLayout1.setAlignOnBaseline(true); + southPanel.setLayout(flowLayout1); - exitBtn.setIcon(new javax.swing.ImageIcon(getClass().getResource("/media/exit-24.png"))); // NOI18N - exitBtn.setText("Close"); - exitBtn.setPreferredSize(new java.awt.Dimension(100, 36)); - exitBtn.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - exitBtnActionPerformed(evt); - } - }); - southPanel.add(exitBtn); + exitBtn.setIcon(new javax.swing.ImageIcon(getClass().getResource("/media/exit-24.png"))); // NOI18N + exitBtn.setText("Close"); + exitBtn.setPreferredSize(new java.awt.Dimension(100, 36)); + exitBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + exitBtnActionPerformed(evt); + } + }); + southPanel.add(exitBtn); - getContentPane().add(southPanel, java.awt.BorderLayout.SOUTH); + getContentPane().add(southPanel, java.awt.BorderLayout.SOUTH); - pack(); - }// //GEN-END:initComponents + pack(); + }// //GEN-END:initComponents private void exitBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exitBtnActionPerformed this.setVisible(false); @@ -98,9 +100,9 @@ public void windowClosing(java.awt.event.WindowEvent e) { }); } - // Variables declaration - do not modify//GEN-BEGIN:variables - private jcs.ui.settings.CommandStationPanel commandStationPanel1; - private javax.swing.JButton exitBtn; - private javax.swing.JPanel southPanel; - // End of variables declaration//GEN-END:variables + // Variables declaration - do not modify//GEN-BEGIN:variables + private jcs.ui.settings.CommandStationPanel commandStationPanel1; + private javax.swing.JButton exitBtn; + private javax.swing.JPanel southPanel; + // End of variables declaration//GEN-END:variables } diff --git a/src/main/java/jcs/ui/settings/CommandStationPanel.java b/src/main/java/jcs/ui/settings/CommandStationPanel.java index 4739e3fb..e2216496 100644 --- a/src/main/java/jcs/ui/settings/CommandStationPanel.java +++ b/src/main/java/jcs/ui/settings/CommandStationPanel.java @@ -1461,62 +1461,70 @@ public Void doInBackground() { } else { switch (selectedCommandStation.getConnectionType()) { case NETWORK -> { + boolean canConnect = false; try { String ip = selectedCommandStation.getIpAddress(); setProgress(10); DecoderController commandStation = createCommandStation(selectedCommandStation); - boolean canConnect = false; setProgress(20); + if (ip == null && selectedCommandStation.isIpAutoConfiguration()) { //Try to obtain the ip through auto configuration - canConnect = commandStation.connect(); + //A connection could be there... + canConnect = commandStation.isConnected(); if (canConnect) { - firePropertyChange("ipAddress", "", commandStation.getIp()); + Logger.trace("allready connected"); + } else { + //try to connected + canConnect = commandStation.connect(); } setProgress(30); - } else { if (Ping.IsReachable(ip)) { setProgress(10); - canConnect = commandStation.connect(); - setProgress(20); + canConnect = commandStation.isConnected(); + if (canConnect) { + Logger.trace("allready connected"); + } else { + canConnect = commandStation.connect(); + setProgress(20); + } } } if (canConnect) { - //Let obtain some data fail safe + firePropertyChange("ipAddress", "", commandStation.getIp()); + //Lets obtain some data fail safe try { String sn = commandStation.getCommandStationInfo().getSerialNumber(); firePropertyChange("serial", "", sn); setProgress(50); if (commandStation instanceof FeedbackController feedbackController) { - //DeviceBean fbDevice = feedbackController.getFeedbackDevice(); - List feedbackModules = feedbackController.getFeedbackModules(); if (!feedbackModules.isEmpty()) { Logger.trace(feedbackController.getCommandStationInfo().getProductName() + " Supports Feedback"); //String id = fbDevice.getIdentifier(); -// int node = Integer.parseInt(id.replace("0x", ""), 16); -// firePropertyChange("node", selectedCommandStation.getFeedbackModuleIdentifier(), node); -// -// Integer channelCount = fbDevice.getSensorBuses().size(); -// firePropertyChange("channels", selectedCommandStation.getFeedbackChannelCount(), channelCount); -// -// Integer bus0 = fbDevice.getBusLength(0); -// firePropertyChange("bus0", selectedCommandStation.getFeedbackBus0ModuleCount(), bus0); -// -// Integer bus1 = fbDevice.getBusLength(1); -// firePropertyChange("bus1", selectedCommandStation.getFeedbackBus1ModuleCount(), bus1); -// -// Integer bus2 = fbDevice.getBusLength(2); -// firePropertyChange("bus2", selectedCommandStation.getFeedbackBus2ModuleCount(), bus2); -// -// Integer bus3 = fbDevice.getBusLength(3); -// firePropertyChange("bus3", selectedCommandStation.getFeedbackBus3ModuleCount(), bus3); -// -// Logger.trace("ID: " + id + " Node: " + node + " Bus 0: " + bus0 + " Bus 1: " + bus1 + " Bus 2: " + bus2 + " Bus 3: " + bus3); + int node = Integer.parseInt(id.replace("0x", ""), 16); + firePropertyChange("node", selectedCommandStation.getFeedbackModuleIdentifier(), node); + + Integer channelCount = fbDevice.getSensorBuses().size(); + firePropertyChange("channels", selectedCommandStation.getFeedbackChannelCount(), channelCount); + + Integer bus0 = fbDevice.getBusLength(0); + firePropertyChange("bus0", selectedCommandStation.getFeedbackBus0ModuleCount(), bus0); + + Integer bus1 = fbDevice.getBusLength(1); + firePropertyChange("bus1", selectedCommandStation.getFeedbackBus1ModuleCount(), bus1); + + Integer bus2 = fbDevice.getBusLength(2); + firePropertyChange("bus2", selectedCommandStation.getFeedbackBus2ModuleCount(), bus2); + + Integer bus3 = fbDevice.getBusLength(3); + firePropertyChange("bus3", selectedCommandStation.getFeedbackBus3ModuleCount(), bus3); + + Logger.trace("ID: " + id + " Node: " + node + " Bus 0: " + bus0 + " Bus 1: " + bus1 + " Bus 2: " + bus2 + " Bus 3: " + bus3); } } } catch (RuntimeException e) { @@ -1541,6 +1549,7 @@ public Void doInBackground() { setProgress(100); } } + case SERIAL -> { String commPort = selectedCommandStation.getSerialPort(); setProgress(10); From 3398d374545659c383fae30bd422baaaa30380ff Mon Sep 17 00:00:00 2001 From: Frans Jacobs <41232225+fransjacobs@users.noreply.github.com> Date: Sat, 10 May 2025 19:56:39 +0200 Subject: [PATCH 56/70] Fix link between objects and object with events. Refactored last things which where still using the old TrackService --- .../esu/ecos/EsuEcosCommandStationImpl.java | 9 ++++++++- .../commandStation/esu/ecos/FeedbackManager.java | 3 +++ .../marklin/cs/MarklinCentralStationImpl.java | 15 +++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java b/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java index d978e99c..b4233727 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java @@ -661,7 +661,7 @@ public static void main(String[] a) { System.setProperty("message.debug", "true"); //Discover the ECoS using mdns InetAddress ecosAddr = EcosConnectionFactory.discoverEcos(); - String ip = ecosAddr.getHostAddress(); + String ip = ecosAddr.getHostAddress(); if (1 == 1) { CommandStationBean csb = new CommandStationBean(); @@ -785,6 +785,13 @@ public static void main(String[] a) { // //reply = cs.connection.sendMessage(new EcosMessage("help(65000,attribute)")); // //Logger.trace(reply.getMessage() + " ->\n" + reply.getResponse()); // + List fbml = cs.getFeedbackModules(); + for (FeedbackModuleBean fbm : fbml) { + Logger.trace(fbm); + Logger.trace("p-1 " + fbm.getSensor(0).getId()); + Logger.trace("p-15 " + fbm.getSensor(15).getId()); + } + // // reply = cs.connection.sendMessage(new EcosMessage("request(65000,volt")); // Logger.trace(reply.getMessage() + " ->\n" + reply.getResponse()); diff --git a/src/main/java/jcs/commandStation/esu/ecos/FeedbackManager.java b/src/main/java/jcs/commandStation/esu/ecos/FeedbackManager.java index d55e6f72..96caeee4 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/FeedbackManager.java +++ b/src/main/java/jcs/commandStation/esu/ecos/FeedbackManager.java @@ -31,6 +31,8 @@ class FeedbackManager { public static final int ID = Ecos.FEEDBACK_MANAGER_ID; public static final int S88_OFFSET = 100; + public static final int DEFAULT_S88_PORT_COUNT = 16; + private final EsuEcosCommandStationImpl ecosCommandStation; private final Map modules; @@ -58,6 +60,7 @@ private List parse(EcosMessage message) { feedbackModule.setId(objectId); feedbackModule.setAddressOffset(S88_OFFSET); feedbackModule.setModuleNumber(objectId - S88_OFFSET); + feedbackModule.setPortCount(DEFAULT_S88_PORT_COUNT); } if (values.containsKey(Ecos.PORTS)) { diff --git a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java index eff082ef..dc1f0e37 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java +++ b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java @@ -477,6 +477,21 @@ public List getFeedbackModules() { l.setPortCount(16); l.setIdentifier(nodeId); feedbackModules.add(l); + + + + if (bus0len != null) { + for (int i = 0; i < (bus0len * 16); i++) { + SensorBean sb = new SensorBean(); + sb.setDeviceId(deviceId); + sb.setContactId((i + 1)); + sb.setName("B0-S-" + (i + 1)); + String id = sb.getId(); + sensorBeans.put(id, sb); + } + } + + for (int i = 0; i < bus1Len; i++) { FeedbackModuleBean b1 = new FeedbackModuleBean(); From 54ea9e9446ad71b50e4c7e4e9b66666b79b4820a Mon Sep 17 00:00:00 2001 From: Frans Jacobs <41232225+fransjacobs@users.noreply.github.com> Date: Sat, 10 May 2025 19:59:54 +0200 Subject: [PATCH 57/70] Fix link between objects and object with events. Refactored last things which where still using the old TrackService --- .../marklin/cs/MarklinCentralStationImpl.java | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java index dc1f0e37..f550895e 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java +++ b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java @@ -477,19 +477,17 @@ public List getFeedbackModules() { l.setPortCount(16); l.setIdentifier(nodeId); feedbackModules.add(l); - - - - if (bus0len != null) { - for (int i = 0; i < (bus0len * 16); i++) { - SensorBean sb = new SensorBean(); - sb.setDeviceId(deviceId); - sb.setContactId((i + 1)); - sb.setName("B0-S-" + (i + 1)); - String id = sb.getId(); - sensorBeans.put(id, sb); - } - } + +// if (bus0len != null) { +// for (int i = 0; i < (bus0len * 16); i++) { +// SensorBean sb = new SensorBean(); +// sb.setDeviceId(deviceId); +// sb.setContactId((i + 1)); +// sb.setName("B0-S-" + (i + 1)); +// String id = sb.getId(); +// sensorBeans.put(id, sb); +// } +// } From 06796aa2f32efc7930ef22f75619f5f612a39aa8 Mon Sep 17 00:00:00 2001 From: Frans Jacobs <41232225+fransjacobs@users.noreply.github.com> Date: Sat, 10 May 2025 20:09:24 +0200 Subject: [PATCH 58/70] Update CommandStationPanel.java --- .../jcs/ui/settings/CommandStationPanel.java | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/main/java/jcs/ui/settings/CommandStationPanel.java b/src/main/java/jcs/ui/settings/CommandStationPanel.java index e2216496..b826b0b2 100644 --- a/src/main/java/jcs/ui/settings/CommandStationPanel.java +++ b/src/main/java/jcs/ui/settings/CommandStationPanel.java @@ -1506,25 +1506,25 @@ public Void doInBackground() { Logger.trace(feedbackController.getCommandStationInfo().getProductName() + " Supports Feedback"); //String id = fbDevice.getIdentifier(); - int node = Integer.parseInt(id.replace("0x", ""), 16); - firePropertyChange("node", selectedCommandStation.getFeedbackModuleIdentifier(), node); - - Integer channelCount = fbDevice.getSensorBuses().size(); - firePropertyChange("channels", selectedCommandStation.getFeedbackChannelCount(), channelCount); - - Integer bus0 = fbDevice.getBusLength(0); - firePropertyChange("bus0", selectedCommandStation.getFeedbackBus0ModuleCount(), bus0); - - Integer bus1 = fbDevice.getBusLength(1); - firePropertyChange("bus1", selectedCommandStation.getFeedbackBus1ModuleCount(), bus1); - - Integer bus2 = fbDevice.getBusLength(2); - firePropertyChange("bus2", selectedCommandStation.getFeedbackBus2ModuleCount(), bus2); - - Integer bus3 = fbDevice.getBusLength(3); - firePropertyChange("bus3", selectedCommandStation.getFeedbackBus3ModuleCount(), bus3); - - Logger.trace("ID: " + id + " Node: " + node + " Bus 0: " + bus0 + " Bus 1: " + bus1 + " Bus 2: " + bus2 + " Bus 3: " + bus3); +// int node = Integer.parseInt(id.replace("0x", ""), 16); +// firePropertyChange("node", selectedCommandStation.getFeedbackModuleIdentifier(), node); +// +// Integer channelCount = fbDevice.getSensorBuses().size(); +// firePropertyChange("channels", selectedCommandStation.getFeedbackChannelCount(), channelCount); +// +// Integer bus0 = fbDevice.getBusLength(0); +// firePropertyChange("bus0", selectedCommandStation.getFeedbackBus0ModuleCount(), bus0); +// +// Integer bus1 = fbDevice.getBusLength(1); +// firePropertyChange("bus1", selectedCommandStation.getFeedbackBus1ModuleCount(), bus1); +// +// Integer bus2 = fbDevice.getBusLength(2); +// firePropertyChange("bus2", selectedCommandStation.getFeedbackBus2ModuleCount(), bus2); +// +// Integer bus3 = fbDevice.getBusLength(3); +// firePropertyChange("bus3", selectedCommandStation.getFeedbackBus3ModuleCount(), bus3); +// +// Logger.trace("ID: " + id + " Node: " + node + " Bus 0: " + bus0 + " Bus 1: " + bus1 + " Bus 2: " + bus2 + " Bus 3: " + bus3); } } } catch (RuntimeException e) { From 0fb13e4b2528e3ff4bdb20ecd2b223e68c33e59b Mon Sep 17 00:00:00 2001 From: Frans Jacobs <41232225+fransjacobs@users.noreply.github.com> Date: Sun, 11 May 2025 22:08:52 +0200 Subject: [PATCH 59/70] Major refactoring in Sensors. Code Compiles still WIP. Commit due to end of weekend --- .../commandStation/autopilot/AutoPilot.java | 26 +- .../autopilot/DriveSimulator.java | 12 +- .../autopilot/ExpectedSensorEventHandler.java | 8 +- .../autopilot/SensorEventHandler.java | 2 +- .../autopilot/state/Dispatcher.java | 44 ++-- .../autopilot/state/EnterBlockState.java | 8 +- .../autopilot/state/PrepareRouteState.java | 10 +- .../autopilot/state/StartState.java | 10 +- .../esu/ecos/AccessoryManager.java | 2 +- .../esu/ecos/FeedbackManager.java | 15 +- .../esu/ecos/net/EcosVirtualConnection.java | 4 +- .../commandStation/events/AccessoryEvent.java | 2 +- .../commandStation/events/JCSActionEvent.java | 2 +- .../commandStation/events/SensorEvent.java | 36 +-- .../jcs/commandStation/hsis88/HSIImpl.java | 3 +- .../marklin/cs/MarklinCentralStationImpl.java | 2 +- .../cs/can/parser/FeedbackEventMessage.java | 3 +- .../virtual/VirtualCommandStationImpl.java | 4 +- src/main/java/jcs/entities/BlockBean.java | 12 +- .../java/jcs/entities/FeedbackModuleBean.java | 105 ++++++-- src/main/java/jcs/entities/SensorBean.java | 129 +++++----- src/main/java/jcs/entities/TileBean.java | 13 +- .../jcs/persistence/H2PersistenceService.java | 13 +- .../jcs/persistence/PersistenceService.java | 3 +- .../jcs/ui/layout/dialogs/BlockDialog.java | 8 +- .../jcs/ui/layout/dialogs/SensorDialog.java | 51 ++-- src/main/java/jcs/ui/layout/tiles/Tile.java | 23 +- .../layout/tiles/TileActionEventHandler.java | 2 +- .../java/jcs/ui/layout/tiles/TileCache.java | 22 +- .../java/jcs/ui/layout/tiles/ui/SensorUI.java | 2 +- .../ui/settings/table/SensorTableModel.java | 9 +- src/main/resources/update-jcs-db-002.sql | 12 + .../autopilot/AutoPilotTest.java | 12 +- .../state/StateMachineStepByStepTest.java | 14 +- .../state/StateMachineThreadTest.java | 24 +- .../can/parser/FeedbackEventMessageTest.java | 44 ++-- .../jcs/entities/FeedbackModuleBeanTest.java | 229 +++++++++--------- .../persistence/PersistenceServiceTest.java | 19 +- src/test/resources/jcs-test-data-h2.sql | 4 +- 39 files changed, 525 insertions(+), 418 deletions(-) diff --git a/src/main/java/jcs/commandStation/autopilot/AutoPilot.java b/src/main/java/jcs/commandStation/autopilot/AutoPilot.java index d733f806..b86d8554 100644 --- a/src/main/java/jcs/commandStation/autopilot/AutoPilot.java +++ b/src/main/java/jcs/commandStation/autopilot/AutoPilot.java @@ -53,7 +53,7 @@ public final class AutoPilot { private static CommandStationBean commandStationBean; - private static final Map sensorHandlers = new HashMap<>(); + private static final Map sensorHandlers = new HashMap<>(); private static final Map dispatchers = new HashMap<>(); //Need a list to be able to unregister @@ -457,9 +457,9 @@ public static boolean isGostDetected() { } private static void handleGhost(SensorEvent event) { - Logger.trace("Check for possible Ghost! @ Sensor " + event.getId()); + Logger.trace("Check for possible Ghost! @ Sensor " + event.getIdString()); List blocks = PersistenceFactory.getService().getBlocks(); - String sensorId = event.getId(); + Integer sensorId = event.getSensorId(); for (BlockBean block : blocks) { Tile tile = TileCache.findTile(block.getTileId()); @@ -487,13 +487,13 @@ private static void handleGhost(SensorEvent event) { static void handleSensorEvent(SensorEvent event) { if (event.isChanged()) { - SensorEventHandler sh = sensorHandlers.get(event.getId()); - Boolean registered = sh != null; //sensorHandlers.containsKey(event.getId()); - Logger.trace((registered ? "Registered " : "") + event.getId() + " has changed " + event.isChanged()); + SensorEventHandler sh = sensorHandlers.get(event.getIdString()); + Boolean registered = sh != null; //sensorHandlers.containsKey(event.getIdString()); + Logger.trace((registered ? "Registered " : "") + event.getIdString() + " has changed " + event.isChanged()); if (sh != null) { //there is a handler registered for this id, pass the event through - //SensorEventHandler sh = sensorHandlers.get(event.getId()); + //SensorEventHandler sh = sensorHandlers.get(event.getIdString()); sh.handleEvent(event); } else { //sensor is not registered and thus not expected! @@ -508,11 +508,11 @@ public static synchronized void addSensorEventHandler(SensorEventHandler handler sensorHandlers.put(handler.getSensorId(), handler); } - public static boolean isSensorHandlerRegistered(String sensorId) { + public static boolean isSensorHandlerRegistered(Integer sensorId) { return sensorHandlers.containsKey(sensorId); } - public static synchronized void removeHandler(String sensorId) { + public static synchronized void removeHandler(Integer sensorId) { sensorHandlers.remove(sensorId); } @@ -567,7 +567,7 @@ private void registerAllSensors() { List sensors = PersistenceFactory.getService().getAssignedSensors(); int cnt = 0; for (SensorBean sb : sensors) { - String key = sb.getId(); + Integer key = sb.getId(); if (!sensorHandlers.containsKey(key)) { SensorListener seh = new SensorListener(key); sensorListeners.add(seh); @@ -672,15 +672,15 @@ boolean isStopped() { private static class SensorListener implements SensorEventListener { - private final String sensorId; + private final Integer sensorId; - SensorListener(String sensorId) { + SensorListener(Integer sensorId) { this.sensorId = sensorId; } @Override public void onSensorChange(SensorEvent event) { - if (sensorId.equals(event.getId())) { + if (sensorId.equals(event.getIdString())) { AutoPilot.handleSensorEvent(event); } } diff --git a/src/main/java/jcs/commandStation/autopilot/DriveSimulator.java b/src/main/java/jcs/commandStation/autopilot/DriveSimulator.java index c55b839d..eb32c7c7 100644 --- a/src/main/java/jcs/commandStation/autopilot/DriveSimulator.java +++ b/src/main/java/jcs/commandStation/autopilot/DriveSimulator.java @@ -51,22 +51,22 @@ public void simulateDriving(int locUid, int speed, LocomotiveBean.Direction dire if (dispatcher.isLocomotiveAutomodeOn()) { Logger.trace("Try to simulate the next sensor of " + dispatcher.getName()); - String occupationSensorId = dispatcher.getOccupationSensorId(); + Integer occupationSensorId = dispatcher.getOccupationSensorId(); if (occupationSensorId != null) { //Start a timer which execute a worker thread which fires the sensor scheduledExecutor.schedule(() -> setSensorValue(occupationSensorId, false), 500, TimeUnit.MILLISECONDS); } - String exitSensorId = dispatcher.getExitSensorId(); + Integer exitSensorId = dispatcher.getExitSensorId(); if (exitSensorId != null) { //Start a time which execute a worker thread which fires the sensor scheduledExecutor.schedule(() -> setSensorValue(exitSensorId, false), 1500, TimeUnit.MILLISECONDS); } - String enterSensorId = dispatcher.getEnterSensorId(); - String inSensorId = dispatcher.getInSensorId(); + Integer enterSensorId = dispatcher.getEnterSensorId(); + Integer inSensorId = dispatcher.getInSensorId(); - String sensorId = dispatcher.getWaitingForSensorId(); + Integer sensorId = dispatcher.getWaitingForSensorId(); int time = 5000; if (sensorId != null && sensorId.equals(enterSensorId)) { @@ -86,7 +86,7 @@ public void simulateDriving(int locUid, int speed, LocomotiveBean.Direction dire } } - private void setSensorValue(String sensorId, boolean active) { + private void setSensorValue(Integer sensorId, boolean active) { SensorBean sensor = PersistenceFactory.getService().getSensor(sensorId); sensor.setActive(active); SensorEvent sensorEvent = new SensorEvent(sensor); diff --git a/src/main/java/jcs/commandStation/autopilot/ExpectedSensorEventHandler.java b/src/main/java/jcs/commandStation/autopilot/ExpectedSensorEventHandler.java index 4befc51e..d71e182c 100644 --- a/src/main/java/jcs/commandStation/autopilot/ExpectedSensorEventHandler.java +++ b/src/main/java/jcs/commandStation/autopilot/ExpectedSensorEventHandler.java @@ -23,23 +23,23 @@ */ public class ExpectedSensorEventHandler implements SensorEventHandler { - private final String sensorId; + private final Integer sensorId; private final Dispatcher dispatcher; - public ExpectedSensorEventHandler(String sensorId, Dispatcher dispatcher) { + public ExpectedSensorEventHandler(Integer sensorId, Dispatcher dispatcher) { this.sensorId = sensorId; this.dispatcher = dispatcher; } @Override public void handleEvent(SensorEvent event) { - if (this.sensorId.equals(event.getId())) { + if (this.sensorId.equals(event.getSensorId())) { this.dispatcher.onIgnoreEvent(event); } } @Override - public String getSensorId() { + public Integer getSensorId() { return this.sensorId; } diff --git a/src/main/java/jcs/commandStation/autopilot/SensorEventHandler.java b/src/main/java/jcs/commandStation/autopilot/SensorEventHandler.java index fb711173..362a8ed8 100644 --- a/src/main/java/jcs/commandStation/autopilot/SensorEventHandler.java +++ b/src/main/java/jcs/commandStation/autopilot/SensorEventHandler.java @@ -25,5 +25,5 @@ public interface SensorEventHandler { void handleEvent(SensorEvent event); - String getSensorId(); + Integer getSensorId(); } diff --git a/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java b/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java index 647430fd..019ea6b2 100644 --- a/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java +++ b/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java @@ -50,16 +50,16 @@ public class Dispatcher { private String departureBlockId; private String destinationBlockId; - private String waitingForSensorId; + private Integer waitingForSensorId; //Enter Sensor of the destination - private String enterSensorId; + private Integer enterSensorId; //In Sensor of the destination - private String inSensorId; + private Integer inSensorId; //The Occupation sensor of the departure - private String occupationSensorId; + private Integer occupationSensorId; //The exit of the departure - private String exitSensorId; + private Integer exitSensorId; private final List stateEventListeners; @@ -213,52 +213,52 @@ public String getStateName() { } } - void setWaitForSensorid(String sensorId) { + void setWaitForSensorid(Integer sensorId) { this.waitingForSensorId = sensorId; } - public String getWaitingForSensorId() { + public Integer getWaitingForSensorId() { return waitingForSensorId; } - public String getEnterSensorId() { + public Integer getEnterSensorId() { return enterSensorId; } - void setEnterSensorId(String enterSensorId) { + void setEnterSensorId(Integer enterSensorId) { this.enterSensorId = enterSensorId; } - public String getInSensorId() { + public Integer getInSensorId() { return inSensorId; } - void setInSensorId(String inSensorId) { + void setInSensorId(Integer inSensorId) { this.inSensorId = inSensorId; } - public String getOccupationSensorId() { + public Integer getOccupationSensorId() { return occupationSensorId; } - void setOccupationSensorId(String occupationSensorId) { + void setOccupationSensorId(Integer occupationSensorId) { this.occupationSensorId = occupationSensorId; } - public String getExitSensorId() { + public Integer getExitSensorId() { return exitSensorId; } - void setExitSensorId(String exitSensorId) { + void setExitSensorId(Integer exitSensorId) { this.exitSensorId = exitSensorId; } void clearDepartureIgnoreEventHandlers() { if (departureBlockId != null) { BlockBean departureBlock = getDepartureBlock(); - String minSensorId = departureBlock.getMinSensorId(); + Integer minSensorId = departureBlock.getMinSensorId(); AutoPilot.removeHandler(minSensorId); - String plusSensorId = departureBlock.getPlusSensorId(); + Integer plusSensorId = departureBlock.getPlusSensorId(); AutoPilot.removeHandler(plusSensorId); } } @@ -266,31 +266,31 @@ void clearDepartureIgnoreEventHandlers() { public void onIgnoreEvent(SensorEvent event) { //Only in Simulator mode if (JCS.getJcsCommandStation().getCommandStationBean().isVirtual()) { - if (this.waitingForSensorId != null && this.waitingForSensorId.equals(event.getId())) { + if (this.waitingForSensorId != null && this.waitingForSensorId.equals(event.getSensorId())) { if (event.isActive()) { this.waitingForSensorId = null; } } - if (this.enterSensorId != null && this.enterSensorId.equals(event.getId())) { + if (this.enterSensorId != null && this.enterSensorId.equals(event.getSensorId())) { if (!event.isActive()) { this.enterSensorId = null; } } - if (this.inSensorId != null && this.inSensorId.equals(event.getId())) { + if (this.inSensorId != null && this.inSensorId.equals(event.getSensorId())) { if (!event.isActive()) { this.inSensorId = null; } } - if (this.exitSensorId != null && this.exitSensorId.equals(event.getId())) { + if (this.exitSensorId != null && this.exitSensorId.equals(event.getSensorId())) { if (!event.isActive()) { this.exitSensorId = null; } } } - //Logger.trace("Event for a ignored listener: " + event.getId() + " Changed: " + event.isChanged() + ", active: " + event.getSensorBean().isActive()); + //Logger.trace("Event for a ignored listener: " + event.getIdString() + " Changed: " + event.isChanged() + ", active: " + event.getSensorBean().isActive()); } synchronized void switchAccessory(AccessoryBean accessory, AccessoryValue value) { diff --git a/src/main/java/jcs/commandStation/autopilot/state/EnterBlockState.java b/src/main/java/jcs/commandStation/autopilot/state/EnterBlockState.java index 18583f41..7addc660 100644 --- a/src/main/java/jcs/commandStation/autopilot/state/EnterBlockState.java +++ b/src/main/java/jcs/commandStation/autopilot/state/EnterBlockState.java @@ -31,7 +31,7 @@ class EnterBlockState extends DispatcherState implements SensorEventListener { private boolean locomotiveBraking = false; private boolean canAdvanceToNextState = false; - private String inSensorId; + private Integer inSensorId; @Override DispatcherState execute(Dispatcher dispatcher) { @@ -66,7 +66,7 @@ DispatcherState execute(Dispatcher dispatcher) { PersistenceFactory.getService().persist(departureBlock); PersistenceFactory.getService().persist(destinationBlock); - + dispatcher.showBlockState(departureBlock); dispatcher.showRoute(route, Color.magenta); dispatcher.showBlockState(destinationBlock); @@ -102,10 +102,10 @@ DispatcherState execute(Dispatcher dispatcher) { @Override public void onSensorChange(SensorEvent sensorEvent) { - if (this.inSensorId.equals(sensorEvent.getId())) { + if (this.inSensorId.equals(sensorEvent.getSensorId())) { if (sensorEvent.isActive()) { this.canAdvanceToNextState = true; - Logger.trace("In Event from Sensor " + sensorEvent.getId()); + Logger.trace("In Event from Sensor " + sensorEvent.getIdString()); synchronized (this) { this.notifyAll(); } diff --git a/src/main/java/jcs/commandStation/autopilot/state/PrepareRouteState.java b/src/main/java/jcs/commandStation/autopilot/state/PrepareRouteState.java index 55ea53c3..b129986a 100644 --- a/src/main/java/jcs/commandStation/autopilot/state/PrepareRouteState.java +++ b/src/main/java/jcs/commandStation/autopilot/state/PrepareRouteState.java @@ -76,7 +76,7 @@ boolean searchRoute(Dispatcher dispatcher) { Logger.trace("Search a free route for " + locomotive.getName() + "..."); BlockBean departureBlock = dispatcher.getDepartureBlock(); - if(departureBlock.getLogicalDirection() == null) { + if (departureBlock.getLogicalDirection() == null) { departureBlock.setLogicalDirection(locomotive.getDirection().getDirection()); } Direction logicalDirection = Direction.get(departureBlock.getLogicalDirection()); @@ -153,7 +153,7 @@ boolean searchRoute(Dispatcher dispatcher) { route = checkedRoutes.get(rIdx); Logger.trace("Choosen route " + route.toLogString()); //persist the departure block - PersistenceFactory.getService().persist(departureBlock); + PersistenceFactory.getService().persist(departureBlock); } else { Logger.debug("No route available for " + locomotive.getName() + " ..."); if (swapLocomotiveDirection) { @@ -223,7 +223,7 @@ boolean reserveRoute(Dispatcher dispatcher) { //Are playing a role. //On the departure side we have the OccupiedSensor, ie the IN sensor when arriving. //The exit sensor i.e the last sensor to leave the departure block. - String occupancySensorId, exitSensorId; + Integer occupancySensorId, exitSensorId; if ("+".equals(departureSuffix)) { occupancySensorId = departureBlock.getMinSensorId(); exitSensorId = departureBlock.getPlusSensorId(); @@ -236,7 +236,7 @@ boolean reserveRoute(Dispatcher dispatcher) { //On the destination side we have the enterSensor end the IN sensor. //From which side on the block is the train expected to arrive? - String enterSensorId, inSensorId; + Integer enterSensorId, inSensorId; if ("+".equals(arrivalSuffix)) { enterSensorId = destinationBlock.getPlusSensorId(); inSensorId = destinationBlock.getMinSensorId(); @@ -256,7 +256,7 @@ boolean reserveRoute(Dispatcher dispatcher) { if (swapLocomotiveDirection) { //Direction newDir = locomotive.getDispatcherDirection(); - Direction newDir = Direction.get(departureBlock.getLogicalDirection()); + Direction newDir = Direction.get(departureBlock.getLogicalDirection()); Logger.trace("Changing Direction to " + newDir); dispatcher.changeLocomotiveDirection(locomotive, newDir); } diff --git a/src/main/java/jcs/commandStation/autopilot/state/StartState.java b/src/main/java/jcs/commandStation/autopilot/state/StartState.java index e39a7a3b..e6cae22d 100644 --- a/src/main/java/jcs/commandStation/autopilot/state/StartState.java +++ b/src/main/java/jcs/commandStation/autopilot/state/StartState.java @@ -32,7 +32,7 @@ class StartState extends DispatcherState implements SensorEventListener { private boolean locomotiveStarted = false; private boolean canAdvanceToNextState = false; - private String enterSensorId; + private Integer enterSensorId; private Dispatcher dispatcher; @Override @@ -42,8 +42,8 @@ DispatcherState execute(Dispatcher dispatcher) { BlockBean departureBlock = dispatcher.getDepartureBlock(); BlockBean destinationBlock = dispatcher.getDestinationBlock(); - String occupancySensorId = dispatcher.getOccupationSensorId(); - String exitSensorId = dispatcher.getExitSensorId(); + Integer occupancySensorId = dispatcher.getOccupationSensorId(); + Integer exitSensorId = dispatcher.getExitSensorId(); //Register them both to ignore event form these sensors. ExpectedSensorEventHandler osh = new ExpectedSensorEventHandler(occupancySensorId, dispatcher); @@ -112,10 +112,10 @@ DispatcherState execute(Dispatcher dispatcher) { @Override public void onSensorChange(SensorEvent sensorEvent) { - if (enterSensorId.equals(sensorEvent.getId())) { + if (enterSensorId.equals(sensorEvent.getSensorId())) { if (sensorEvent.isActive()) { canAdvanceToNextState = true; - Logger.trace("Enter Event from Sensor " + sensorEvent.getId()); + Logger.trace("Enter Event from Sensor " + sensorEvent.getIdString()); synchronized (this) { this.notifyAll(); } diff --git a/src/main/java/jcs/commandStation/esu/ecos/AccessoryManager.java b/src/main/java/jcs/commandStation/esu/ecos/AccessoryManager.java index 4da6ecf7..8b91ccd2 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/AccessoryManager.java +++ b/src/main/java/jcs/commandStation/esu/ecos/AccessoryManager.java @@ -242,7 +242,7 @@ String findId(Integer address) { @Override public void onAccessoryChange(AccessoryEvent accessoryEvent) { AccessoryBean ab = accessoryEvent.getAccessoryBean(); - String id = accessoryEvent.getId(); + String id = accessoryEvent.getIdString(); if (!this.accessories.containsKey(id)) { id = findId(ab.getAddress()); } diff --git a/src/main/java/jcs/commandStation/esu/ecos/FeedbackManager.java b/src/main/java/jcs/commandStation/esu/ecos/FeedbackManager.java index 63087025..ab4c9c6a 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/FeedbackManager.java +++ b/src/main/java/jcs/commandStation/esu/ecos/FeedbackManager.java @@ -52,8 +52,8 @@ private List parse(EcosMessage message) { if (ID != objectId) { FeedbackModuleBean feedbackModule; - if (this.modules.containsKey(objectId)) { - feedbackModule = this.modules.get(objectId); + if (modules.containsKey(objectId)) { + feedbackModule = modules.get(objectId); } else { feedbackModule = new FeedbackModuleBean(); feedbackModule.setId(objectId); @@ -61,7 +61,6 @@ private List parse(EcosMessage message) { feedbackModule.setModuleNumber(objectId - S88_OFFSET); //ESU ECoS has 1 bus feedbackModule.setIdentifier(0); - feedbackModule.setPortCount(16); } if (values.containsKey(Ecos.PORTS)) { @@ -70,19 +69,21 @@ private List parse(EcosMessage message) { int ports = Integer.parseInt(vports); feedbackModule.setPortCount(ports); } + } else { + feedbackModule.setPortCount(S88_DEFAULT_PORT_COUNT); } if (values.containsKey(Ecos.STATE)) { String state = values.get(Ecos.STATE).toString(); updatePorts(state, feedbackModule); } - this.modules.put(objectId, feedbackModule); + modules.put(objectId, feedbackModule); changedSensors = feedbackModule.getChangedSensors(); if (event) { - if (this.ecosCommandStation != null) { + if (ecosCommandStation != null) { for (SensorEvent sensorEvent : changedSensors) { - this.ecosCommandStation.fireSensorEventListeners(sensorEvent); + ecosCommandStation.fireSensorEventListeners(sensorEvent); } } } @@ -97,7 +98,7 @@ private List parse(EcosMessage message) { fbmb.setId(S88_OFFSET + i); fbmb.setPortCount(S88_DEFAULT_PORT_COUNT); fbmb.setIdentifier(0); - this.modules.put(fbmb.getId(), fbmb); + modules.put(fbmb.getId(), fbmb); } } } diff --git a/src/main/java/jcs/commandStation/esu/ecos/net/EcosVirtualConnection.java b/src/main/java/jcs/commandStation/esu/ecos/net/EcosVirtualConnection.java index db9dad58..39ca5dd5 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/net/EcosVirtualConnection.java +++ b/src/main/java/jcs/commandStation/esu/ecos/net/EcosVirtualConnection.java @@ -178,7 +178,7 @@ public synchronized EcosMessage sendMessage(EcosMessage message) { default -> { //Interpret the message //Logger.trace(msg); - //Logger.trace(message.getId() + ": " + message.getCommand()); + //Logger.trace(message.getIdString() + ": " + message.getCommand()); String cmd = message.getCommand(); String id = message.getId(); int objId = message.getObjectId(); @@ -425,7 +425,7 @@ FeedbackModuleBean getFeedbackModule(int moduleId) { public void sendEvent(SensorEvent sensorEvent) { Logger.trace("Device: " + sensorEvent.getDeviceId() + " contact: " + sensorEvent.getContactId() + " -> " + sensorEvent.isActive()); FeedbackModuleBean fbm = getFeedbackModule(100 + sensorEvent.getDeviceId()); - //Logger.trace(fbm.getId()+" nr: "+fbm.getModuleNumber() + " Current ports: " + fbm.portToString()); + //Logger.trace(fbm.getIdString()+" nr: "+fbm.getModuleNumber() + " Current ports: " + fbm.portToString()); int port = sensorEvent.getContactId() - 1; fbm.setPortValue(port, sensorEvent.isActive()); //Logger.trace(100 + fbm.getModuleNumber() + " changed ports: " + fbm.portToString()); diff --git a/src/main/java/jcs/commandStation/events/AccessoryEvent.java b/src/main/java/jcs/commandStation/events/AccessoryEvent.java index 03ee2d36..34f94a98 100755 --- a/src/main/java/jcs/commandStation/events/AccessoryEvent.java +++ b/src/main/java/jcs/commandStation/events/AccessoryEvent.java @@ -63,7 +63,7 @@ public Integer getAddress() { } @Override - public String getId() { + public String getIdString() { return accessoryBean.getId(); } diff --git a/src/main/java/jcs/commandStation/events/JCSActionEvent.java b/src/main/java/jcs/commandStation/events/JCSActionEvent.java index 49a278bd..e353eee1 100644 --- a/src/main/java/jcs/commandStation/events/JCSActionEvent.java +++ b/src/main/java/jcs/commandStation/events/JCSActionEvent.java @@ -25,6 +25,6 @@ public interface JCSActionEvent { * * @return the id of the Object which requires an action */ - String getId(); + String getIdString(); } diff --git a/src/main/java/jcs/commandStation/events/SensorEvent.java b/src/main/java/jcs/commandStation/events/SensorEvent.java index b498b2f8..7127a9cd 100755 --- a/src/main/java/jcs/commandStation/events/SensorEvent.java +++ b/src/main/java/jcs/commandStation/events/SensorEvent.java @@ -38,22 +38,26 @@ public SensorBean getSensorBean() { return sensorBean; } + public Integer getSensorId() { + return sensorBean.getId(); + } + @Override - public String getId() { - if (sensorBean.getId() != null) { - return sensorBean.getId(); - } else { - //TODO: Number format? check with both CS 3 and HSI 88 life sensors - Integer deviceId = sensorBean.getDeviceId(); - Integer contactId = sensorBean.getContactId(); - String cn = ((contactId) > 9 ? "" : "0"); - if (cn.length() == 2) { - cn = "00" + cn; - } else if (cn.length() == 3) { - cn = "0" + cn; - } - return deviceId + "-" + cn; - } + public String getIdString() { +// if (sensorBean.getIdString() != null) { + return sensorBean.getId().toString(); +// } else { +// //TODO: Number format? check with both CS 3 and HSI 88 life sensors +// Integer deviceId = sensorBean.getDeviceId(); +// Integer contactId = sensorBean.getContactId(); +// String cn = ((contactId) > 9 ? "" : "0"); +// if (cn.length() == 2) { +// cn = "00" + cn; +// } else if (cn.length() == 3) { +// cn = "0" + cn; +// } +// return deviceId + "-" + cn; +// } } public Integer getDeviceId() { @@ -76,7 +80,7 @@ public boolean isActive() { @Override public String toString() { - return "SensorEvent{" + "id=" + getId() + ", active=" + (isActive() ? "1" : "0") + "}"; + return "SensorEvent{" + "id=" + getIdString() + ", active=" + (isActive() ? "1" : "0") + "}"; } } diff --git a/src/main/java/jcs/commandStation/hsis88/HSIImpl.java b/src/main/java/jcs/commandStation/hsis88/HSIImpl.java index 95b015a6..ffe412ab 100644 --- a/src/main/java/jcs/commandStation/hsis88/HSIImpl.java +++ b/src/main/java/jcs/commandStation/hsis88/HSIImpl.java @@ -278,7 +278,8 @@ private void fireSensorEvents(HSIMessage message) { //Logger.trace("U: " + sb.toLogString()); } } else { - sb = new SensorBean(0, key, contacts[i]); + //TODO: !!!!!!! + sb = null; //new SensorBean(0, key, contacts[i]); this.sensors.put(sb.getContactId(), sb); SensorEvent se = new SensorEvent(sb); diff --git a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java index 48d522c7..6e922548 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java +++ b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java @@ -480,7 +480,7 @@ public List getFeedbackModules() { // sb.setDeviceId(deviceId); // sb.setContactId((i + 1)); // sb.setName("B0-S-" + (i + 1)); -// String id = sb.getId(); +// String id = sb.getIdString(); // sensorBeans.put(id, sb); // } // } diff --git a/src/main/java/jcs/commandStation/marklin/cs/can/parser/FeedbackEventMessage.java b/src/main/java/jcs/commandStation/marklin/cs/can/parser/FeedbackEventMessage.java index 93d65443..a2dd7bd8 100644 --- a/src/main/java/jcs/commandStation/marklin/cs/can/parser/FeedbackEventMessage.java +++ b/src/main/java/jcs/commandStation/marklin/cs/can/parser/FeedbackEventMessage.java @@ -46,7 +46,8 @@ public static SensorBean parse(CanMessage message, Date eventDate) { int status = data[5]; Integer millis = ByteUtil.toInt(new byte[]{data[6], data[7]}) * 10; - SensorBean sensorBean = new SensorBean(deviceId, contactId, status, previousStatus, millis, eventDate); + //TODO!!!!!! + SensorBean sensorBean = null;//new SensorBean(deviceId, contactId, status, previousStatus, millis, eventDate); return sensorBean; } else { Logger.warn("Can't parse message, not a Sensor Response! " + resp); diff --git a/src/main/java/jcs/commandStation/virtual/VirtualCommandStationImpl.java b/src/main/java/jcs/commandStation/virtual/VirtualCommandStationImpl.java index d861a454..040e8417 100644 --- a/src/main/java/jcs/commandStation/virtual/VirtualCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/virtual/VirtualCommandStationImpl.java @@ -82,7 +82,7 @@ public synchronized boolean connect() { // mainDevice.setVersion(VersionInfo.getVersion()); // // mainDevice.setSerial("1"); -// mainDevice.setIdentifier(this.commandStationBean.getId()); +// mainDevice.setIdentifier(this.commandStationBean.getIdString()); // mainDevice.setName(this.commandStationBean.getDescription()); infoBean = new InfoBean(); @@ -300,7 +300,7 @@ public void switchAccessory(Integer address, String protocol, AccessoryBean.Acce private void fireAllAccessoryEventListeners(final AccessoryEvent accessoryEvent) { for (AccessoryEventListener listener : this.accessoryEventListeners) { listener.onAccessoryChange(accessoryEvent); - Logger.trace("Fired accessory listener " + accessoryEvent.getId()); + Logger.trace("Fired accessory listener " + accessoryEvent.getIdString()); } } diff --git a/src/main/java/jcs/entities/BlockBean.java b/src/main/java/jcs/entities/BlockBean.java index edc9223c..a014ff74 100644 --- a/src/main/java/jcs/entities/BlockBean.java +++ b/src/main/java/jcs/entities/BlockBean.java @@ -31,8 +31,8 @@ public class BlockBean { private String id; private String tileId; private String description; - private String plusSensorId; - private String minSensorId; + private Integer plusSensorId; + private Integer minSensorId; private String plusSignalId; private String minSignalId; private Long locomotiveId; @@ -110,11 +110,11 @@ public void setDescription(String description) { } @Column(name = "plus_sensor_id") - public String getPlusSensorId() { + public Integer getPlusSensorId() { return plusSensorId; } - public void setPlusSensorId(String plusSensorId) { + public void setPlusSensorId(Integer plusSensorId) { this.plusSensorId = plusSensorId; } @@ -133,11 +133,11 @@ public void setPlusSensorBean(SensorBean plusSensorBean) { } @Column(name = "min_sensor_id") - public String getMinSensorId() { + public Integer getMinSensorId() { return minSensorId; } - public void setMinSensorId(String minSensorId) { + public void setMinSensorId(Integer minSensorId) { this.minSensorId = minSensorId; } diff --git a/src/main/java/jcs/entities/FeedbackModuleBean.java b/src/main/java/jcs/entities/FeedbackModuleBean.java index af710dd7..a93f6b25 100644 --- a/src/main/java/jcs/entities/FeedbackModuleBean.java +++ b/src/main/java/jcs/entities/FeedbackModuleBean.java @@ -34,8 +34,26 @@ public class FeedbackModuleBean { private int[] prevPorts; public static int DEFAULT_PORT_COUNT = 16; + public static int DEFAULT_ADDRESS_OFFSET = 0; + public static int DEFAULT_IDENTIFIER = 0; public FeedbackModuleBean() { + this(null, null); + } + + public FeedbackModuleBean(Integer id, Integer moduleNumber) { + this(id, moduleNumber, DEFAULT_PORT_COUNT, DEFAULT_ADDRESS_OFFSET, DEFAULT_IDENTIFIER); + } + + public FeedbackModuleBean(Integer id, Integer moduleNumber, Integer portCount, Integer addressOffset, Integer identifier) { + this.id = id; + this.moduleNumber = moduleNumber; + this.portCount = portCount; + this.addressOffset = addressOffset; + this.identifier = identifier; + + ports = new int[portCount]; + prevPorts = new int[portCount]; } public Integer getId() { @@ -60,16 +78,9 @@ public Integer getPortCount() { public void setPortCount(Integer portCount) { this.portCount = portCount; - if (portCount != null) { - if (this.ports == null) { - ports = new int[portCount]; - prevPorts = new int[portCount]; - } else { - if (ports.length != portCount) { - ports = new int[portCount]; - prevPorts = new int[portCount]; - } - } + if (portCount != null && portCount != ports.length) { + ports = new int[portCount]; + prevPorts = new int[portCount]; } } @@ -103,6 +114,14 @@ public void setPortValue(int port, boolean active) { this.ports[port] = active ? 1 : 0; } + public boolean isPort(int port) { + if (ports != null && port < ports.length) { + return this.ports[port] == 1; + } else { + return false; + } + } + public int getAccumulatedPortsValue() { int val = 0; for (int i = 0; i < ports.length; i++) { @@ -123,25 +142,69 @@ public void setPrevPorts(int[] prevPorts) { this.prevPorts = prevPorts; } +// public static Integer calculateModuleNumber(int contactId) { +// int module = (contactId - 1) / 16 + 1; +// return module; +// } +// public static int calculatePortNumber(int contactId) { +// int module = (contactId - 1) / 16 + 1; +// int mport = contactId - (module - 1) * 16; +// return mport; +// } +// public static int calculateContactId(int module, int port) { +// //Bei einer CS2 errechnet sich der richtige Kontakt mit der Formel M - 1 * 16 + N +// module = module - 1; +// int contactId = module * 16; +// return contactId + port; + // } public SensorBean getSensor(int port) { - SensorBean sb = new SensorBean(id, port, ports[port]); + int node = identifier; + int pcnt = portCount; + int modnr = this.moduleNumber; + + int sensorId = addressOffset + moduleNumber + port; + int contactId = port; + + //contactid moet doornummer van device is de node of nodg een veld in de sensor table toeveoegen + SensorBean sb = new SensorBean(sensorId, moduleNumber, contactId, identifier, ports[port]); + //id of a sensor is deviceid + contactid + //device is moduelnr + //contact -- + //dit lukt bij esu want maar 1 bus.. + //niet bi marklin want 4 bussen of zeggen bus 1 device 0 en conatct 1000 + // 1 conatct 1016 etc + // bus 0 0 en conatct 0 - 15 + // bsu 2 0 ense 2000 --- + //dus voor id de address offset er bij tellen dus + //modulenr + contactnr + //this.moduleNumber; + + //Marklin: + //node in case of Link S88 else 0 when cs self + //when 0 - 15 then Link s88 self so address offset should be 0 module id 0 + //when 1000 (bus 1) address offset 1000 module nr 0 - 31 sensor is module nr * 16 + port + offset + //sensor is is offset + module nr * 16 + port + // module number * 16 + port + address offset + // address depends on the BUS as ther are 4 busses with differen address offsets + //contact id of the module (0- 15) has to be added to the (bus) adressoffset to get the sensor address so bus 1 is 1000 + //ESU + // node is 0 + //id is the ojbetc id isstart with 100 + //module number is id - offset (100) set by the esu + // sensor id offset + module nr + module nr * 16 + port + //contact id is the module id * 16 +port ie 0 1st module, 1 2nd mod 16+0 is contact 1 on 2ndmod + // + //second device is 101 so these then id's 16 = 31 addres offset is 100 + // is module number + 16 + address offset return sb; } - public boolean isPort(int port) { - if (ports != null && port < ports.length) { - return this.ports[port] == 1; - } else { - return false; - } - } - public List getChangedSensors() { List changedSensors = new ArrayList<>(ports.length); for (int i = 0; i < ports.length; i++) { if (ports[i] != prevPorts[i]) { - SensorBean sb = new SensorBean(moduleNumber, i + 1, ports[i]); + SensorBean sb = null; //new SensorBean(moduleNumber, i + 1, ports[i]); SensorEvent se = new SensorEvent(sb); changedSensors.add(se); } @@ -154,7 +217,7 @@ public List getSensors() { for (int i = 0; i < ports.length; i++) { if (ports[i] != prevPorts[i]) { - SensorBean sb = new SensorBean(moduleNumber, i + 1, ports[i]); + SensorBean sb = null; //new SensorBean(moduleNumber, i + 1, ports[i]); sensors.add(sb); } } diff --git a/src/main/java/jcs/entities/SensorBean.java b/src/main/java/jcs/entities/SensorBean.java index 7ec90c05..54319131 100755 --- a/src/main/java/jcs/entities/SensorBean.java +++ b/src/main/java/jcs/entities/SensorBean.java @@ -21,15 +21,14 @@ import jakarta.persistence.Table; import jakarta.persistence.Transient; -import java.io.Serializable; import java.util.Date; import java.util.Objects; @Table(name = "sensors", indexes = { @Index(name = "sens_devi_cont_idx", columnList = "device_id, contact_id", unique = true)}) -public class SensorBean implements Serializable { +public class SensorBean { - private String id; + private Integer id; private String name; private Integer deviceId; private Integer contactId; @@ -37,62 +36,61 @@ public class SensorBean implements Serializable { private Integer previousStatus; private Integer millis; private Date lastUpdated; + private Integer nodeId; public SensorBean() { - this(null, null, null, null, null, null, null, null); + this(null,null, null, null, null, null, null, null, null); } - public SensorBean(Integer deviceId, Integer contactId, Integer status) { - this(null, null, deviceId, contactId, status, null, null, null); - } - public SensorBean(Integer deviceId, Integer contactId, Integer status, Integer previousStatus, Integer millis, Date lastUpdated) { - this(null, null, deviceId, contactId, status, previousStatus, millis, lastUpdated); + public SensorBean(Integer id, Integer deviceId, Integer contactId, Integer nodeId, Integer status) { + this(id, null, deviceId, contactId, nodeId, status, null, null, null); } - public SensorBean(String name, Integer deviceId, Integer contactId) { - this(null, name, deviceId, contactId, null, null, null, null); - } +// public SensorBean(Integer deviceId, Integer contactId, Integer status, Integer previousStatus, Integer millis, Date lastUpdated) { +// this(null, null, deviceId, contactId, status, previousStatus, millis, lastUpdated); +// } - public SensorBean(String name, Integer deviceId, Integer contactId, Integer status, Integer previousStatus, Integer millis, Date lastUpdated) { - this(null, name, deviceId, contactId, status, previousStatus, millis, lastUpdated); - } +// public SensorBean(Integer id, String name, Integer deviceId, Integer contactId, Integer nodeId) { +// this(id, name, deviceId, contactId, null,null, null, null, null); +// } - public SensorBean(String id, String name, Integer deviceId, Integer contactId, Integer status, Integer previousStatus, Integer millis, Date lastUpdated) { +// public SensorBean(String name, Integer deviceId, Integer contactId, Integer status, Integer previousStatus, Integer millis, Date lastUpdated) { +// this(null, name, deviceId, contactId, status, previousStatus, millis, lastUpdated); +// } + public SensorBean(Integer id, String name, Integer deviceId, Integer contactId, Integer nodeId, Integer status, Integer previousStatus, Integer millis, Date lastUpdated) { this.id = id; this.name = name; this.status = status; this.previousStatus = previousStatus; this.deviceId = deviceId; this.contactId = contactId; + this.nodeId = nodeId; this.millis = millis; this.lastUpdated = lastUpdated; + + if (name == null && deviceId != null && contactId != null) { + String cn = contactId.toString(); + int cnl = cn.length(); + for (int x = 0; x < 4 - cnl; x++) { + cn = "0" + cn; + } + String dn = deviceId.toString(); + int dnl = dn.length(); + for (int x = 0; x < 2 - cnl; x++) { + dn = "0" + dn; + } + this.name = dn + "-" + cn; + } } @Id @Column(name = "id", nullable = false) - public String getId() { - if (id == null) { - id = generateId(); - } + public Integer getId() { return id; } - private String generateId() { - //Format the id start with the device then "-" - //than a 4 char contact id - if (contactId == null) { - return null; - } - String cn = contactId.toString(); - int cnl = cn.length(); - for (int x = 0; x < 4 - cnl; x++) { - cn = "0" + cn; - } - return deviceId + "-" + cn; - } - - public void setId(String id) { + public void setId(Integer id) { this.id = id; } @@ -123,6 +121,15 @@ public void setContactId(Integer contactId) { this.contactId = contactId; } + @Column(name = "node_id") + public Integer getNodeId() { + return nodeId; + } + + public void setNodeId(Integer nodeId) { + this.nodeId = nodeId; + } + @Column(name = "status") public Integer getStatus() { return status; @@ -226,6 +233,7 @@ public int hashCode() { hash = 41 * hash + Objects.hashCode(this.name); hash = 41 * hash + Objects.hashCode(this.deviceId); hash = 41 * hash + Objects.hashCode(this.contactId); + hash = 41 * hash + Objects.hashCode(this.nodeId); hash = 41 * hash + Objects.hashCode(this.status); hash = 41 * hash + Objects.hashCode(this.previousStatus); hash = 41 * hash + Objects.hashCode(this.millis); @@ -257,6 +265,9 @@ public boolean equals(Object obj) { if (!Objects.equals(this.contactId, other.contactId)) { return false; } + if (!Objects.equals(this.nodeId, other.nodeId)) { + return false; + } if (!Objects.equals(this.status, other.status)) { return false; } @@ -286,28 +297,44 @@ public boolean equalsDeviceIdAndContactId(Object obj) { return Objects.equals(this.contactId, other.contactId); } + public boolean equalsId(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final SensorBean other = (SensorBean) obj; + return Objects.equals(this.id, other.id); + } + @Override public String toString() { return name; } public String toLogString() { - String ids; - if (id == null) { - ids = "(" + generateId() + ")"; - } else { - ids = id; - } +// String ids; +// if (id == null) { +// ids = "(" + generateId() + ")"; +// } else { +// ids = id; +// } return "SensorBean{" + "id=" - + ids + + id + ", name=" + name + ", deviceId=" + deviceId + ", contactId=" + contactId + + ", nodeId=" + + nodeId + ", status=" + status + ", previousStatus=" @@ -316,22 +343,6 @@ public String toLogString() { + millis + ", lastUpdated=" + lastUpdated - + '}'; + + "}"; } } - -// public static Integer calculateModuleNumber(int contactId) { -// int module = (contactId - 1) / 16 + 1; -// return module; -// } -// public static int calculatePortNumber(int contactId) { -// int module = (contactId - 1) / 16 + 1; -// int mport = contactId - (module - 1) * 16; -// return mport; -// } -// public static int calculateContactId(int module, int port) { -// //Bei einer CS2 errechnet sich der richtige Kontakt mit der Formel M - 1 * 16 + N -// module = module - 1; -// int contactId = module * 16; -// return contactId + port; - // } diff --git a/src/main/java/jcs/entities/TileBean.java b/src/main/java/jcs/entities/TileBean.java index 8976511b..21384242 100644 --- a/src/main/java/jcs/entities/TileBean.java +++ b/src/main/java/jcs/entities/TileBean.java @@ -22,7 +22,6 @@ import jakarta.persistence.Transient; import java.awt.Point; -import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -33,7 +32,7 @@ @Table(name = "tiles", indexes = { @Index(name = "tile_x_y", columnList = "x, y", unique = true)}) -public class TileBean implements Serializable, Comparable { +public class TileBean implements Comparable { protected String id; protected Integer x; @@ -43,7 +42,7 @@ public class TileBean implements Serializable, Comparable { protected String tileDirection; protected String signalAccessoryType; protected String accessoryId; - protected String sensorId; + protected Integer sensorId; protected List neighbours; @@ -60,11 +59,11 @@ public TileBean(String id, TileType tileType, Orientation orientation, Direction this(id, tileType, orientation, direction, x, y, null, null, null); } - public TileBean(String id, TileType tileType, Orientation orientation, Direction direction, Point center, SignalType signalType, String accessoryId, String sensorId) { + public TileBean(String id, TileType tileType, Orientation orientation, Direction direction, Point center, SignalType signalType, String accessoryId, Integer sensorId) { this(id, tileType, orientation, direction, center.x, center.y, signalType, null, sensorId); } - public TileBean(String id, TileType tileType, Orientation orientation, Direction direction, Integer x, Integer y, SignalType signalType, String accessoryId, String sensorId) { + public TileBean(String id, TileType tileType, Orientation orientation, Direction direction, Integer x, Integer y, SignalType signalType, String accessoryId, Integer sensorId) { this.id = id; this.setTileType(tileType); this.tileOrientation = orientation.getOrientation(); @@ -208,11 +207,11 @@ public void setAccessoryId(String accessoryId) { } @Column(name = "sensor_id") - public String getSensorId() { + public Integer getSensorId() { return sensorId; } - public void setSensorId(String sensorId) { + public void setSensorId(Integer sensorId) { this.sensorId = sensorId; } diff --git a/src/main/java/jcs/persistence/H2PersistenceService.java b/src/main/java/jcs/persistence/H2PersistenceService.java index 6d567ac0..81618f28 100755 --- a/src/main/java/jcs/persistence/H2PersistenceService.java +++ b/src/main/java/jcs/persistence/H2PersistenceService.java @@ -140,7 +140,7 @@ public SensorBean getSensor(Integer deviceId, Integer contactId) { } @Override - public SensorBean getSensor(String id) { + public SensorBean getSensor(Integer id) { SensorBean sensor = database.where("id=?", id).first(SensorBean.class); return sensor; } @@ -173,8 +173,9 @@ public void remove(SensorBean sensor) { } @Override + @Deprecated public List generateSensorBeans(Integer deviceId, Integer bus0len, Integer bus1len, Integer bus2len, Integer bus3len) { - Map sensorBeans = new HashMap<>(); + Map sensorBeans = new HashMap<>(); if (bus0len != null) { for (int i = 0; i < (bus0len * 16); i++) { @@ -182,7 +183,7 @@ public List generateSensorBeans(Integer deviceId, Integer bus0len, I sb.setDeviceId(deviceId); sb.setContactId((i + 1)); sb.setName("B0-S-" + (i + 1)); - String id = sb.getId(); + Integer id = sb.getId(); sensorBeans.put(id, sb); } } @@ -193,7 +194,7 @@ public List generateSensorBeans(Integer deviceId, Integer bus0len, I sb.setDeviceId(deviceId); sb.setContactId((i + 1001)); sb.setName("B1-S-" + (i + 1001)); - String id = sb.getId(); + Integer id = sb.getId(); sensorBeans.put(id, sb); } } @@ -204,7 +205,7 @@ public List generateSensorBeans(Integer deviceId, Integer bus0len, I sb.setDeviceId(deviceId); sb.setContactId((i + 2001)); sb.setName("B2-S-" + (i + 2001)); - String id = sb.getId(); + Integer id = sb.getId(); sensorBeans.put(id, sb); } } @@ -214,7 +215,7 @@ public List generateSensorBeans(Integer deviceId, Integer bus0len, I SensorBean sb = new SensorBean(); sb.setContactId((i + 3001)); sb.setName("B3-S-" + (i + 3001)); - String id = sb.getId(); + Integer id = sb.getId(); sensorBeans.put(id, sb); } } diff --git a/src/main/java/jcs/persistence/PersistenceService.java b/src/main/java/jcs/persistence/PersistenceService.java index 28ec731c..ddd12548 100755 --- a/src/main/java/jcs/persistence/PersistenceService.java +++ b/src/main/java/jcs/persistence/PersistenceService.java @@ -100,7 +100,7 @@ public interface PersistenceService { * @param id The ID of the SensorBean to retrieve. * @return The SensorBean, or null if not found. */ - SensorBean getSensor(String id); + SensorBean getSensor(Integer id); /** * Retrieves a SensorBean by device and contact ID. @@ -136,6 +136,7 @@ public interface PersistenceService { * @param bus3len Length of bus 3. * @return A List of generated SensorBeans. */ + @Deprecated List generateSensorBeans(Integer deviceId, Integer bus0len, Integer bus1len, Integer bus2len, Integer bus3len); // Locomotive diff --git a/src/main/java/jcs/ui/layout/dialogs/BlockDialog.java b/src/main/java/jcs/ui/layout/dialogs/BlockDialog.java index 9b06c95f..9a29d5e2 100644 --- a/src/main/java/jcs/ui/layout/dialogs/BlockDialog.java +++ b/src/main/java/jcs/ui/layout/dialogs/BlockDialog.java @@ -39,6 +39,8 @@ */ public class BlockDialog extends javax.swing.JDialog { + private static final long serialVersionUID = 6278388475191663591L; + private final Block block; private final LayoutCanvas layoutCanvas; @@ -61,9 +63,9 @@ public BlockDialog(java.awt.Frame parent, Block block, LayoutCanvas layoutCanvas postInit(); } - private Set getLinkedSensorIds() { + private Set getLinkedSensorIds() { List blocks = PersistenceFactory.getService().getBlocks(); - Set linkedSensorIds = new HashSet<>(); + Set linkedSensorIds = new HashSet<>(); for (BlockBean bb : blocks) { if (bb.getPlusSensorId() != null) { linkedSensorIds.add(bb.getPlusSensorId()); @@ -85,7 +87,7 @@ private void postInit() { List allSensors = PersistenceFactory.getService().getSensors(); List freeSensors = new ArrayList<>(); // filter the list, remove sensors which are already linked to other blocks. - Set linkedSensorIds = getLinkedSensorIds(); + Set linkedSensorIds = getLinkedSensorIds(); for (SensorBean sb : allSensors) { if (!linkedSensorIds.contains(sb.getId())) { diff --git a/src/main/java/jcs/ui/layout/dialogs/SensorDialog.java b/src/main/java/jcs/ui/layout/dialogs/SensorDialog.java index 0d7f2c20..bbcebda9 100644 --- a/src/main/java/jcs/ui/layout/dialogs/SensorDialog.java +++ b/src/main/java/jcs/ui/layout/dialogs/SensorDialog.java @@ -29,6 +29,7 @@ import jcs.persistence.PersistenceFactory; import jcs.ui.layout.tiles.Sensor; import jcs.ui.layout.tiles.Tile; +import jcs.ui.layout.tiles.TileCache; import org.tinylog.Logger; /** @@ -37,6 +38,8 @@ */ public class SensorDialog extends javax.swing.JDialog { + private static final long serialVersionUID = -1992484290463412418L; + private final Sensor sensor; private final SensorBeanComboBoxModel sensorComboBoxModel; @@ -57,13 +60,13 @@ public SensorDialog(java.awt.Frame parent, Tile tile) { private void postInit() { setLocationRelativeTo(null); - String text = this.headingLbl.getText() + " " + this.sensor.getId(); + String text = this.headingLbl.getText() + " " + sensor.getId(); this.headingLbl.setText(text); List sensors = PersistenceFactory.getService().getSensors(); List sensorTiles = PersistenceFactory.getService().getTileBeansByTileType(TileBean.TileType.SENSOR); - Set usedSensorIds = new HashSet<>(); + Set usedSensorIds = new HashSet<>(); for (TileBean tb : sensorTiles) { if (tb.getSensorId() != null) { usedSensorIds.add(tb.getSensorId()); @@ -77,11 +80,11 @@ private void postInit() { } } //Ensure the selected is still there - if (this.sensor.getSensorBean() != null) { - filtered.add(this.sensor.getSensorBean()); + if (sensor.getSensorBean() != null) { + filtered.add(sensor.getSensorBean()); } else { - if (sensor.getSensorId() != null && this.sensor.getSensorBean() == null) { - this.sensor.setSensorBean(PersistenceFactory.getService().getSensor(sensor.getSensorId())); + if (sensor.getSensorId() != null && sensor.getSensorBean() == null) { + sensor.setSensorBean(PersistenceFactory.getService().getSensor(sensor.getSensorId())); filtered.add(this.sensor.getSensorBean()); } } @@ -92,30 +95,30 @@ private void postInit() { sensorComboBoxModel.removeAllElements(); sensorComboBoxModel.addAll(filtered); - this.sensorCB.setModel(sensorComboBoxModel); + sensorCB.setModel(sensorComboBoxModel); SensorBean sb = this.sensor.getSensorBean(); if (sb == null) { sb = emptyBean; - //Use the SensorTileId as id - sb.setId(this.sensor.getId()); + //Use the SensorTileId as id sequence + sb.setId(TileCache.getIdSeq(sensor.getId())); } - this.sensor.setSensorBean(sb); - this.sensorComboBoxModel.setSelectedItem(sb); + sensor.setSensorBean(sb); + sensorComboBoxModel.setSelectedItem(sb); - if (this.sensor.getSensorBean().getName() != null) { - this.nameTF.setText(this.sensor.getSensorBean().getName()); + if (sensor.getSensorBean().getName() != null) { + nameTF.setText(this.sensor.getSensorBean().getName()); } else { //Use the tile name - this.nameTF.setText(this.sensor.getTileBean().getId()); + nameTF.setText(sensor.getTileBean().getId()); } - if (this.sensor.getSensorBean().getDeviceId() != null) { - this.deviceIdSpinner.setValue(this.sensor.getSensorBean().getDeviceId()); + if (sensor.getSensorBean().getDeviceId() != null) { + deviceIdSpinner.setValue(this.sensor.getSensorBean().getDeviceId()); } if (this.sensor.getSensorBean().getContactId() != null) { - this.contactIdSpinner.setValue(this.sensor.getSensorBean().getContactId()); + contactIdSpinner.setValue(this.sensor.getSensorBean().getContactId()); } if (JCS.getJcsCommandStation() != null) { @@ -267,7 +270,9 @@ private void saveExitBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-F JCS.getJcsCommandStation().addSensorEventListener(sensor); } } else if (this.sensor != null && this.sensor.getSensorBean() == null) { - SensorBean sensorBean = new SensorBean(this.nameTF.getText(), (Integer) this.deviceIdSpinner.getValue(), (Integer) contactIdSpinner.getValue()); + + //TODO !!!!! + SensorBean sensorBean = null; //new SensorBean(this.nameTF.getText(), (Integer) this.deviceIdSpinner.getValue(), (Integer) contactIdSpinner.getValue()); if (PersistenceFactory.getService() != null) { sensorBean = PersistenceFactory.getService().persist(sensorBean); @@ -308,13 +313,13 @@ class SensorBeanByIdSorter implements Comparator { @Override public int compare(SensorBean a, SensorBean b) { //Avoid null pointers - String aa = a.getId(); + Integer aa = a.getId(); if (aa == null) { - aa = "000"; + aa = 0; } - String bb = b.getId(); + Integer bb = b.getId(); if (bb == null) { - bb = "000"; + bb = 0; } return aa.compareTo(bb); @@ -323,6 +328,8 @@ public int compare(SensorBean a, SensorBean b) { class SensorBeanComboBoxModel extends DefaultComboBoxModel { + private static final long serialVersionUID = 3565601635482469055L; + private final List model; public SensorBeanComboBoxModel() { diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java index 5ca5e808..4ba0ad50 100755 --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -26,7 +26,6 @@ import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; import java.beans.PropertyChangeListener; -import java.io.Serializable; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -72,7 +71,7 @@ * which have an influence on the screen are in the TileModel.
* All Drawing code is in the TileUI. */ -public abstract class Tile extends JComponent { // implements ChangeListener +public abstract class Tile extends JComponent { public static final int GRID = 20; public static final int DEFAULT_WIDTH = GRID * 2; @@ -101,13 +100,11 @@ public abstract class Tile extends JComponent { // implements ChangeListener protected TileType tileType; protected String accessoryId; - protected String sensorId; + protected Integer sensorId; - //protected AccessoryValue accessoryValue; protected AccessoryValue routeValue; protected SignalType signalType; - //protected AccessoryBean.SignalValue signalValue; protected TileBean tileBean; protected AccessoryBean accessoryBean; @@ -408,11 +405,11 @@ public void setAccessoryId(String accessoryId) { } } - public String getSensorId() { + public Integer getSensorId() { return sensorId; } - public void setSensorId(String sensorId) { + public void setSensorId(Integer sensorId) { this.sensorId = sensorId; } @@ -930,7 +927,7 @@ private Handler getHandler() { return handler; } - class Handler implements ActionListener, ChangeListener, Serializable { + class Handler implements ActionListener, ChangeListener { @Override public void stateChanged(ChangeEvent e) { @@ -987,14 +984,4 @@ public Rectangle getTileBounds() { return new Rectangle(tileX - renderWidth / 2, tileY - renderHeight / 2, renderWidth, renderHeight); } } - -// @Override -// protected void paintComponent(Graphics g) { -// if (Logger.isTraceEnabled()) { -// long started = System.currentTimeMillis(); -// super.paintComponent(g); -// long now = System.currentTimeMillis(); -// Logger.trace(id + " Duration: " + (now - started) + " ms. Cp: " + xyToString() + " O: " + model.getTileOrienation()); -// } -// } } diff --git a/src/main/java/jcs/ui/layout/tiles/TileActionEventHandler.java b/src/main/java/jcs/ui/layout/tiles/TileActionEventHandler.java index 93a1cf34..6ce2c7b0 100644 --- a/src/main/java/jcs/ui/layout/tiles/TileActionEventHandler.java +++ b/src/main/java/jcs/ui/layout/tiles/TileActionEventHandler.java @@ -87,7 +87,7 @@ public void run() { } private void fireSensorEvent(SensorEvent sensorEvent) { - //Logger.trace("Firing Sensor Action " + sensorEvent.getId() + " -> " + sensorEvent.isActive()); + //Logger.trace("Firing Sensor Action " + sensorEvent.getIdString() + " -> " + sensorEvent.isActive()); List acl = JCS.getJcsCommandStation().getFeedbackControllers(); for (FeedbackController fbc : acl) { fbc.fireSensorEventListeners(sensorEvent); diff --git a/src/main/java/jcs/ui/layout/tiles/TileCache.java b/src/main/java/jcs/ui/layout/tiles/TileCache.java index 3b8dd766..83aa2d4e 100644 --- a/src/main/java/jcs/ui/layout/tiles/TileCache.java +++ b/src/main/java/jcs/ui/layout/tiles/TileCache.java @@ -80,7 +80,7 @@ public class TileCache { private TileCache() { } - private static int nextIdSeq(String id) { + public static int getIdSeq(String id) { String idnr = id.substring(3); int idSeq = Integer.parseInt(idnr); return idSeq; @@ -153,21 +153,21 @@ public static Tile createTile(TileBean tileBean, boolean showValues) { switch (tileType) { case STRAIGHT -> { tile = new Straight(tileBean); - straightIdSeq = maxIdSeq(straightIdSeq, nextIdSeq(tileBean.getId())); + straightIdSeq = maxIdSeq(straightIdSeq, getIdSeq(tileBean.getId())); } case CROSSING -> { tile = new Crossing(tileBean); - crossingIdSeq = maxIdSeq(crossingIdSeq, nextIdSeq(tileBean.getId())); + crossingIdSeq = maxIdSeq(crossingIdSeq, getIdSeq(tileBean.getId())); } case CURVED -> { tile = new Curved(tileBean); - curvedIdSeq = maxIdSeq(curvedIdSeq, nextIdSeq(tileBean.getId())); + curvedIdSeq = maxIdSeq(curvedIdSeq, getIdSeq(tileBean.getId())); } case SWITCH -> { tile = new Switch(tileBean); tile.setAccessoryBean(tileBean.getAccessoryBean()); - switchIdSeq = maxIdSeq(switchIdSeq, nextIdSeq(tileBean.getId())); + switchIdSeq = maxIdSeq(switchIdSeq, getIdSeq(tileBean.getId())); if (showValues && tileBean.getAccessoryBean() != null) { tile.setAccessoryValue((tileBean.getAccessoryBean()).getAccessoryValue()); } @@ -177,7 +177,7 @@ public static Tile createTile(TileBean tileBean, boolean showValues) { tile = new Cross(tileBean); tile.setAccessoryBean(tileBean.getAccessoryBean()); - crossIdSeq = maxIdSeq(crossIdSeq, nextIdSeq(tileBean.getId())); + crossIdSeq = maxIdSeq(crossIdSeq, getIdSeq(tileBean.getId())); if (showValues && tileBean.getAccessoryBean() != null) { tile.setAccessoryValue((tileBean.getAccessoryBean()).getAccessoryValue()); } @@ -187,7 +187,7 @@ public static Tile createTile(TileBean tileBean, boolean showValues) { tile = new Signal(tileBean); tile.setAccessoryBean(tileBean.getAccessoryBean()); - signalIdSeq = maxIdSeq(signalIdSeq, nextIdSeq(tileBean.getId())); + signalIdSeq = maxIdSeq(signalIdSeq, getIdSeq(tileBean.getId())); if (showValues && tileBean.getAccessoryBean() != null) { ((Signal) tile).setSignalValue(((AccessoryBean) tileBean.getAccessoryBean()).getSignalValue()); } @@ -196,7 +196,7 @@ public static Tile createTile(TileBean tileBean, boolean showValues) { case SENSOR -> { tile = new Sensor(tileBean); tile.setSensorBean(tileBean.getSensorBean()); - sensorIdSeq = maxIdSeq(sensorIdSeq, nextIdSeq(tileBean.getId())); + sensorIdSeq = maxIdSeq(sensorIdSeq, getIdSeq(tileBean.getId())); if (showValues && tileBean.getSensorBean() != null) { ((Sensor) tile).setActive(((SensorBean) tileBean.getSensorBean()).isActive()); @@ -206,15 +206,15 @@ public static Tile createTile(TileBean tileBean, boolean showValues) { case BLOCK -> { tile = new Block(tileBean); tile.setBlockBean(tileBean.getBlockBean()); - blockIdSeq = maxIdSeq(blockIdSeq, nextIdSeq(tileBean.getId())); + blockIdSeq = maxIdSeq(blockIdSeq, getIdSeq(tileBean.getId())); } case STRAIGHT_DIR -> { tile = new StraightDirection(tileBean); - straightDirectionIdSeq = maxIdSeq(straightDirectionIdSeq, nextIdSeq(tileBean.getId())); + straightDirectionIdSeq = maxIdSeq(straightDirectionIdSeq, getIdSeq(tileBean.getId())); } case END -> { tile = new End(tileBean); - endIdSeq = maxIdSeq(endIdSeq, nextIdSeq(tileBean.getId())); + endIdSeq = maxIdSeq(endIdSeq, getIdSeq(tileBean.getId())); } default -> Logger.warn("Unknown Tile Type " + tileType); diff --git a/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java b/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java index 14fda899..42223e8f 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java @@ -99,7 +99,7 @@ public void mousePressed(MouseEvent e) { sb.setLastUpdated(new Date()); SensorEvent sae = new SensorEvent(sb); TileCache.enqueTileAction(sae); - //Logger.trace("Changing Tile "+tile.getId()+" Sensor "+sb.getId()+" to "+sb.isActive()+"..."); + //Logger.trace("Changing Tile "+tile.getIdString()+" Sensor "+sb.getIdString()+" to "+sb.isActive()+"..."); } } else { redispatchToParent(e); diff --git a/src/main/java/jcs/ui/settings/table/SensorTableModel.java b/src/main/java/jcs/ui/settings/table/SensorTableModel.java index 6c40b982..231ae4d8 100644 --- a/src/main/java/jcs/ui/settings/table/SensorTableModel.java +++ b/src/main/java/jcs/ui/settings/table/SensorTableModel.java @@ -15,7 +15,6 @@ */ package jcs.ui.settings.table; -import java.math.BigDecimal; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -32,6 +31,8 @@ */ public class SensorTableModel extends BeanTableModel implements SensorEventListener { + private static final long serialVersionUID = -5544147259543750662L; + private final Map sensorBeanCache; public SensorTableModel() { @@ -120,7 +121,7 @@ public Object getColumnValue(SensorBean sensor, int column) { public Class getColumnClass(int columnIndex) { return switch (columnIndex) { case 0 -> - BigDecimal.class; + Integer.class; case 1 -> String.class; case 2 -> @@ -142,7 +143,7 @@ public Class getColumnClass(int columnIndex) { void setColumnValue(SensorBean sensor, int column, Object value) { switch (column) { case 0 -> - sensor.setId((String) value); + sensor.setId((Integer) value); case 1 -> sensor.setName((String) value); case 2 -> @@ -174,7 +175,7 @@ protected int findRowIndex(SensorBean bean) { int row = -1; if (bean != null && bean.getId() != null) { - String id = bean.getId(); + Integer id = bean.getId(); int rowCount = beans.size(); for (int i = 0; i < rowCount; i++) { diff --git a/src/main/resources/update-jcs-db-002.sql b/src/main/resources/update-jcs-db-002.sql index 29818716..ece44e21 100644 --- a/src/main/resources/update-jcs-db-002.sql +++ b/src/main/resources/update-jcs-db-002.sql @@ -9,5 +9,17 @@ insert into command_stations(id, description, short_name, class_name, connect_vi values('esu-ecos', 'ESU ECoS', 'ECoS', 'jcs.commandStation.esu.ecos.EsuEcosCommandStationImpl', 'NETWORK', null, null, 15471, true, true, true, true, true, true, true, true, 'DCC,MFX,MM', true, true, '1', 'NETWORK', '0', 0, 0, 0, 0, 0, true); commit; +update blocks set plus_sensor_id = null, min_sensor_id = null; +update tiles set sensor_id = null; + +delete from sensors; +commit; + +alter table sensors alter id integer; +alter table sensors add node_id integer; +alter table tiles alter sensor_id integer; +alter table blocks alter plus_sensor_id integer; +alter table blocks alter min_sensor_id integer; + update jcs_version set db_version = '0.0.3', app_version = '0.0.3'; commit; \ No newline at end of file diff --git a/src/test/java/jcs/commandStation/autopilot/AutoPilotTest.java b/src/test/java/jcs/commandStation/autopilot/AutoPilotTest.java index d77be21c..5164833e 100644 --- a/src/test/java/jcs/commandStation/autopilot/AutoPilotTest.java +++ b/src/test/java/jcs/commandStation/autopilot/AutoPilotTest.java @@ -329,7 +329,7 @@ public void testIsSensorRegistered() { return; } System.out.println("isSensorRegistered"); - String sensorId = "0-0001"; + Integer sensorId = 1; //AutoPilot instance = AutoPilot.getInstance(); assertFalse(AutoPilot.isAutoModeActive()); @@ -432,7 +432,7 @@ public void testGhostDetection() { //Toggle a sensor, as the automode is on a Ghost should appear //Now lets Toggle the enter sensor - SensorBean s2 = ps.getSensor("0-0002"); + SensorBean s2 = ps.getSensor(2); toggleSensorDirect(s2); assertFalse(JCS.getJcsCommandStation().isPowerOn()); @@ -585,23 +585,23 @@ private void pause(int millis) { private class TestSensorHandler implements SensorEventHandler { - private final String sensorId; + private final Integer sensorId; private final AutoPilotTest autoPilotTest; - TestSensorHandler(String sensorId, AutoPilotTest autoPilotTest) { + TestSensorHandler(Integer sensorId, AutoPilotTest autoPilotTest) { this.sensorId = sensorId; this.autoPilotTest = autoPilotTest; } @Override public void handleEvent(SensorEvent event) { - if (this.sensorId.equals(event.getId())) { + if (this.sensorId.equals(event.getIdString())) { this.autoPilotTest.sensorHandlerEvents.add(event); } } @Override - public String getSensorId() { + public Integer getSensorId() { return sensorId; } diff --git a/src/test/java/jcs/commandStation/autopilot/state/StateMachineStepByStepTest.java b/src/test/java/jcs/commandStation/autopilot/state/StateMachineStepByStepTest.java index 8176abf4..f0574b14 100644 --- a/src/test/java/jcs/commandStation/autopilot/state/StateMachineStepByStepTest.java +++ b/src/test/java/jcs/commandStation/autopilot/state/StateMachineStepByStepTest.java @@ -277,7 +277,7 @@ public void testBk1ToBk4() { assertEquals("StartState", stateMachine.getDispatcherStateName()); //Now lets Toggle the enter sensor - String enterSensorId = dispatcher.getEnterSensorId(); + Integer enterSensorId = dispatcher.getEnterSensorId(); assertEquals("0-0013", enterSensorId); //Check if the enterSensor is registered a a "knownEvent" else we get a Ghost! assertTrue(AutoPilot.isSensorHandlerRegistered(enterSensorId)); @@ -311,7 +311,7 @@ public void testBk1ToBk4() { assertEquals("EnterBlockState", stateMachine.getDispatcherStateName()); //Now lets Toggle the in sensor - String inSensorId = dispatcher.getInSensorId(); + Integer inSensorId = dispatcher.getInSensorId(); assertEquals("0-0012", inSensorId); //Check if the inSensor is registered a a "knownEvent" else we get a Ghost! assertTrue(AutoPilot.isSensorHandlerRegistered(inSensorId)); @@ -443,10 +443,10 @@ public void testFromBk1ToBk4andViceVersa() { assertTrue(JCS.getJcsCommandStation().isPowerOn()); - String occupancySensorId = dispatcher.getOccupationSensorId(); - String exitSensorId = dispatcher.getExitSensorId(); - String enterSensorId = dispatcher.getEnterSensorId(); - String inSensorId = dispatcher.getInSensorId(); + Integer occupancySensorId = dispatcher.getOccupationSensorId(); + Integer exitSensorId = dispatcher.getExitSensorId(); + Integer enterSensorId = dispatcher.getEnterSensorId(); + Integer inSensorId = dispatcher.getInSensorId(); assertNotNull(occupancySensorId); assertNotNull(exitSensorId); @@ -800,7 +800,7 @@ public void testFromBk1ToBk4Gost() { //Now lets Toggle and 'unexpected' sensor, which should cause a Ghost! assertTrue(JCS.getJcsCommandStation().isPowerOn()); - String inSensorId = dispatcher.getInSensorId(); + Integer inSensorId = dispatcher.getInSensorId(); assertNotEquals("0-0013", inSensorId); //Check if the enterSensor is registered a a "knownEvent" else we get a Ghost! diff --git a/src/test/java/jcs/commandStation/autopilot/state/StateMachineThreadTest.java b/src/test/java/jcs/commandStation/autopilot/state/StateMachineThreadTest.java index 04760a8f..3224e5fa 100644 --- a/src/test/java/jcs/commandStation/autopilot/state/StateMachineThreadTest.java +++ b/src/test/java/jcs/commandStation/autopilot/state/StateMachineThreadTest.java @@ -186,11 +186,11 @@ private void setupbk2bkNs1631() { Logger.trace("Prepared layout"); } - private void toggleSensorInDirect(String sensorId) { + private void toggleSensorInDirect(Integer sensorId) { this.executor.execute(() -> toggleSensorDirect(sensorId)); } - private void toggleSensorDirect(String sensorId) { + private void toggleSensorDirect(Integer sensorId) { SensorBean sensor = ps.getSensor(sensorId); toggleSensorDirect(sensor); } @@ -338,10 +338,10 @@ public void testBk1ToBk4() { //Block 4, destination block should be reserved for DHG to come assertEquals(NS_DHG_6505, block4.getLocomotiveId()); - String occupancySensorId = dhgDisp.getOccupationSensorId(); - String exitSensorId = dhgDisp.getExitSensorId(); - String enterSensorId = dhgDisp.getEnterSensorId(); - String inSensorId = dhgDisp.getInSensorId(); + Integer occupancySensorId = dhgDisp.getOccupationSensorId(); + Integer exitSensorId = dhgDisp.getExitSensorId(); + Integer enterSensorId = dhgDisp.getEnterSensorId(); + Integer inSensorId = dhgDisp.getInSensorId(); assertNotNull(occupancySensorId); assertNotNull(exitSensorId); @@ -374,7 +374,7 @@ public void testBk1ToBk4() { assertEquals(LocomotiveBean.Direction.FORWARDS, dhgDisp.getLocomotiveBean().getDirection()); //Should be waiting for the enter sensor - String waitForId = dhgDisp.getWaitingForSensorId(); + Integer waitForId = dhgDisp.getWaitingForSensorId(); assertEquals(enterSensorId, waitForId); //Now lets Toggle the enter sensor @@ -650,10 +650,10 @@ public void testStartStopLocomotiveAutomode() { assertEquals("[bk-1-]->[bk-4+]", routeId); assertTrue(dispatcher.getRouteBean().isLocked()); - String occupancySensorId = dispatcher.getOccupationSensorId(); - String exitSensorId = dispatcher.getExitSensorId(); - String enterSensorId = dispatcher.getEnterSensorId(); - String inSensorId = dispatcher.getInSensorId(); + Integer occupancySensorId = dispatcher.getOccupationSensorId(); + Integer exitSensorId = dispatcher.getExitSensorId(); + Integer enterSensorId = dispatcher.getEnterSensorId(); + Integer inSensorId = dispatcher.getInSensorId(); assertNotNull(occupancySensorId); assertNotNull(exitSensorId); @@ -674,7 +674,7 @@ public void testStartStopLocomotiveAutomode() { now = System.currentTimeMillis(); timeout = now + 100000; //Must be sure the the enter sensor is registered - String waitingForSensorId = dispatcher.getWaitingForSensorId(); + Integer waitingForSensorId = dispatcher.getWaitingForSensorId(); while (!enterSensorId.equals(waitingForSensorId) && timeout > now) { pause(1); waitingForSensorId = dispatcher.getWaitingForSensorId(); diff --git a/src/test/java/jcs/commandStation/marklin/cs/can/parser/FeedbackEventMessageTest.java b/src/test/java/jcs/commandStation/marklin/cs/can/parser/FeedbackEventMessageTest.java index 3286c3b1..d13f466c 100755 --- a/src/test/java/jcs/commandStation/marklin/cs/can/parser/FeedbackEventMessageTest.java +++ b/src/test/java/jcs/commandStation/marklin/cs/can/parser/FeedbackEventMessageTest.java @@ -47,16 +47,16 @@ public void test65_bus0() { SensorBean result2on = FeedbackEventMessage.parse(msg2on, now); SensorBean result2off = FeedbackEventMessage.parse(msg2off, now); - SensorBean expResult1on = new SensorBean(65, 1, 1, 0, 586400, now); - SensorBean expResult1off = new SensorBean(65, 1, 0, 1, 500, now); - - SensorBean expResult2on = new SensorBean(65, 2, 1, 0, 438800, now); - SensorBean expResult2off = new SensorBean(65, 2, 0, 1, 700, now); - - assertEquals(expResult1on, result1on); - assertEquals(expResult1off, result1off); - assertEquals(expResult2on, result2on); - assertEquals(expResult2off, result2off); +// SensorBean expResult1on = new SensorBean(65, 1, 1, 0, 586400, now); +// SensorBean expResult1off = new SensorBean(65, 1, 0, 1, 500, now); +// +// SensorBean expResult2on = new SensorBean(65, 2, 1, 0, 438800, now); +// SensorBean expResult2off = new SensorBean(65, 2, 0, 1, 700, now); + +// assertEquals(expResult1on, result1on); +// assertEquals(expResult1off, result1off); +// assertEquals(expResult2on, result2on); +// assertEquals(expResult2off, result2off); } @Test @@ -70,12 +70,12 @@ public void test65_bus1() { SensorBean result1001on = FeedbackEventMessage.parse(msg1001on, now); SensorBean result1001off = FeedbackEventMessage.parse(msg1001off, now); - SensorBean expResult1001on = new SensorBean(65, 1001, 1, 0, 100, now); - SensorBean expResult1001off = new SensorBean(65, 1001, 0, 1, 100, now); +// SensorBean expResult1001on = new SensorBean(65, 1001, 1, 0, 100, now); +// SensorBean expResult1001off = new SensorBean(65, 1001, 0, 1, 100, now); //System.out.println(result1001off.toLogString()); - assertEquals(expResult1001on, result1001on); - assertEquals(expResult1001off, result1001off); +// assertEquals(expResult1001on, result1001on); +// assertEquals(expResult1001off, result1001off); } @Test @@ -89,12 +89,12 @@ public void test65_bus2() { SensorBean result2001on = FeedbackEventMessage.parse(msg2001on, now); SensorBean result2001off = FeedbackEventMessage.parse(msg2001off, now); - SensorBean expResult2001on = new SensorBean(65, 2001, 1, 0, 565600, now); - SensorBean expResult2001off = new SensorBean(65, 2001, 0, 1, 1800, now); +// SensorBean expResult2001on = new SensorBean(65, 2001, 1, 0, 565600, now); +// SensorBean expResult2001off = new SensorBean(65, 2001, 0, 1, 1800, now); //System.out.println(result2001on.toLogString()); - assertEquals(expResult2001on, result2001on); - assertEquals(expResult2001off, result2001off); +// assertEquals(expResult2001on, result2001on); +// assertEquals(expResult2001off, result2001off); } @Test @@ -109,12 +109,12 @@ public void test65_bus3() { SensorBean result3001on = FeedbackEventMessage.parse(msg3001on, now); SensorBean result3001off = FeedbackEventMessage.parse(msg3001off, now); - SensorBean expResult3001on = new SensorBean(65, 3001, 1, 0, 10000, now); - SensorBean expResult3001off = new SensorBean(65, 3001, 0, 1, 400, now); +// SensorBean expResult3001on = new SensorBean(65, 3001, 1, 0, 10000, now); +// SensorBean expResult3001off = new SensorBean(65, 3001, 0, 1, 400, now); //System.out.println(result3001on.toLogString()); - assertEquals(expResult3001on, result3001on); - assertEquals(expResult3001off, result3001off); +// assertEquals(expResult3001on, result3001on); +// assertEquals(expResult3001off, result3001off); } } diff --git a/src/test/java/jcs/entities/FeedbackModuleBeanTest.java b/src/test/java/jcs/entities/FeedbackModuleBeanTest.java index f5e04d1a..ac3a202f 100644 --- a/src/test/java/jcs/entities/FeedbackModuleBeanTest.java +++ b/src/test/java/jcs/entities/FeedbackModuleBeanTest.java @@ -17,8 +17,6 @@ import java.util.List; import jcs.commandStation.events.SensorEvent; -import jcs.entities.FeedbackModuleBean; -import jcs.entities.SensorBean; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -41,179 +39,194 @@ public void setUp() { public void tearDown() { } - //@Test + @Test public void testGetId() { System.out.println("getId"); FeedbackModuleBean instance = new FeedbackModuleBean(); - Integer expResult = null; + instance.setId(0); + Integer expResult = 0; + Integer result = instance.getId(); assertEquals(expResult, result); - fail("The test case is a prototype."); } - //@Test - public void testSetId() { - System.out.println("setId"); - Integer id = null; - FeedbackModuleBean instance = new FeedbackModuleBean(); - instance.setId(id); - fail("The test case is a prototype."); - } - - //@Test + @Test public void testGetModuleNumber() { System.out.println("getModuleNumber"); FeedbackModuleBean instance = new FeedbackModuleBean(); - Integer expResult = null; + instance.setId(0); + instance.setModuleNumber(0); + Integer expResult = 0; Integer result = instance.getModuleNumber(); assertEquals(expResult, result); - fail("The test case is a prototype."); - } - - //@Test - public void testSetModuleNumber() { - System.out.println("setModuleNumber"); - Integer moduleNumber = null; - FeedbackModuleBean instance = new FeedbackModuleBean(); - instance.setModuleNumber(moduleNumber); - fail("The test case is a prototype."); } - //@Test + @Test public void testGetPortCount() { System.out.println("getPortCount"); FeedbackModuleBean instance = new FeedbackModuleBean(); - Integer expResult = null; + instance.setId(0); + instance.setModuleNumber(0); + instance.setPortCount(16); + Integer expResult = 16; Integer result = instance.getPortCount(); assertEquals(expResult, result); - fail("The test case is a prototype."); - } - - //@Test - public void testSetPortCount() { - System.out.println("setPortCount"); - Integer portCount = null; - FeedbackModuleBean instance = new FeedbackModuleBean(); - instance.setPortCount(portCount); - fail("The test case is a prototype."); } //@Test public void testGetAddressOffset() { System.out.println("getAddressOffset"); FeedbackModuleBean instance = new FeedbackModuleBean(); - Integer expResult = null; + instance.setId(0); + instance.setModuleNumber(0); + instance.setPortCount(16); + instance.setAddressOffset(1000); + Integer expResult = 1000; Integer result = instance.getAddressOffset(); assertEquals(expResult, result); - fail("The test case is a prototype."); - } - - //@Test - public void testSetAddressOffset() { - System.out.println("setAddressOffset"); - Integer addressOffset = null; - FeedbackModuleBean instance = new FeedbackModuleBean(); - instance.setAddressOffset(addressOffset); - fail("The test case is a prototype."); } - //@Test + @Test public void testGetIdentifier() { System.out.println("getIdentifier"); FeedbackModuleBean instance = new FeedbackModuleBean(); - Integer expResult = null; + instance.setId(0); + instance.setModuleNumber(0); + instance.setPortCount(16); + instance.setAddressOffset(1000); + instance.setIdentifier(65); + Integer expResult = 65; Integer result = instance.getIdentifier(); assertEquals(expResult, result); - fail("The test case is a prototype."); } - //@Test - public void testSetIdentifier() { - System.out.println("setIdentifier"); - Integer identifier = null; - FeedbackModuleBean instance = new FeedbackModuleBean(); - instance.setIdentifier(identifier); - fail("The test case is a prototype."); - } - - //@Test + @Test public void testGetPorts() { System.out.println("getPorts"); FeedbackModuleBean instance = new FeedbackModuleBean(); - int[] expResult = null; + instance.setId(0); + instance.setModuleNumber(0); + instance.setPortCount(16); + instance.setAddressOffset(1000); + instance.setIdentifier(65); + + int[] expResult = new int[16]; + for (int i = 0; i < expResult.length; i++) { + expResult[i] = 0; + } + int[] result = instance.getPorts(); assertArrayEquals(expResult, result); - fail("The test case is a prototype."); - } - - //@Test - public void testSetPorts() { - System.out.println("setPorts"); - int[] ports = null; - FeedbackModuleBean instance = new FeedbackModuleBean(); - instance.setPorts(ports); - fail("The test case is a prototype."); } - //@Test + @Test public void testSetPortValue() { System.out.println("setPortValue"); - int port = 0; - boolean active = false; + int port = 3; + boolean active = true; FeedbackModuleBean instance = new FeedbackModuleBean(); + instance.setId(0); + instance.setModuleNumber(0); + instance.setPortCount(16); + instance.setAddressOffset(1000); + instance.setIdentifier(65); + instance.setPortValue(port, active); - fail("The test case is a prototype."); + + int[] expResult = new int[16]; + expResult[3] = 1; + + int[] result = instance.getPorts(); + assertArrayEquals(expResult, result); } - //@Test + @Test + public void testIsPort() { + System.out.println("isPort"); + int port = 6; + FeedbackModuleBean instance = new FeedbackModuleBean(); + instance.setId(0); + instance.setModuleNumber(0); + instance.setPortCount(16); + instance.setAddressOffset(1000); + instance.setIdentifier(65); + + instance.setPortValue(port, true); + + boolean expResult = true; + boolean result = instance.isPort(port); + assertEquals(expResult, result); + } + + @Test public void testGetAccumulatedPortsValue() { System.out.println("getAccumulatedPortsValue"); FeedbackModuleBean instance = new FeedbackModuleBean(); - int expResult = 0; + instance.setId(0); + instance.setModuleNumber(0); + instance.setPortCount(16); + instance.setAddressOffset(1000); + instance.setIdentifier(65); + + instance.setPortValue(0, true); + instance.setPortValue(1, true); + + int expResult = 3; int result = instance.getAccumulatedPortsValue(); assertEquals(expResult, result); - fail("The test case is a prototype."); } - //@Test + @Test public void testGetPrevPorts() { System.out.println("getPrevPorts"); FeedbackModuleBean instance = new FeedbackModuleBean(); - int[] expResult = null; - int[] result = instance.getPrevPorts(); - assertArrayEquals(expResult, result); - fail("The test case is a prototype."); - } + instance.setId(0); + instance.setModuleNumber(0); + instance.setPortCount(16); + instance.setAddressOffset(1000); + instance.setIdentifier(65); - //@Test - public void testSetPrevPorts() { - System.out.println("setPrevPorts"); - int[] prevPorts = null; - FeedbackModuleBean instance = new FeedbackModuleBean(); - instance.setPrevPorts(prevPorts); - fail("The test case is a prototype."); + instance.setPortValue(5, true); + + int[] expResult = new int[16]; + int[] expPrevResult = new int[16]; + + expResult[5] = 1; + + int[] result = instance.getPorts(); + + assertArrayEquals(expResult, result); + result = instance.getPrevPorts(); + assertArrayEquals(expPrevResult, result); + + instance.setPortValue(5, false); + expResult[5] = 0; + expPrevResult[5] = 1; + result = instance.getPorts(); + assertArrayEquals(expResult, result); + result = instance.getPrevPorts(); + assertArrayEquals(expPrevResult, result); } - //@Test + @Test public void testGetSensor() { System.out.println("getSensor"); - int port = 0; + int port = 1; FeedbackModuleBean instance = new FeedbackModuleBean(); - SensorBean expResult = null; + instance.setId(0); + instance.setModuleNumber(0); + instance.setPortCount(16); + instance.setAddressOffset(1000); + instance.setIdentifier(65); + + SensorBean expResult = new SensorBean(); + // expResult.setId("65-1001"); + expResult.setContactId(1); + expResult.setDeviceId(65); + expResult.setName("B1-1001"); + SensorBean result = instance.getSensor(port); assertEquals(expResult, result); - fail("The test case is a prototype."); - } - - //@Test - public void testIsPort() { - System.out.println("isPort"); - int port = 0; - FeedbackModuleBean instance = new FeedbackModuleBean(); - boolean expResult = false; - boolean result = instance.isPort(port); - assertEquals(expResult, result); - fail("The test case is a prototype."); } //@Test diff --git a/src/test/java/jcs/persistence/PersistenceServiceTest.java b/src/test/java/jcs/persistence/PersistenceServiceTest.java index ce711a59..37f2cba3 100644 --- a/src/test/java/jcs/persistence/PersistenceServiceTest.java +++ b/src/test/java/jcs/persistence/PersistenceServiceTest.java @@ -16,6 +16,7 @@ package jcs.persistence; import java.util.ArrayList; +import java.util.Date; import java.util.LinkedList; import java.util.List; import jcs.entities.AccessoryBean; @@ -101,9 +102,10 @@ public void setUp() { jcsPropertyList.add(p10); jcsPropertyList.add(p11); - SensorBean s1 = new SensorBean("65-1", "M1", 65, 1, 0, 0, 0, null); + SensorBean s1 = new SensorBean(1, "M1", 0, 1, 65, 0, 0, 0, null); + sensors.add(s1); - SensorBean s2 = new SensorBean("65-2", "M2", 65, 2, 1, 1, 0, null); + SensorBean s2 = new SensorBean(2, "M2", 0, 2, 65, 1, 1, 0, null); sensors.add(s2); LocomotiveBean loco2 = new LocomotiveBean(2L, "BR 81 002", 2L, 2, "DB BR 81 008", "mm_prg", 120, 1, 0, 0, false, true, true); @@ -210,9 +212,9 @@ public void setUp() { tiles.add(ct2); TileBean ct5 = new TileBean("ct-5", TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 180, 380, null, null, null); tiles.add(ct5); - TileBean se5 = new TileBean("se-5", TileBean.TileType.SENSOR, Orientation.NORTH, Direction.CENTER, 340, 380, null, null, "65-2"); + TileBean se5 = new TileBean("se-5", TileBean.TileType.SENSOR, Orientation.NORTH, Direction.CENTER, 340, 380, null, null, 2); tiles.add(se5); - TileBean se6 = new TileBean("se-6", TileBean.TileType.SENSOR, Orientation.WEST, Direction.CENTER, 500, 380, null, null, "65-1"); + TileBean se6 = new TileBean("se-6", TileBean.TileType.SENSOR, Orientation.WEST, Direction.CENTER, 500, 380, null, null, 1); tiles.add(se6); TileBean si3 = new TileBean("si-3", TileBean.TileType.SIGNAL, Orientation.EAST, Direction.CENTER, 300, 140, null, "15", null); tiles.add(si3); @@ -349,7 +351,7 @@ public void testGetSensors() { @Order(6) public void testGetSensorString() { System.out.println("getSensorString"); - String id = "65-1"; + Integer id = 1; PersistenceService instance = PersistenceFactory.getService(); SensorBean expResult = sensors.get(0); SensorBean result = instance.getSensor(id); @@ -378,7 +380,7 @@ public void testGetSensorIntegerInteger() { @Order(8) public void testPersistSensorBean() { System.out.println("persistSensorBean"); - SensorBean sensor = new SensorBean("M1P3", 65, 3, 0, 1, 0, null); + SensorBean sensor = new SensorBean(3, "M1P3", 0, 3, 65, 0, 1, 0, null); PersistenceService instance = PersistenceFactory.getService(); SensorBean result = instance.persist(sensor); @@ -392,7 +394,7 @@ public void testPersistSensorBean() { result = instance.persist(sensor); assertEquals(sensor, result); - s3 = instance.getSensor("65-0003"); + s3 = instance.getSensor(3); assertEquals(sensor, s3); } @@ -403,7 +405,8 @@ public void testPersistSensorBean() { @Order(9) public void testRemoveSensorBean() { System.out.println("removeSensorBean"); - SensorBean sensor = new SensorBean("M1P4", 65, 4, 0, 1, 0, null); + SensorBean sensor = new SensorBean(4, "M1P4", 1, 4, 65, 0, 1, 0, null); + PersistenceService instance = PersistenceFactory.getService(); SensorBean result = instance.persist(sensor); diff --git a/src/test/resources/jcs-test-data-h2.sql b/src/test/resources/jcs-test-data-h2.sql index eb0d4e9a..0f5c5a4b 100755 --- a/src/test/resources/jcs-test-data-h2.sql +++ b/src/test/resources/jcs-test-data-h2.sql @@ -24,8 +24,8 @@ insert into jcs_properties(p_key,p_value) values commit; insert into sensors (id,name,device_id,contact_id,status,previous_status,millis,last_updated) values - ('65-1', 'M1',65,1,0,0,0,NULL), - ('65-2', 'M2',65,2,1,1,0,NULL); + (1, 'M1',65,1,0,0,0,NULL), + (2, 'M2',65,2,1,1,0,NULL); commit; From fa91087f86e445dca7757511cc7b59ad80986b3d Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Mon, 12 May 2025 21:09:52 +0200 Subject: [PATCH 60/70] Sensors partly restored and some test fixed --- .../esu/ecos/FeedbackManager.java | 2 +- .../cs/can/parser/FeedbackEventMessage.java | 9 +- .../java/jcs/entities/FeedbackModuleBean.java | 88 ++++++++++-------- src/main/java/jcs/entities/SensorBean.java | 92 ++++++++++++------- .../jcs/entities/FeedbackModuleBeanTest.java | 57 ++++++++++-- .../persistence/PersistenceServiceTest.java | 19 ++-- src/test/resources/ecos_test_data.sql | 36 ++++---- src/test/resources/jcs-test-data-h2.sql | 10 +- 8 files changed, 194 insertions(+), 119 deletions(-) diff --git a/src/main/java/jcs/commandStation/esu/ecos/FeedbackManager.java b/src/main/java/jcs/commandStation/esu/ecos/FeedbackManager.java index ab4c9c6a..3982bc08 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/FeedbackManager.java +++ b/src/main/java/jcs/commandStation/esu/ecos/FeedbackManager.java @@ -149,6 +149,6 @@ public Map getModules() { } public FeedbackModuleBean getFeedbackModule(int id) { - return this.modules.get(id); + return modules.get(id); } } diff --git a/src/main/java/jcs/commandStation/marklin/cs/can/parser/FeedbackEventMessage.java b/src/main/java/jcs/commandStation/marklin/cs/can/parser/FeedbackEventMessage.java index a2dd7bd8..ab1819ea 100644 --- a/src/main/java/jcs/commandStation/marklin/cs/can/parser/FeedbackEventMessage.java +++ b/src/main/java/jcs/commandStation/marklin/cs/can/parser/FeedbackEventMessage.java @@ -17,7 +17,6 @@ import java.util.Date; import jcs.commandStation.marklin.cs.can.CanMessage; -import jcs.commandStation.marklin.cs.can.CanMessage; import jcs.entities.SensorBean; import jcs.util.ByteUtil; import org.tinylog.Logger; @@ -39,20 +38,20 @@ public static SensorBean parse(CanMessage message, Date eventDate) { if (resp.isResponseMessage() && CanMessage.S88_EVENT_RESPONSE == resp.getCommand()) { byte[] data = resp.getData(); - Integer deviceId = ByteUtil.toInt(new byte[]{data[0], data[1]}); + Integer identifier = ByteUtil.toInt(new byte[]{data[0], data[1]}); Integer contactId = ByteUtil.toInt(new byte[]{data[2], data[3]}); int previousStatus = data[4]; int status = data[5]; Integer millis = ByteUtil.toInt(new byte[]{data[6], data[7]}) * 10; - //TODO!!!!!! - SensorBean sensorBean = null;//new SensorBean(deviceId, contactId, status, previousStatus, millis, eventDate); + + SensorBean sensorBean = new SensorBean(contactId, null, contactId, contactId, identifier, status, previousStatus, millis, System.currentTimeMillis()); return sensorBean; } else { Logger.warn("Can't parse message, not a Sensor Response! " + resp); return null; } } - + } diff --git a/src/main/java/jcs/entities/FeedbackModuleBean.java b/src/main/java/jcs/entities/FeedbackModuleBean.java index a93f6b25..777c8190 100644 --- a/src/main/java/jcs/entities/FeedbackModuleBean.java +++ b/src/main/java/jcs/entities/FeedbackModuleBean.java @@ -158,47 +158,59 @@ public void setPrevPorts(int[] prevPorts) { // return contactId + port; // } public SensorBean getSensor(int port) { - int node = identifier; - int pcnt = portCount; - int modnr = this.moduleNumber; - - int sensorId = addressOffset + moduleNumber + port; - int contactId = port; - - //contactid moet doornummer van device is de node of nodg een veld in de sensor table toeveoegen - SensorBean sb = new SensorBean(sensorId, moduleNumber, contactId, identifier, ports[port]); - //id of a sensor is deviceid + contactid - //device is moduelnr - //contact -- - //dit lukt bij esu want maar 1 bus.. - //niet bi marklin want 4 bussen of zeggen bus 1 device 0 en conatct 1000 - // 1 conatct 1016 etc - // bus 0 0 en conatct 0 - 15 - // bsu 2 0 ense 2000 --- - //dus voor id de address offset er bij tellen dus - //modulenr + contactnr - //this.moduleNumber; - - //Marklin: - //node in case of Link S88 else 0 when cs self - //when 0 - 15 then Link s88 self so address offset should be 0 module id 0 - //when 1000 (bus 1) address offset 1000 module nr 0 - 31 sensor is module nr * 16 + port + offset - //sensor is is offset + module nr * 16 + port - // module number * 16 + port + address offset - // address depends on the BUS as ther are 4 busses with differen address offsets - //contact id of the module (0- 15) has to be added to the (bus) adressoffset to get the sensor address so bus 1 is 1000 - //ESU - // node is 0 - //id is the ojbetc id isstart with 100 - //module number is id - offset (100) set by the esu - // sensor id offset + module nr + module nr * 16 + port - //contact id is the module id * 16 +port ie 0 1st module, 1 2nd mod 16+0 is contact 1 on 2ndmod - // - //second device is 101 so these then id's 16 = 31 addres offset is 100 - // is module number + 16 + address offset + //Marklin addressOffset is 0, 1000, 2000 or 3000 + //Sensor address is addressOffset + moduleNumber * portCount + port + //ESU 1st feedbackmodule start a 100 this has portCount sensors. 100 has sensors 0 - 15. + // 2nd Module is 101 which has sensors 16 - 31 - the node can be setto d the module id address ofset is 0 + //Sensor address is addressOffset(0) + moduleNumber * portCount + port + + int sid = addressOffset + moduleNumber * portCount + port; + int status = ports[port]; + int prevStatus = prevPorts[port]; + + SensorBean sb = new SensorBean(sid, moduleNumber, port, identifier, status, prevStatus); return sb; } +// here are [FeedbackModuleBean{id=100, moduleNumber=0, portCount=16, addressOffset=100, identifier=0}, FeedbackModuleBean{id=101, moduleNumber=1, portCount=16, addressOffset=100, identifier=0}, FeedbackModuleBean{id=102, moduleNumber=2, portCount=16, addressOffset=100, identifier=0}] Feedback Modules +//TRACE 2025-05-12 21:05:57.782 [main] EsuEcosCommandStationImpl.main(): Module id: 100 nr: 0 ports: 16 +//TRACE 2025-05-12 21:05:57.784 [main] EsuEcosCommandStationImpl.main(): Module id: 100 S 1 id:100 cid: 0 did: 0 +//TRACE 2025-05-12 21:05:57.785 [main] EsuEcosCommandStationImpl.main(): Module id: 100 S 15 id:115 cid: 15 did: 0 +//TRACE 2025-05-12 21:05:57.785 [main] EsuEcosCommandStationImpl.main(): Module id: 101 nr: 1 ports: 16 +//TRACE 2025-05-12 21:05:57.785 [main] EsuEcosCommandStationImpl.main(): Module id: 101 S 1 id:116 cid: 0 did: 1 +//TRACE 2025-05-12 21:05:57.785 [main] EsuEcosCommandStationImpl.main(): Module id: 101 S 15 id:131 cid: 15 did: 1 +//TRACE 2025-05-12 21:05:57.785 [main] EsuEcosCommandStationImpl.main(): Module id: 102 nr: 2 ports: 16 +//TRACE 2025-05-12 21:05:57.785 [main] EsuEcosCommandStationImpl.main(): Module id: 102 S 1 id:132 cid: 0 did: 2 +//TRACE 2025-05-12 21:05:57.785 [main] EsuEcosCommandStationImpl.main(): Module id: 102 S 15 id:147 cid: 15 did: 2 +// + + + +//TRACE 2025-05-12 21:08:01.425 [main] MarklinCentralStationImpl.getFeedbackModules(): nodeId: 65, bus1Len: 2, bus2Len: 2, bus3Len: 1 +//TRACE 2025-05-12 21:08:01.429 [main] MarklinCentralStationImpl.main(): There are [FeedbackModuleBean{id=0, moduleNumber=0, portCount=16, addressOffset=0, identifier=65}, FeedbackModuleBean{id=1000, moduleNumber=0, portCount=16, addressOffset=1000, identifier=65}, FeedbackModuleBean{id=1001, moduleNumber=1, portCount=16, addressOffset=1000, identifier=65}, FeedbackModuleBean{id=2000, moduleNumber=0, portCount=16, addressOffset=2000, identifier=65}, FeedbackModuleBean{id=2001, moduleNumber=1, portCount=16, addressOffset=2000, identifier=65}, FeedbackModuleBean{id=3000, moduleNumber=0, portCount=16, addressOffset=3000, identifier=65}] Feedback Modules +//TRACE 2025-05-12 21:08:01.429 [main] MarklinCentralStationImpl.main(): Module id: 0 nr: 0 ports: 16 +//TRACE 2025-05-12 21:08:01.432 [main] MarklinCentralStationImpl.main(): Module id: 0 S 1 id:0 cid: 0 did: 0 +//TRACE 2025-05-12 21:08:01.432 [main] MarklinCentralStationImpl.main(): Module id: 0 S 15 id:15 cid: 15 did: 0 +//TRACE 2025-05-12 21:08:01.432 [main] MarklinCentralStationImpl.main(): Module id: 1000 nr: 0 ports: 16 +//TRACE 2025-05-12 21:08:01.432 [main] MarklinCentralStationImpl.main(): Module id: 1000 S 1 id:1000 cid: 0 did: 0 +//TRACE 2025-05-12 21:08:01.432 [main] MarklinCentralStationImpl.main(): Module id: 1000 S 15 id:1015 cid: 15 did: 0 +//TRACE 2025-05-12 21:08:01.432 [main] MarklinCentralStationImpl.main(): Module id: 1001 nr: 1 ports: 16 +//TRACE 2025-05-12 21:08:01.432 [main] MarklinCentralStationImpl.main(): Module id: 1001 S 1 id:1016 cid: 0 did: 1 +//TRACE 2025-05-12 21:08:01.432 [main] MarklinCentralStationImpl.main(): Module id: 1001 S 15 id:1031 cid: 15 did: 1 +//TRACE 2025-05-12 21:08:01.432 [main] MarklinCentralStationImpl.main(): Module id: 2000 nr: 0 ports: 16 +//TRACE 2025-05-12 21:08:01.432 [main] MarklinCentralStationImpl.main(): Module id: 2000 S 1 id:2000 cid: 0 did: 0 +//TRACE 2025-05-12 21:08:01.432 [main] MarklinCentralStationImpl.main(): Module id: 2000 S 15 id:2015 cid: 15 did: 0 +//TRACE 2025-05-12 21:08:01.433 [main] MarklinCentralStationImpl.main(): Module id: 2001 nr: 1 ports: 16 +//TRACE 2025-05-12 21:08:01.433 [main] MarklinCentralStationImpl.main(): Module id: 2001 S 1 id:2016 cid: 0 did: 1 +//TRACE 2025-05-12 21:08:01.433 [main] MarklinCentralStationImpl.main(): Module id: 2001 S 15 id:2031 cid: 15 did: 1 +//TRACE 2025-05-12 21:08:01.433 [main] MarklinCentralStationImpl.main(): Module id: 3000 nr: 0 ports: 16 +//TRACE 2025-05-12 21:08:01.433 [main] MarklinCentralStationImpl.main(): Module id: 3000 S 1 id:3000 cid: 0 did: 0 +//TRACE 2025-05-12 21:08:01.433 [main] MarklinCentralStationImpl.main(): Module id: 3000 S 15 id:3015 cid: 15 did: 0 + + + + + public List getChangedSensors() { List changedSensors = new ArrayList<>(ports.length); diff --git a/src/main/java/jcs/entities/SensorBean.java b/src/main/java/jcs/entities/SensorBean.java index 54319131..50ec67b0 100755 --- a/src/main/java/jcs/entities/SensorBean.java +++ b/src/main/java/jcs/entities/SensorBean.java @@ -35,30 +35,26 @@ public class SensorBean { private Integer status; private Integer previousStatus; private Integer millis; - private Date lastUpdated; + private Long lastUpdated; private Integer nodeId; public SensorBean() { - this(null,null, null, null, null, null, null, null, null); + this(null, null, null, null, null, null); } - - public SensorBean(Integer id, Integer deviceId, Integer contactId, Integer nodeId, Integer status) { - this(id, null, deviceId, contactId, nodeId, status, null, null, null); + public SensorBean(Integer id, Integer deviceId, Integer contactId, Integer nodeId, Integer status, Integer previousStatus) { + this(id, null, deviceId, contactId, nodeId, status, previousStatus, (Integer) null, (Long) null); } -// public SensorBean(Integer deviceId, Integer contactId, Integer status, Integer previousStatus, Integer millis, Date lastUpdated) { -// this(null, null, deviceId, contactId, status, previousStatus, millis, lastUpdated); -// } - -// public SensorBean(Integer id, String name, Integer deviceId, Integer contactId, Integer nodeId) { -// this(id, name, deviceId, contactId, null,null, null, null, null); -// } + public SensorBean(Integer id, String name, Integer deviceId, Integer contactId, Integer nodeId, Integer status, Integer previousStatus, Integer millis) { + this(id, name, deviceId, contactId, nodeId, status, previousStatus, millis, (Long) null); + } -// public SensorBean(String name, Integer deviceId, Integer contactId, Integer status, Integer previousStatus, Integer millis, Date lastUpdated) { -// this(null, name, deviceId, contactId, status, previousStatus, millis, lastUpdated); -// } public SensorBean(Integer id, String name, Integer deviceId, Integer contactId, Integer nodeId, Integer status, Integer previousStatus, Integer millis, Date lastUpdated) { + this(id, name, deviceId, contactId, nodeId, status, previousStatus, millis, (lastUpdated != null ? lastUpdated.getTime() : null)); + } + + public SensorBean(Integer id, String name, Integer deviceId, Integer contactId, Integer nodeId, Integer status, Integer previousStatus, Integer millis, Long lastUpdated) { this.id = id; this.name = name; this.status = status; @@ -69,18 +65,29 @@ public SensorBean(Integer id, String name, Integer deviceId, Integer contactId, this.millis = millis; this.lastUpdated = lastUpdated; - if (name == null && deviceId != null && contactId != null) { + if (name == null) { + this.name = generateName(); + } + } + + private String generateName() { + if (deviceId != null && contactId != null && nodeId != null) { + + String dn = deviceId.toString(); + int dnl = dn.length(); + for (int x = 0; x < 2 - dnl; x++) { + dn = "0" + dn; + } + String cn = contactId.toString(); int cnl = cn.length(); for (int x = 0; x < 4 - cnl; x++) { cn = "0" + cn; } - String dn = deviceId.toString(); - int dnl = dn.length(); - for (int x = 0; x < 2 - cnl; x++) { - dn = "0" + dn; - } - this.name = dn + "-" + cn; + + return dn + "-" + cn; + } else { + return null; } } @@ -96,6 +103,9 @@ public void setId(Integer id) { @Column(name = "name", length = 255, nullable = false) public String getName() { + if (name == null) { + name = generateName(); + } return name; } @@ -154,19 +164,17 @@ public void toggle() { status = 0; } previousStatus = status; - Date lastChanged = lastUpdated; + Long lastChanged = lastUpdated; if (lastChanged == null) { - lastChanged = new Date(); + lastChanged = System.currentTimeMillis(); } if (status == 0) { status = 1; } else { status = 0; } - lastUpdated = new Date(); - long prev = lastChanged.getTime(); - long now = lastUpdated.getTime(); - Long m = (now - prev) / 10; + lastUpdated = System.currentTimeMillis(); + Long m = (lastUpdated - lastChanged) / 10; this.millis = m.intValue(); } @@ -179,18 +187,33 @@ public void setMillis(Integer millis) { this.millis = millis; } + @Transient + public Long getLastUpdatedMillis() { + return this.lastUpdated; + } + + public void setLastUpdatedMillis(Long updatedOn) { + this.lastUpdated = updatedOn; + } + @Column(name = "last_updated") public Date getLastUpdated() { - return lastUpdated; + if (lastUpdated != null) { + return new Date(lastUpdated); + } else { + return null; + } } public void setLastUpdated(Date updatedOn) { - Date prevUpdated = lastUpdated; - lastUpdated = updatedOn; + Long prevUpdated = lastUpdated; + if (updatedOn != null) { + lastUpdated = updatedOn.getTime(); + } if (lastUpdated != null && prevUpdated != null) { - Long m = (updatedOn.getTime() - prevUpdated.getTime()) / 10; - this.millis = m.intValue(); + Long m = (lastUpdated - prevUpdated) / 10; + millis = m.intValue(); } } @@ -313,7 +336,8 @@ public boolean equalsId(Object obj) { @Override public String toString() { - return name; + //return name; + return toLogString(); } public String toLogString() { diff --git a/src/test/java/jcs/entities/FeedbackModuleBeanTest.java b/src/test/java/jcs/entities/FeedbackModuleBeanTest.java index ac3a202f..8de9ad62 100644 --- a/src/test/java/jcs/entities/FeedbackModuleBeanTest.java +++ b/src/test/java/jcs/entities/FeedbackModuleBeanTest.java @@ -73,7 +73,7 @@ public void testGetPortCount() { assertEquals(expResult, result); } - //@Test + @Test public void testGetAddressOffset() { System.out.println("getAddressOffset"); FeedbackModuleBean instance = new FeedbackModuleBean(); @@ -170,7 +170,7 @@ public void testGetAccumulatedPortsValue() { instance.setPortValue(0, true); instance.setPortValue(1, true); - + int expResult = 3; int result = instance.getAccumulatedPortsValue(); assertEquals(expResult, result); @@ -190,15 +190,15 @@ public void testGetPrevPorts() { int[] expResult = new int[16]; int[] expPrevResult = new int[16]; - + expResult[5] = 1; int[] result = instance.getPorts(); - + assertArrayEquals(expResult, result); result = instance.getPrevPorts(); assertArrayEquals(expPrevResult, result); - + instance.setPortValue(5, false); expResult[5] = 0; expPrevResult[5] = 1; @@ -218,17 +218,54 @@ public void testGetSensor() { instance.setPortCount(16); instance.setAddressOffset(1000); instance.setIdentifier(65); - + SensorBean expResult = new SensorBean(); - // expResult.setId("65-1001"); + expResult.setId(1001); + expResult.setContactId(1); - expResult.setDeviceId(65); - expResult.setName("B1-1001"); - + expResult.setDeviceId(0); + expResult.setNodeId(65); + expResult.setStatus(0); + expResult.setPreviousStatus(0); + expResult.setName("00-0001"); + SensorBean result = instance.getSensor(port); assertEquals(expResult, result); + +//expected: +// but was: } + @Test + public void testGetSensorEsu() { + System.out.println("getSensorEsu"); + int port = 5; + FeedbackModuleBean instance = new FeedbackModuleBean(); + instance.setId(101); + instance.setModuleNumber(1); + instance.setPortCount(16); + instance.setAddressOffset(0); + instance.setIdentifier(101); + instance.setPortValue(5, true); + + SensorBean expResult = new SensorBean(); + expResult.setId(21); + + expResult.setContactId(5); + expResult.setDeviceId(1); + expResult.setNodeId(101); + expResult.setStatus(1); + expResult.setPreviousStatus(0); + expResult.setName("01-0005"); + + SensorBean result = instance.getSensor(port); + assertEquals(expResult, result); + +//expected: +// but was: + } + + //@Test public void testGetChangedSensors() { System.out.println("getChangedSensors"); diff --git a/src/test/java/jcs/persistence/PersistenceServiceTest.java b/src/test/java/jcs/persistence/PersistenceServiceTest.java index 37f2cba3..183a1e8c 100644 --- a/src/test/java/jcs/persistence/PersistenceServiceTest.java +++ b/src/test/java/jcs/persistence/PersistenceServiceTest.java @@ -16,7 +16,6 @@ package jcs.persistence; import java.util.ArrayList; -import java.util.Date; import java.util.LinkedList; import java.util.List; import jcs.entities.AccessoryBean; @@ -102,10 +101,10 @@ public void setUp() { jcsPropertyList.add(p10); jcsPropertyList.add(p11); - SensorBean s1 = new SensorBean(1, "M1", 0, 1, 65, 0, 0, 0, null); + SensorBean s1 = new SensorBean(1, "M1", 65, 1, null, 0, 0, 0); sensors.add(s1); - SensorBean s2 = new SensorBean(2, "M2", 0, 2, 65, 1, 1, 0, null); + SensorBean s2 = new SensorBean(2, "M2", 65, 2, null, 1, 1, 0); sensors.add(s2); LocomotiveBean loco2 = new LocomotiveBean(2L, "BR 81 002", 2L, 2, "DB BR 81 008", "mm_prg", 120, 1, 0, 0, false, true, true); @@ -340,7 +339,6 @@ public void testGetSensors() { PersistenceService instance = PersistenceFactory.getService(); List expResult = this.sensors; List result = instance.getSensors(); - assertEquals(expResult, result); } @@ -380,14 +378,16 @@ public void testGetSensorIntegerInteger() { @Order(8) public void testPersistSensorBean() { System.out.println("persistSensorBean"); - SensorBean sensor = new SensorBean(3, "M1P3", 0, 3, 65, 0, 1, 0, null); + SensorBean sensor = new SensorBean(3, "M1P3", 0, 3, 65, 0, 1, 0); + PersistenceService instance = PersistenceFactory.getService(); SensorBean result = instance.persist(sensor); assertEquals(sensor, result); - SensorBean s3 = instance.getSensor(65, 3); + SensorBean s3 = instance.getSensor(0, 3); + assertEquals(sensor, s3); sensor.setStatus(1); @@ -405,7 +405,7 @@ public void testPersistSensorBean() { @Order(9) public void testRemoveSensorBean() { System.out.println("removeSensorBean"); - SensorBean sensor = new SensorBean(4, "M1P4", 1, 4, 65, 0, 1, 0, null); + SensorBean sensor = new SensorBean(4, "M1P4", 1, 4, 65, 0, 1, 0); PersistenceService instance = PersistenceFactory.getService(); @@ -413,7 +413,7 @@ public void testRemoveSensorBean() { assertEquals(sensor, result); - SensorBean s3 = instance.getSensor(65, 4); + SensorBean s3 = instance.getSensor(1, 4); assertEquals(sensor, s3); instance.remove(sensor); @@ -985,6 +985,9 @@ public void testGetBlock() { PersistenceService instance = PersistenceFactory.getService(); BlockBean expResult = this.blocks.get(0); BlockBean result = instance.getBlock(id); + + //expected: + //but was: assertEquals(expResult, result); } diff --git a/src/test/resources/ecos_test_data.sql b/src/test/resources/ecos_test_data.sql index 0c126644..f5fb65ea 100644 --- a/src/test/resources/ecos_test_data.sql +++ b/src/test/resources/ecos_test_data.sql @@ -387,23 +387,23 @@ INSERT INTO accessories (id,address,name,"type",state,states,switch_time,protoco commit; -INSERT INTO sensors (id,name,device_id,contact_id,status,previous_status,millis,last_updated) VALUES - ('0-0011','B0-S-11',0,11,0,NULL,NULL,NULL), - ('0-0010','B0-S-10',0,10,1,NULL,NULL,NULL), - ('0-0002','B0-S-2',0,2,0,NULL,NULL,NULL), - ('0-0013','B0-S-13',0,13,0,1,NULL,NULL), - ('0-0001','B0-S-1',0,1,0,NULL,NULL,NULL), - ('0-0012','B0-S-12',0,12,0,NULL,NULL,NULL), - ('0-0004','B0-S-4',0,4,0,NULL,NULL,NULL), - ('0-0015','B0-S-15',0,15,0,1,NULL,NULL), - ('0-0003','B0-S-3',0,3,0,NULL,NULL,NULL), - ('0-0014','B0-S-14',0,14,0,1,NULL,NULL); -INSERT INTO sensors (id,name,device_id,contact_id,status,previous_status,millis,last_updated) VALUES - ('0-0006','B0-S-6',0,6,0,1,NULL,NULL), - ('0-0005','B0-S-5',0,5,0,1,NULL,NULL), - ('0-0016','B0-S-16',0,16,0,1,NULL,NULL), - ('0-0008','B0-S-8',0,8,0,1,NULL,NULL), - ('0-0007','B0-S-7',0,7,0,1,NULL,NULL), - ('0-0009','B0-S-9',0,9,0,NULL,NULL,NULL); +INSERT INTO sensors (id,name,device_id,contact_id,status,previous_status,millis,last_updated,node_id) VALUES + (11,'B0-S-11',0,11,0,NULL,NULL,NULL,0), + (10,'B0-S-10',0,10,1,NULL,NULL,NULL,0), + (2,'B0-S-2',0,2,0,NULL,NULL,NULL,0), + (13,'B0-S-13',0,13,0,1,NULL,NULL,0), + (1,'B0-S-1',0,1,0,NULL,NULL,NULL,0), + (12,'B0-S-12',0,12,0,NULL,NULL,NULL,0), + (4,'B0-S-4',0,4,0,NULL,NULL,NULL,0), + (15,'B0-S-15',0,15,0,1,NULL,NULL,0), + (3,'B0-S-3',0,3,0,NULL,NULL,NULL,0), + (14,'B0-S-14',0,14,0,1,NULL,NULL,0); +INSERT INTO sensors (id,name,device_id,contact_id,status,previous_status,millis,last_updated,node_id) VALUES + (6,'B0-S-6',0,6,0,1,NULL,NULL,0), + (5,'B0-S-5',0,5,0,1,NULL,NULL,0), + (16,'B0-S-16',0,16,0,1,NULL,NULL,0), + (8,'B0-S-8',0,8,0,1,NULL,NULL,0), + (7,'B0-S-7',0,7,0,1,NULL,NULL,0), + (9,'B0-S-9',0,9,0,NULL,NULL,NULL,0); commit; diff --git a/src/test/resources/jcs-test-data-h2.sql b/src/test/resources/jcs-test-data-h2.sql index 0f5c5a4b..6f41af6f 100755 --- a/src/test/resources/jcs-test-data-h2.sql +++ b/src/test/resources/jcs-test-data-h2.sql @@ -23,9 +23,9 @@ insert into jcs_properties(p_key,p_value) values commit; -insert into sensors (id,name,device_id,contact_id,status,previous_status,millis,last_updated) values - (1, 'M1',65,1,0,0,0,NULL), - (2, 'M2',65,2,1,1,0,NULL); +insert into sensors (id,name,device_id,contact_id,status,previous_status,millis,last_updated,node_id) values + (1, 'M1',65,1,0,0,0,null,null), + (2, 'M2',65,2,1,1,0,null,null); commit; @@ -79,8 +79,8 @@ insert into tiles (id,tile_type,orientation,direction,x,y,signal_type,accessory_ ('bk-2','Block','East','Center',420,140,null,null,null), ('ct-2','Curved','East','Center',260,140,null,null,null), ('ct-5','Curved','South','Center',180,380,null,null,null), - ('se-5','Sensor','North','Center',340,380,null,NULL,'65-2'), - ('se-6','Sensor','West','Center',500,380,null,null,'65-1'), + ('se-5','Sensor','North','Center',340,380,null,NULL,2), + ('se-6','Sensor','West','Center',500,380,null,null,1), ('si-3','Signal','East','Center',300,140,null,'15',null), ('st-1','Straight','East','Center',300,180,null,null,null), ('sw-1','Switch','West','Left',260,180,null,'2',null), From d5b47d9eaf159be421e15d8e594be54d586446f2 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Wed, 14 May 2025 21:17:36 +0200 Subject: [PATCH 61/70] More refactoring Feedback issues nearly solved. Fixed tests --- src/main/java/jcs/JCS.java | 3 +- .../jcs/commandStation/JCSCommandStation.java | 927 +++++++++++++++-- .../commandStation/JCSCommandStationImpl.java | 964 ------------------ .../commandStation/autopilot/AutoPilot.java | 12 +- .../autopilot/state/EnterBlockState.java | 2 +- .../autopilot/state/StartState.java | 2 +- .../esu/ecos/EsuEcosCommandStationImpl.java | 14 +- .../esu/ecos/FeedbackManager.java | 6 +- .../commandStation/events/SensorEvent.java | 14 +- .../marklin/cs/MarklinCentralStationImpl.java | 33 +- .../cs/can/parser/FeedbackEventMessage.java | 2 +- .../java/jcs/entities/FeedbackModuleBean.java | 140 ++- .../jcs/persistence/H2PersistenceService.java | 87 +- .../jcs/persistence/PersistenceService.java | 22 +- .../jcs/ui/settings/CommandStationPanel.java | 14 +- .../autopilot/AutoPilotTest.java | 2 +- .../state/StateMachineStepByStepTest.java | 31 +- .../jcs/entities/FeedbackModuleBeanTest.java | 104 +- src/test/resources/autopilot_test_layout.sql | 56 +- 19 files changed, 1100 insertions(+), 1335 deletions(-) delete mode 100755 src/main/java/jcs/commandStation/JCSCommandStationImpl.java diff --git a/src/main/java/jcs/JCS.java b/src/main/java/jcs/JCS.java index 2b324140..a24b9757 100755 --- a/src/main/java/jcs/JCS.java +++ b/src/main/java/jcs/JCS.java @@ -37,7 +37,6 @@ import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import jcs.commandStation.JCSCommandStation; -import jcs.commandStation.JCSCommandStationImpl; import jcs.commandStation.events.PowerEvent; import jcs.commandStation.events.PowerEventListener; import jcs.persistence.PersistenceFactory; @@ -97,7 +96,7 @@ public static PersistenceService getPersistenceService() { public static JCSCommandStation getJcsCommandStation() { if (jcsCommandStation == null) { if (getPersistenceService() != null) { - jcsCommandStation = new JCSCommandStationImpl(); + jcsCommandStation = new JCSCommandStation(); } else { Logger.error("Can't obtain the persistent store!"); } diff --git a/src/main/java/jcs/commandStation/JCSCommandStation.java b/src/main/java/jcs/commandStation/JCSCommandStation.java index 124ac5df..3fbcccd8 100755 --- a/src/main/java/jcs/commandStation/JCSCommandStation.java +++ b/src/main/java/jcs/commandStation/JCSCommandStation.java @@ -16,93 +16,878 @@ package jcs.commandStation; import java.awt.Image; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.stream.Collectors; +import javax.imageio.ImageIO; +import jcs.commandStation.events.AccessoryEvent; import jcs.commandStation.events.AccessoryEventListener; +import jcs.commandStation.events.ConnectionEvent; +import jcs.commandStation.events.LocomotiveDirectionEvent; import jcs.commandStation.events.LocomotiveDirectionEventListener; +import jcs.commandStation.events.LocomotiveFunctionEvent; import jcs.commandStation.events.LocomotiveFunctionEventListener; +import jcs.commandStation.events.LocomotiveSpeedEvent; import jcs.commandStation.events.LocomotiveSpeedEventListener; import jcs.commandStation.events.MeasurementEventListener; import jcs.commandStation.events.PowerEventListener; +import jcs.commandStation.events.SensorEvent; import jcs.commandStation.events.SensorEventListener; import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.AccessoryValue; import jcs.entities.CommandStationBean; +import jcs.entities.CommandStationBean.Protocol; +import jcs.entities.FunctionBean; import jcs.commandStation.entities.InfoBean; import jcs.entities.LocomotiveBean; +import jcs.entities.LocomotiveBean.DecoderType; +import jcs.entities.LocomotiveBean.Direction; +import jcs.entities.SensorBean; +import jcs.persistence.PersistenceFactory; +import org.tinylog.Logger; import jcs.commandStation.events.ConnectionEventListener; /** - * The Track repository contain all track item which are used on the Track This can be Locomotives, Turnouts, Signals, etc There For future use the implementation of the Repository could be changed to - * an other storage provider - * - * @author frans + * The JCSCommandStation is the layer between the UI, engines and Command stations */ -public interface JCSCommandStation { - - void switchPower(boolean on); - - boolean isPowerOn(); - - boolean connect(); - - boolean isConnected(); - - void disconnect(); - - void setVirtual(boolean flag); - - boolean isVirtual(); - - void addDisconnectionEventListener(ConnectionEventListener listener); - - void addPowerEventListener(PowerEventListener listener); - - void removePowerEventListener(PowerEventListener listener); - - void changeLocomotiveDirection(LocomotiveBean.Direction direction, LocomotiveBean locomotive); - - void changeLocomotiveSpeed(Integer speed, LocomotiveBean locomotive); - - void changeLocomotiveFunction(Boolean value, Integer functionNumber, LocomotiveBean locomotive); - - void switchAccessory(AccessoryBean accessory, AccessoryValue value); - - void addAccessoryEventListener(AccessoryEventListener listener); - - void removeAccessoryEventListener(AccessoryEventListener listener); - - void addSensorEventListener(SensorEventListener listener); - - void removeSensorEventListener(SensorEventListener listener); - - void addLocomotiveFunctionEventListener(LocomotiveFunctionEventListener listener); - - void removeLocomotiveFunctionEventListener(LocomotiveFunctionEventListener listener); - - void addLocomotiveDirectionEventListener(LocomotiveDirectionEventListener listener); - - void removeLocomotiveDirectionEventListener(LocomotiveDirectionEventListener listener); - - void addLocomotiveSpeedEventListener(LocomotiveSpeedEventListener listener); - - void removeLocomotiveSpeedEventListener(LocomotiveSpeedEventListener listener); - - void addMeasurementEventListener(MeasurementEventListener listener); - - void removeMeasurementListener(MeasurementEventListener listener); - - CommandStationBean getCommandStationBean(); - - InfoBean getCommandStationInfo(); - - Image getLocomotiveImage(String imageName); - - Image getLocomotiveFunctionImage(String imageName); - - DecoderController getDecoderController(); - - List getAccessoryControllers(); - - List getFeedbackControllers(); +public class JCSCommandStation { + + private DecoderController decoderController; + private Map accessoryControllers; + private Map feedbackControllers; + + private final List sensorListeners; + + private final List accessoryEventListeners; + private final List locomotiveFunctionEventListeners; + + private final List locomotiveDirectionEventListeners; + private final List locomotiveSpeedEventListeners; + + private final Set supportedProtocols; + private CommandStationBean commandStation; + + private final ExecutorService executor; + + private static final String AWT_THREAD = "AWT-EventQueue-0"; + + /** + * Wrapper around the "real" CommandStation implementation.
+ * Operations to commandStations should not be performed in the EventDispatch thread.
+ * Operations to commandStations are performed in a worker thread to avoid blocking the EventDispatch thread.
+ */ + public JCSCommandStation() { + this("true".equalsIgnoreCase(System.getProperty("skip.controller.autoconnect", "true"))); + } + + private JCSCommandStation(boolean autoConnectController) { + executor = Executors.newCachedThreadPool(); + accessoryControllers = new HashMap<>(); + feedbackControllers = new HashMap<>(); + + sensorListeners = new LinkedList<>(); + accessoryEventListeners = new LinkedList<>(); + locomotiveFunctionEventListeners = new LinkedList<>(); + locomotiveDirectionEventListeners = new LinkedList<>(); + locomotiveSpeedEventListeners = new LinkedList<>(); + supportedProtocols = new HashSet<>(); + + try { + if (autoConnectController && decoderController != null && decoderController.getCommandStationBean() != null || accessoryControllers.isEmpty() || feedbackControllers.isEmpty()) { + connect(); + Logger.trace(decoderController != null ? "Aquired " + decoderController.getClass().getSimpleName() : "Could not aquire a Command Station! " + (decoderController.isConnected() ? "Connected" : "NOT Connected")); + } else { + Logger.trace("Auto Connect disabled"); + } + } catch (Exception e) { + Logger.warn("Can't connect with default Command Station!"); + } + } + + public final boolean connect() { + boolean decoderControllerConnected = false; + boolean allreadyConnected = false; + + //Check if already connected to avoid duplication.... + if (commandStation != null && decoderController != null) { + decoderControllerConnected = decoderController.isConnected(); + allreadyConnected = true; + Logger.trace(decoderController.getClass().getName() + " allready connected..."); + } else { + commandStation = PersistenceFactory.getService().getDefaultCommandStation(); + } + + int accessoryCntrConnected = 0; + int feedbackCntrConnected = 0; + + if (commandStation == null) { + Logger.error("No Default Command Station found!"); + return false; + } + + if (decoderController == null && commandStation != null) { + decoderController = ControllerFactory.getDecoderController(commandStation, false); + } + + if (decoderController == null) { + Logger.error("No DecoderController configured!"); + return false; + } + + if (accessoryControllers.isEmpty()) { + List acl = ControllerFactory.getAccessoryControllers(); + for (AccessoryController ac : acl) { + accessoryControllers.put(ac.getCommandStationBean().getId(), ac); + } + } + + //TODO: a warning log in the main screen + if (accessoryControllers.isEmpty()) { + Logger.warn("No Accessory Controllers configured!"); + } + + if (feedbackControllers.isEmpty()) { + List fcl = ControllerFactory.getFeedbackControllers(); + for (FeedbackController fc : fcl) { + feedbackControllers.put(fc.getCommandStationBean().getId(), fc); + } + } + + //TODO: a warning log in the main screen + if (feedbackControllers.isEmpty()) { + Logger.warn("No Feedback Controllers configured!"); + } + + if (decoderController != null && !decoderControllerConnected) { + decoderControllerConnected = decoderController.isConnected(); + if (!decoderControllerConnected) { + decoderControllerConnected = decoderController.connect(); + } + } + + //Connect the Accessories controllers if needed + if (!accessoryControllers.isEmpty() && !allreadyConnected) { + for (AccessoryController ac : accessoryControllers.values()) { + if (ac.isConnected()) { + accessoryCntrConnected++; + } else { + try { + if (ac.connect()) { + accessoryCntrConnected++; + } + } catch (Exception e) { + Logger.warn(" Can't connected to " + ac.getCommandStationBean().getDescription()); + } + } + } + } + + //Connect the Feedback Controllers controllers if needed + if (!feedbackControllers.isEmpty() && !allreadyConnected) { + for (FeedbackController fc : feedbackControllers.values()) { + if (fc.isConnected()) { + feedbackCntrConnected++; + } else { + try { + if (fc.connect()) { + feedbackCntrConnected++; + } + } catch (Exception e) { + Logger.warn(" Can't connected to " + fc.getCommandStationBean().getDescription()); + } + } + } + } + + Logger.trace("Connected Controllers: Decoder: " + (decoderControllerConnected ? "Yes" : "No") + " Accessory: " + accessoryCntrConnected + " Feedback: " + feedbackCntrConnected); + + if (decoderControllerConnected && !allreadyConnected && decoderController != null) { + decoderController.addConnectionEventListener(new ConnectionListener(this)); + + decoderController.addLocomotiveFunctionEventListener(new LocomotiveFunctionChangeEventListener(this)); + decoderController.addLocomotiveDirectionEventListener(new LocomotiveDirectionChangeEventListener(this)); + decoderController.addLocomotiveSpeedEventListener(new LocomotiveSpeedChangeEventListener(this)); + + supportedProtocols.addAll(decoderController.getCommandStationBean().getSupportedProtocols()); + } + + if (accessoryCntrConnected > 0 && !allreadyConnected) { + for (AccessoryController ac : accessoryControllers.values()) { + if (ac.isConnected()) { + ac.addAccessoryEventListener(new AccessoryChangeEventListener(this)); + ac.addConnectionEventListener(new ConnectionListener(this)); + } + } + } + + if (feedbackCntrConnected > 0 && !allreadyConnected) { + for (FeedbackController fc : feedbackControllers.values()) { + if (fc.isConnected()) { + fc.addSensorEventListener(new SensorChangeEventListener(this)); + fc.addConnectionEventListener(new ConnectionListener(this)); + } + } + } + + //TODO implement get the day end i.e. the current state of all Objects on track + return decoderControllerConnected; + } + + public CommandStationBean getCommandStationBean() { + if (decoderController != null) { + return decoderController.getCommandStationBean(); + } else { + return null; + } + } + + public boolean isConnected() { + if (decoderController != null) { + return decoderController.isConnected(); + } else { + return false; + } + } + + public void disconnect() { + for (FeedbackController fc : feedbackControllers.values()) { + if (fc != decoderController) { + fc.disconnect(); + } + } + for (AccessoryController ac : accessoryControllers.values()) { + if (ac != decoderController) { + ac.disconnect(); + } + } + + if (decoderController != null) { + decoderController.disconnect(); + } + + //Enable command station switching so + decoderController = null; + accessoryControllers.clear(); + feedbackControllers.clear(); + commandStation = null; + ControllerFactory.reset(); + } + + public void setVirtual(boolean flag) { + Logger.info("Switch Virtual Mode " + (flag ? "On" : "Off")); + commandStation.setVirtual(flag); + PersistenceFactory.getService().persist(commandStation); + + decoderController.setVirtual(flag); + } + + public boolean isVirtual() { + if (decoderController != null) { + return decoderController.isVirtual(); + } else { + return false; + } + } + + public Image getLocomotiveImage(String imageName) { + Image image = null; + + if (decoderController != null) { + image = decoderController.getLocomotiveImage(imageName); + if (image != null) { + storeImage(image, imageName, true); + } + } + return image; + } + + public Image getLocomotiveFunctionImage(String imageName) { + Image image = null; + if (decoderController != null) { + image = decoderController.getLocomotiveFunctionImage(imageName); + if (image != null) { + storeImage(image, imageName, false); + } + } + return image; + } + + private void storeImage(Image image, String imageName, boolean locomotive) { + Path path; + String csp = null; + if (decoderController != null) { + csp = this.decoderController.getCommandStationBean().getLastUsedSerial(); + if (csp == null) { + csp = this.decoderController.getCommandStationBean().getId(); + } + } + + String basePath = System.getProperty("user.home") + File.separator + "jcs" + File.separator + "cache" + File.separator + csp; + + if (locomotive) { + path = Paths.get(basePath); + } else { + path = Paths.get(basePath + File.separator + "functions"); + } + + File imageFile = new File(path + File.separator + imageName.toLowerCase() + ".png"); + + try { + if (!Files.exists(path)) { + Files.createDirectories(path); + Logger.trace("Created new directory " + path); + } + ImageIO.write((BufferedImage) image, "png", imageFile); + } catch (IOException ex) { + Logger.error("Can't store image " + imageFile + "! ", ex.getMessage()); + } + Logger.trace("Stored image " + imageName + ".png in the cache"); + } + + public InfoBean getCommandStationInfo() { + if (decoderController != null) { + return decoderController.getCommandStationInfo(); + } else { + return null; + } + } + + public String getCommandStationName() { + if (decoderController != null && decoderController.getCommandStationInfo() != null) { + return decoderController.getCommandStationInfo().getProductName(); + } else if (decoderController != null && decoderController.getCommandStationBean() != null) { + return decoderController.getCommandStationBean().getDescription(); + } else { + return null; + } + } + + public String getCommandStationSerialNumber() { + if (decoderController != null && decoderController.getCommandStationInfo() != null) { + return decoderController.getCommandStationInfo().getSerialNumber(); + } else { + return null; + } + } + + public String getCommandStationArticleNumber() { + if (decoderController != null && decoderController.getCommandStationInfo() != null) { + return decoderController.getCommandStationInfo().getArticleNumber(); + } else { + return null; + } + } + + public void switchPower(boolean on) { + //Logger.trace("Switch Power " + (on ? "On" : "Off")); + if (decoderController != null && !AWT_THREAD.equals(Thread.currentThread().getName())) { + decoderController.power(on); + } else if (decoderController != null) { + executor.execute(() -> decoderController.power(on)); + } + } + + public boolean isPowerOn() { + boolean power = false; + if (decoderController != null) { + power = decoderController.isPower(); + } + return power; + } + + public void changeLocomotiveDirection(Direction newDirection, LocomotiveBean locomotive) { + Logger.debug("Changing direction to " + newDirection + " for: " + locomotive.getName() + " id: " + locomotive.getId()); + + int address; + if ("marklin.cs".equals(locomotive.getCommandStationId()) || "esu-ecos".equals(locomotive.getCommandStationId())) { + address = locomotive.getId().intValue(); + } else { + //TODO: check this probably not needed anymore + if (supportedProtocols.size() == 1) { + address = locomotive.getAddress(); + } else { + if (locomotive.getUid() != null) { + address = locomotive.getUid().intValue(); + } else { + address = locomotive.getId().intValue(); + } + } + } + + if (decoderController != null && !AWT_THREAD.equals(Thread.currentThread().getName())) { + decoderController.changeVelocity(address, 0, locomotive.getDirection()); + decoderController.changeDirection(address, newDirection); + } else { + executor.execute(() -> { + decoderController.changeVelocity(address, 0, locomotive.getDirection()); + decoderController.changeDirection(address, newDirection); + }); + } + } + + public void changeLocomotiveSpeed(Integer newVelocity, LocomotiveBean locomotive) { + Logger.trace("Changing velocity to " + newVelocity + " for " + locomotive.getName()); + + int address; + if ("marklin.cs".equals(locomotive.getCommandStationId()) || "esu-ecos".equals(locomotive.getCommandStationId())) { + address = locomotive.getId().intValue(); + } else { + //TODO: check this probably not needed anymore + if (supportedProtocols.size() == 1) { + address = locomotive.getAddress(); + } else { + if (locomotive.getUid() != null) { + address = locomotive.getUid().intValue(); + } else { + address = locomotive.getId().intValue(); + } + } + } + + if (decoderController != null && !AWT_THREAD.equals(Thread.currentThread().getName())) { + decoderController.changeVelocity(address, newVelocity, locomotive.getDirection()); + } else { + executor.execute(() -> decoderController.changeVelocity(address, newVelocity, locomotive.getDirection())); + } + } + + public void changeLocomotiveFunction(Boolean newValue, Integer functionNumber, LocomotiveBean locomotive) { + Logger.trace("Changing Function " + functionNumber + " to " + (newValue ? "on" : "off") + " on " + locomotive.getName()); + int address; + if ("marklin.cs".equals(locomotive.getCommandStationId()) || "esu-ecos".equals(locomotive.getCommandStationId())) { + address = locomotive.getId().intValue(); + } else { + //TODO: check this probably not needed anymore + if (supportedProtocols.size() == 1) { + address = locomotive.getAddress(); + } else { + if (locomotive.getUid() != null) { + address = locomotive.getUid().intValue(); + } else { + address = locomotive.getId().intValue(); + } + } + } + if (decoderController != null && !AWT_THREAD.equals(Thread.currentThread().getName())) { + decoderController.changeFunctionValue(address, functionNumber, newValue); + } else { + executor.execute(() -> decoderController.changeFunctionValue(address, functionNumber, newValue)); + } + } + + public void switchAccessory(AccessoryBean accessory, AccessoryValue value) { + String id = accessory.getId(); + Integer address = accessory.getAddress(); + Integer switchTime = accessory.getSwitchTime(); + AccessoryBean.Protocol protocol = accessory.getProtocol(); + if (protocol == null) { + protocol = AccessoryBean.Protocol.DCC; + } + AccessoryValue val = value; + Integer states = accessory.getStates(); + Integer state = accessory.getState(); + + if (states == null) { + states = 2; + } + if (state == null) { + state = AccessoryValue.RED == val ? 0 : 1; + } + + if (states > 2) { + if (accessory.getState() > 1) { + address = address + 1; + val = AccessoryValue.get(state - 2); + } + } + + Logger.trace("Changing accessory with address: " + address + ", " + accessory.getName() + " to " + val.getValue()); + changeAccessory(address, protocol.getValue(), val, switchTime); + } + + private void changeAccessory(final Integer address, final String protocol, final AccessoryValue value, final Integer switchTime) { + if (!AWT_THREAD.equals(Thread.currentThread().getName())) { + for (AccessoryController ac : accessoryControllers.values()) { + ac.switchAccessory(address, protocol, value, switchTime); + } + } else { + executor.execute(() -> { + for (AccessoryController ac : accessoryControllers.values()) { + ac.switchAccessory(address, protocol, value, switchTime); + } + }); + } + } + + public void addSensorEventListener(SensorEventListener listener) { + sensorListeners.add(listener); + } + + public void removeSensorEventListener(SensorEventListener listener) { + sensorListeners.remove(listener); + } + + public void addAccessoryEventListener(AccessoryEventListener listener) { + accessoryEventListeners.add(listener); + } + + public void removeAccessoryEventListener(AccessoryEventListener listener) { + accessoryEventListeners.remove(listener); + } + + public void addLocomotiveFunctionEventListener(LocomotiveFunctionEventListener listener) { + locomotiveFunctionEventListeners.add(listener); + } + + public void removeLocomotiveFunctionEventListener(LocomotiveFunctionEventListener listener) { + locomotiveFunctionEventListeners.remove(listener); + } + + public void addLocomotiveDirectionEventListener(LocomotiveDirectionEventListener listener) { + locomotiveDirectionEventListeners.add(listener); + } + + public void removeLocomotiveDirectionEventListener(LocomotiveDirectionEventListener listener) { + this.locomotiveDirectionEventListeners.remove(listener); + } + + public void addLocomotiveSpeedEventListener(LocomotiveSpeedEventListener listener) { + locomotiveSpeedEventListeners.add(listener); + } + + public void removeLocomotiveSpeedEventListener(LocomotiveSpeedEventListener listener) { + locomotiveSpeedEventListeners.remove(listener); + } + + public void addDisconnectionEventListener(ConnectionEventListener listener) { + if (decoderController != null) { + decoderController.addConnectionEventListener(listener); + } + for (AccessoryController ac : accessoryControllers.values()) { + if (ac != decoderController) { + ac.addConnectionEventListener(listener); + } + } + + for (FeedbackController fc : feedbackControllers.values()) { + if (fc != decoderController) { + fc.addConnectionEventListener(listener); + } + } + } + + public void addPowerEventListener(PowerEventListener listener) { + if (decoderController != null) { + decoderController.addPowerEventListener(listener); + } + } + + public void removePowerEventListener(PowerEventListener listener) { + if (decoderController != null) { + decoderController.removePowerEventListener(listener); + } + } + + public void addMeasurementEventListener(MeasurementEventListener listener) { + if (decoderController != null && decoderController.isSupportTrackMeasurements()) { + decoderController.addMeasurementEventListener(listener); + } + } + + public void removeMeasurementListener(MeasurementEventListener listener) { + if (decoderController != null && decoderController.isSupportTrackMeasurements()) { + decoderController.removeMeasurementEventListener(listener); + } + } + + public DecoderController getDecoderController() { + return decoderController; + } + + public List getAccessoryControllers() { + return accessoryControllers.values().stream().collect(Collectors.toList()); + } + + public List getFeedbackControllers() { + return feedbackControllers.values().stream().collect(Collectors.toList()); + } + + private class SensorChangeEventListener implements SensorEventListener { + + private final JCSCommandStation commandStation; + + SensorChangeEventListener(JCSCommandStation commandStation) { + this.commandStation = commandStation; + } + + @Override + public void onSensorChange(SensorEvent event) { + SensorBean sb = event.getSensorBean(); + boolean newValue = event.isActive(); + //SensorBean dbsb = PersistenceFactory.getService().getSensor(sb.getDeviceId(), sb.getContactId()); + SensorBean dbsb = PersistenceFactory.getService().getSensor(event.getSensorId()); + + if (dbsb == null) { + //Try using the deviceId and contactId + dbsb = PersistenceFactory.getService().getSensor(sb.getDeviceId(), sb.getContactId()); + } + + if (dbsb != null) { + if (sb.getId() == null) { + sb.setId(dbsb.getId()); + } + sb.setName(dbsb.getName()); + sb.setActive(newValue); + PersistenceFactory.getService().persist(sb); + } + + //Avoid concurrent modification exceptions + List snapshot = new ArrayList<>(commandStation.sensorListeners); + + for (SensorEventListener sl : snapshot) { + if (sl != null) { + sl.onSensorChange(event); + } + } + } + } + + private class AccessoryChangeEventListener implements AccessoryEventListener { + + private final JCSCommandStation trackService; + + AccessoryChangeEventListener(JCSCommandStation trackService) { + this.trackService = trackService; + } + + @Override + public void onAccessoryChange(AccessoryEvent event) { + AccessoryBean ab = event.getAccessoryBean(); + + int address = ab.getAddress(); + String commandStationId = ab.getCommandStationId(); + + AccessoryBean dbab = PersistenceFactory.getService().getAccessoryByAddressAndCommandStationId(address, commandStationId); + if (dbab == null) { + //check if address is even, might be the second address of a signal + if (address % 2 == 0) { + address = address - 1; + dbab = PersistenceFactory.getService().getAccessoryByAddressAndCommandStationId(address, commandStationId); + if (dbab != null && dbab.isSignal() && dbab.getStates() > 2) { + ab.setAddress(address); + int p = ab.getState() + 2; + ab.setState(p); + } else { + dbab = null; + } + } + } + + if (dbab != null) { + //set all properties + ab.setId(dbab.getId()); + ab.setDecoder(dbab.getDecoder()); + ab.setDecType(dbab.getDecType()); + ab.setName(dbab.getName()); + ab.setType(dbab.getType()); + ab.setGroup(dbab.getGroup()); + ab.setIcon(dbab.getIcon()); + ab.setIconFile(dbab.getIconFile()); + ab.setStates(dbab.getStates()); + ab.setCommandStationId(dbab.getCommandStationId()); + //might be set by the event + if (ab.getSwitchTime() == null) { + ab.setSwitchTime(dbab.getSwitchTime()); + } + + PersistenceFactory.getService().persist(ab); + + for (AccessoryEventListener al : this.trackService.accessoryEventListeners) { + al.onAccessoryChange(event); + } + } + } + } + + private class LocomotiveFunctionChangeEventListener implements LocomotiveFunctionEventListener { + + private final JCSCommandStation trackService; + + LocomotiveFunctionChangeEventListener(JCSCommandStation trackService) { + this.trackService = trackService; + } + + @Override + public void onFunctionChange(LocomotiveFunctionEvent functionEvent) { + FunctionBean fb = functionEvent.getFunctionBean(); + + FunctionBean dbfb = null; + String commandStationId = trackService.getDecoderController().getCommandStationBean().getId(); + + if ("marklin.cs".equals(commandStationId) || "esu-ecos".equals(commandStationId)) { + dbfb = PersistenceFactory.getService().getLocomotiveFunction(fb.getLocomotiveId(), fb.getNumber()); + } else { + Integer address = fb.getLocomotiveId().intValue(); + + LocomotiveBean dblb = PersistenceFactory.getService().getLocomotive(address, DecoderType.get(fb.getDecoderTypeString()), fb.getCommandStationId()); + if (dblb != null) { + dbfb = PersistenceFactory.getService().getLocomotiveFunction(dblb.getId(), fb.getNumber()); + } + } + + if (dbfb != null) { + if (!Objects.equals(dbfb.getValue(), fb.getValue())) { + dbfb.setValue(fb.getValue()); + if (!dbfb.isMomentary()) { + PersistenceFactory.getService().persist(dbfb); + functionEvent.setFunctionBean(dbfb); + } + for (LocomotiveFunctionEventListener fl : trackService.locomotiveFunctionEventListeners) { + fl.onFunctionChange(functionEvent); + } + } + } + } + } + + private class LocomotiveDirectionChangeEventListener implements LocomotiveDirectionEventListener { + + private final JCSCommandStation trackService; + + LocomotiveDirectionChangeEventListener(JCSCommandStation trackService) { + this.trackService = trackService; + } + + @Override + public void onDirectionChange(LocomotiveDirectionEvent directionEvent) { + LocomotiveBean lb = directionEvent.getLocomotiveBean(); + if (lb != null) { + LocomotiveBean dblb = null; + //For marklin and Ecos use the ID + if ("marklin.cs".equals(lb.getCommandStationId()) || "esu-ecos".equals(lb.getCommandStationId())) { + dblb = PersistenceFactory.getService().getLocomotive(lb.getId()); + } else { + Integer address; + if (lb.getAddress() != null) { + address = lb.getAddress(); + } else { + address = lb.getId().intValue(); + } + if (lb.getDecoderType() != null) { + dblb = PersistenceFactory.getService().getLocomotive(address, lb.getDecoderType(), lb.getCommandStationId()); + } else { + //Try to match one... + Set protocols = PersistenceFactory.getService().getDefaultCommandStation().getSupportedProtocols(); + for (Protocol protocol : protocols) { + DecoderType decoder = DecoderType.get(protocol.getProtocol()); + dblb = PersistenceFactory.getService().getLocomotive(address, decoder, lb.getCommandStationId()); + if (dblb != null) { + break; + } + } + } + } + + if (dblb != null) { + if (!Objects.equals(dblb.getRichtung(), lb.getRichtung())) { + Integer richtung = lb.getRichtung(); + dblb.setRichtung(richtung); + PersistenceFactory.getService().persist(dblb); + + Logger.trace(dblb.getId() + ", " + dblb.getName() + ": " + dblb.getDirection().getDirection()); + + directionEvent.setLocomotiveBean(dblb); + + for (LocomotiveDirectionEventListener dl : this.trackService.locomotiveDirectionEventListeners) { + dl.onDirectionChange(directionEvent); + } + } + } else { + Logger.trace("No loc found for " + lb.toLogString()); + } + } + } + } + + private class LocomotiveSpeedChangeEventListener implements LocomotiveSpeedEventListener { + + private final JCSCommandStation trackService; + + LocomotiveSpeedChangeEventListener(JCSCommandStation trackService) { + this.trackService = trackService; + } + + @Override + public void onSpeedChange(LocomotiveSpeedEvent speedEvent) { + LocomotiveBean lb = speedEvent.getLocomotiveBean(); + if (lb != null) { + LocomotiveBean dblb; + //For marklin and Ecos use the ID + if ("marklin.cs".equals(lb.getCommandStationId()) || "esu-ecos".equals(lb.getCommandStationId())) { + dblb = PersistenceFactory.getService().getLocomotive(lb.getId()); + } else { + Integer address; + if (lb.getAddress() != null) { + address = lb.getAddress(); + } else { + address = lb.getId().intValue(); + } + dblb = PersistenceFactory.getService().getLocomotive(address, lb.getDecoderType(), lb.getCommandStationId()); + } + + if (dblb != null) { + Integer velocity = lb.getVelocity(); + dblb.setVelocity(velocity); + PersistenceFactory.getService().persist(dblb); + + speedEvent.setLocomotiveBean(dblb); + for (LocomotiveSpeedEventListener dl : trackService.locomotiveSpeedEventListeners) { + if (dl != null) { + dl.onSpeedChange(speedEvent); + } + } + } else { + if ("marklin.cs".equals(lb.getCommandStationId()) || "esu-ecos".equals(lb.getCommandStationId())) { + Logger.trace("No loc with id " + lb.getId() + ", " + lb.getCommandStationId()); + } else { + Logger.trace("No loc found for " + lb.toLogString()); + } + } + } + } + } + + private class ConnectionListener implements ConnectionEventListener { + + private final JCSCommandStation jcsCommandStation; + + ConnectionListener(JCSCommandStation jcsCommandStation) { + this.jcsCommandStation = jcsCommandStation; + } + + @Override + public void onConnectionChange(ConnectionEvent event) { + if (event.isConnected()) { + Logger.trace(event.getSource() + " has re-connected!"); + } else { + Logger.trace(event.getSource() + " is Disconnected!"); + //jcsCommandStationImpl.disconnect(); + } + } + } } diff --git a/src/main/java/jcs/commandStation/JCSCommandStationImpl.java b/src/main/java/jcs/commandStation/JCSCommandStationImpl.java deleted file mode 100755 index ee4011c4..00000000 --- a/src/main/java/jcs/commandStation/JCSCommandStationImpl.java +++ /dev/null @@ -1,964 +0,0 @@ -/* - * Copyright 2023 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.commandStation; - -import java.awt.Image; -import java.awt.image.BufferedImage; -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.stream.Collectors; -import javax.imageio.ImageIO; -import jcs.commandStation.events.AccessoryEvent; -import jcs.commandStation.events.AccessoryEventListener; -import jcs.commandStation.events.ConnectionEvent; -import jcs.commandStation.events.LocomotiveDirectionEvent; -import jcs.commandStation.events.LocomotiveDirectionEventListener; -import jcs.commandStation.events.LocomotiveFunctionEvent; -import jcs.commandStation.events.LocomotiveFunctionEventListener; -import jcs.commandStation.events.LocomotiveSpeedEvent; -import jcs.commandStation.events.LocomotiveSpeedEventListener; -import jcs.commandStation.events.MeasurementEventListener; -import jcs.commandStation.events.PowerEventListener; -import jcs.commandStation.events.SensorEvent; -import jcs.commandStation.events.SensorEventListener; -import jcs.entities.AccessoryBean; -import jcs.entities.AccessoryBean.AccessoryValue; -import jcs.entities.CommandStationBean; -import jcs.entities.CommandStationBean.Protocol; -import jcs.entities.FunctionBean; -import jcs.commandStation.entities.InfoBean; -import jcs.entities.LocomotiveBean; -import jcs.entities.LocomotiveBean.DecoderType; -import jcs.entities.LocomotiveBean.Direction; -import jcs.entities.SensorBean; -import jcs.persistence.PersistenceFactory; -import org.tinylog.Logger; -import jcs.commandStation.events.ConnectionEventListener; - -/** - * The JCSCommandStation is the layer between the UI, engines and Command stations - */ -public class JCSCommandStationImpl implements JCSCommandStation { - - private DecoderController decoderController; - private Map accessoryControllers; - private Map feedbackControllers; - - private final List sensorListeners; - - private final List accessoryEventListeners; - private final List locomotiveFunctionEventListeners; - - private final List locomotiveDirectionEventListeners; - private final List locomotiveSpeedEventListeners; - - private final Set supportedProtocols; - private CommandStationBean commandStation; - - private final ExecutorService executor; - - private static final String AWT_THREAD = "AWT-EventQueue-0"; - - /** - * Wrapper around the "real" CommandStation implementation.
- * Operations to commandStations should not be performed in the EventDispatch thread.
- * Operations to commandStations are performed in a worker thread to avoid blocking the EventDispatch thread.
- */ - public JCSCommandStationImpl() { - this("true".equalsIgnoreCase(System.getProperty("skip.controller.autoconnect", "true"))); - } - - private JCSCommandStationImpl(boolean autoConnectController) { - executor = Executors.newCachedThreadPool(); - accessoryControllers = new HashMap<>(); - feedbackControllers = new HashMap<>(); - - sensorListeners = new LinkedList<>(); - accessoryEventListeners = new LinkedList<>(); - locomotiveFunctionEventListeners = new LinkedList<>(); - locomotiveDirectionEventListeners = new LinkedList<>(); - locomotiveSpeedEventListeners = new LinkedList<>(); - supportedProtocols = new HashSet<>(); - - try { - if (autoConnectController && decoderController != null && decoderController.getCommandStationBean() != null || accessoryControllers.isEmpty() || feedbackControllers.isEmpty()) { - connect(); - Logger.trace(decoderController != null ? "Aquired " + decoderController.getClass().getSimpleName() : "Could not aquire a Command Station! " + (decoderController.isConnected() ? "Connected" : "NOT Connected")); - } else { - Logger.trace("Auto Connect disabled"); - } - } catch (Exception e) { - Logger.warn("Can't connect with default Command Station!"); - } - } - - @Override - public final boolean connect() { - boolean decoderControllerConnected = false; - boolean allreadyConnected = false; - - //Check if already connected to avoid duplication.... - if (commandStation != null && decoderController != null) { - decoderControllerConnected = decoderController.isConnected(); - allreadyConnected = true; - Logger.trace(decoderController.getClass().getName() + " allready connected..."); - } else { - commandStation = PersistenceFactory.getService().getDefaultCommandStation(); - } - - int accessoryCntrConnected = 0; - int feedbackCntrConnected = 0; - - if (commandStation == null) { - Logger.error("No Default Command Station found!"); - return false; - } - - if (decoderController == null && commandStation != null) { - decoderController = ControllerFactory.getDecoderController(commandStation, false); - } - - if (decoderController == null) { - Logger.error("No DecoderController configured!"); - return false; - } - - if (accessoryControllers.isEmpty()) { - List acl = ControllerFactory.getAccessoryControllers(); - for (AccessoryController ac : acl) { - accessoryControllers.put(ac.getCommandStationBean().getId(), ac); - } - } - - //TODO: a warning log in the main screen - if (accessoryControllers.isEmpty()) { - Logger.warn("No Accessory Controllers configured!"); - } - - if (feedbackControllers.isEmpty()) { - List fcl = ControllerFactory.getFeedbackControllers(); - for (FeedbackController fc : fcl) { - feedbackControllers.put(fc.getCommandStationBean().getId(), fc); - } - } - - //TODO: a warning log in the main screen - if (feedbackControllers.isEmpty()) { - Logger.warn("No Feedback Controllers configured!"); - } - - if (decoderController != null && !decoderControllerConnected) { - decoderControllerConnected = decoderController.isConnected(); - if (!decoderControllerConnected) { - decoderControllerConnected = decoderController.connect(); - } - } - - //Connect the Accessories controllers if needed - if (!accessoryControllers.isEmpty() && !allreadyConnected) { - for (AccessoryController ac : accessoryControllers.values()) { - if (ac.isConnected()) { - accessoryCntrConnected++; - } else { - try { - if (ac.connect()) { - accessoryCntrConnected++; - } - } catch (Exception e) { - Logger.warn(" Can't connected to " + ac.getCommandStationBean().getDescription()); - } - } - } - } - - //Connect the Feedback Controllers controllers if needed - if (!feedbackControllers.isEmpty() && !allreadyConnected) { - for (FeedbackController fc : feedbackControllers.values()) { - if (fc.isConnected()) { - feedbackCntrConnected++; - } else { - try { - if (fc.connect()) { - feedbackCntrConnected++; - } - } catch (Exception e) { - Logger.warn(" Can't connected to " + fc.getCommandStationBean().getDescription()); - } - } - } - } - - Logger.trace("Connected Controllers: Decoder: " + (decoderControllerConnected ? "Yes" : "No") + " Accessory: " + accessoryCntrConnected + " Feedback: " + feedbackCntrConnected); - - if (decoderControllerConnected && !allreadyConnected && decoderController != null) { - decoderController.addConnectionEventListener(new ConnectionListener(this)); - - decoderController.addLocomotiveFunctionEventListener(new LocomotiveFunctionChangeEventListener(this)); - decoderController.addLocomotiveDirectionEventListener(new LocomotiveDirectionChangeEventListener(this)); - decoderController.addLocomotiveSpeedEventListener(new LocomotiveSpeedChangeEventListener(this)); - - supportedProtocols.addAll(decoderController.getCommandStationBean().getSupportedProtocols()); - -// if (decoderController.isSupportTrackMeasurements()) { -// //Start the measurements background task -// long measureInterval = Long.parseLong(System.getProperty("track.measurements.interval", "5")); -// measureInterval = measureInterval * 1000; -// -// if (measureInterval > 0) { -// TrackMeasurementTask measurementTask = new TrackMeasurementTask(this); -// Timer timer = new Timer("Timer"); -// timer.schedule(measurementTask, 0, measureInterval); -// Logger.debug("Started Track measurements with an interval of " + measureInterval + "s"); -// } else { -// Logger.debug("Skipping Track measurements"); -// } -// } else { -// Logger.debug("Track measurements are not supported"); -// } - } - - if (accessoryCntrConnected > 0 && !allreadyConnected) { - for (AccessoryController ac : accessoryControllers.values()) { - if (ac.isConnected()) { - ac.addAccessoryEventListener(new AccessoryChangeEventListener(this)); - ac.addConnectionEventListener(new ConnectionListener(this)); - } - } - } - - if (feedbackCntrConnected > 0 && !allreadyConnected) { - for (FeedbackController fc : feedbackControllers.values()) { - if (fc.isConnected()) { - fc.addSensorEventListener(new SensorChangeEventListener(this)); - fc.addConnectionEventListener(new ConnectionListener(this)); - } - } - } - - //TODO implement get the day end i.e. the current state of all Objects on track - return decoderControllerConnected; - } - - @Override - public CommandStationBean getCommandStationBean() { - if (this.decoderController != null) { - return this.decoderController.getCommandStationBean(); - } else { - return null; - } - } - - @Override - public boolean isConnected() { - if (decoderController != null) { - return decoderController.isConnected(); - } else { - return false; - } - } - - @Override - public void disconnect() { - for (FeedbackController fc : feedbackControllers.values()) { - if (fc != decoderController) { - fc.disconnect(); - } - } - for (AccessoryController ac : accessoryControllers.values()) { - if (ac != decoderController) { - ac.disconnect(); - } - } - - if (decoderController != null) { - decoderController.disconnect(); - } - - //Enable command station switching so - decoderController = null; - accessoryControllers.clear(); - feedbackControllers.clear(); - commandStation = null; - ControllerFactory.reset(); - } - - @Override - public void setVirtual(boolean flag) { - Logger.info("Switch Virtual Mode " + (flag ? "On" : "Off")); - commandStation.setVirtual(flag); - PersistenceFactory.getService().persist(commandStation); - - decoderController.setVirtual(flag); - } - - @Override - public boolean isVirtual() { - if (this.decoderController != null) { - return this.decoderController.isVirtual(); - } else { - return false; - } - } - - @Override - public Image getLocomotiveImage(String imageName) { - Image image = null; - - if (decoderController != null) { - image = decoderController.getLocomotiveImage(imageName); - if (image != null) { - storeImage(image, imageName, true); - } - } - return image; - } - - @Override - public Image getLocomotiveFunctionImage(String imageName) { - Image image = null; - if (decoderController != null) { - image = decoderController.getLocomotiveFunctionImage(imageName); - if (image != null) { - storeImage(image, imageName, false); - } - } - return image; - } - - private void storeImage(Image image, String imageName, boolean locomotive) { - Path path; - String csp = null; - if (decoderController != null) { - csp = this.decoderController.getCommandStationBean().getLastUsedSerial(); - if (csp == null) { - csp = this.decoderController.getCommandStationBean().getId(); - } - } - - String basePath = System.getProperty("user.home") + File.separator + "jcs" + File.separator + "cache" + File.separator + csp; - - if (locomotive) { - path = Paths.get(basePath); - } else { - path = Paths.get(basePath + File.separator + "functions"); - } - - File imageFile = new File(path + File.separator + imageName.toLowerCase() + ".png"); - - try { - if (!Files.exists(path)) { - Files.createDirectories(path); - Logger.trace("Created new directory " + path); - } - ImageIO.write((BufferedImage) image, "png", imageFile); - } catch (IOException ex) { - Logger.error("Can't store image " + imageFile + "! ", ex.getMessage()); - } - Logger.trace("Stored image " + imageName + ".png in the cache"); - } - - @Override - public InfoBean getCommandStationInfo() { - if (decoderController != null) { - return decoderController.getCommandStationInfo(); - } else { - return null; - } - } - - public String getCommandStationName() { - if (decoderController != null && decoderController.getCommandStationInfo() != null) { - return decoderController.getCommandStationInfo().getProductName(); - } else if (decoderController != null && decoderController.getCommandStationBean() != null) { - return decoderController.getCommandStationBean().getDescription(); - } else { - return null; - } - } - - public String getCommandStationSerialNumber() { - if (decoderController != null && decoderController.getCommandStationInfo() != null) { - return decoderController.getCommandStationInfo().getSerialNumber(); - } else { - return null; - } - } - - public String getCommandStationArticleNumber() { - if (decoderController != null && decoderController.getCommandStationInfo() != null) { - return decoderController.getCommandStationInfo().getArticleNumber(); - } else { - return null; - } - } - - @Override - public void switchPower(boolean on) { - //Logger.trace("Switch Power " + (on ? "On" : "Off")); - if (decoderController != null && !AWT_THREAD.equals(Thread.currentThread().getName())) { - decoderController.power(on); - } else if (decoderController != null) { - executor.execute(() -> decoderController.power(on)); - } - } - - @Override - public boolean isPowerOn() { - boolean power = false; - if (decoderController != null) { - power = decoderController.isPower(); - } - return power; - } - - @Override - public void changeLocomotiveDirection(Direction newDirection, LocomotiveBean locomotive) { - Logger.debug("Changing direction to " + newDirection + " for: " + locomotive.getName() + " id: " + locomotive.getId()); - - int address; - if ("marklin.cs".equals(locomotive.getCommandStationId()) || "esu-ecos".equals(locomotive.getCommandStationId())) { - address = locomotive.getId().intValue(); - } else { - //TODO: check this probably not needed anymore - if (supportedProtocols.size() == 1) { - address = locomotive.getAddress(); - } else { - if (locomotive.getUid() != null) { - address = locomotive.getUid().intValue(); - } else { - address = locomotive.getId().intValue(); - } - } - } - - if (decoderController != null && !AWT_THREAD.equals(Thread.currentThread().getName())) { - decoderController.changeVelocity(address, 0, locomotive.getDirection()); - decoderController.changeDirection(address, newDirection); - } else { - executor.execute(() -> { - decoderController.changeVelocity(address, 0, locomotive.getDirection()); - decoderController.changeDirection(address, newDirection); - }); - } - } - - @Override - public void changeLocomotiveSpeed(Integer newVelocity, LocomotiveBean locomotive) { - Logger.trace("Changing velocity to " + newVelocity + " for " + locomotive.getName()); - - int address; - if ("marklin.cs".equals(locomotive.getCommandStationId()) || "esu-ecos".equals(locomotive.getCommandStationId())) { - address = locomotive.getId().intValue(); - } else { - //TODO: check this probably not needed anymore - if (supportedProtocols.size() == 1) { - address = locomotive.getAddress(); - } else { - if (locomotive.getUid() != null) { - address = locomotive.getUid().intValue(); - } else { - address = locomotive.getId().intValue(); - } - } - } - - if (decoderController != null && !AWT_THREAD.equals(Thread.currentThread().getName())) { - decoderController.changeVelocity(address, newVelocity, locomotive.getDirection()); - } else { - executor.execute(() -> decoderController.changeVelocity(address, newVelocity, locomotive.getDirection())); - } - } - - @Override - public void changeLocomotiveFunction(Boolean newValue, Integer functionNumber, LocomotiveBean locomotive) { - Logger.trace("Changing Function " + functionNumber + " to " + (newValue ? "on" : "off") + " on " + locomotive.getName()); - int address; - if ("marklin.cs".equals(locomotive.getCommandStationId()) || "esu-ecos".equals(locomotive.getCommandStationId())) { - address = locomotive.getId().intValue(); - } else { - //TODO: check this probably not needed anymore - if (supportedProtocols.size() == 1) { - address = locomotive.getAddress(); - } else { - if (locomotive.getUid() != null) { - address = locomotive.getUid().intValue(); - } else { - address = locomotive.getId().intValue(); - } - } - } - if (decoderController != null && !AWT_THREAD.equals(Thread.currentThread().getName())) { - decoderController.changeFunctionValue(address, functionNumber, newValue); - } else { - executor.execute(() -> decoderController.changeFunctionValue(address, functionNumber, newValue)); - } - } - - @Override - public void switchAccessory(AccessoryBean accessory, AccessoryValue value) { - String id = accessory.getId(); - Integer address = accessory.getAddress(); - Integer switchTime = accessory.getSwitchTime(); - AccessoryBean.Protocol protocol = accessory.getProtocol(); - if (protocol == null) { - protocol = AccessoryBean.Protocol.DCC; - } - AccessoryValue val = value; - Integer states = accessory.getStates(); - Integer state = accessory.getState(); - - if (states == null) { - states = 2; - } - if (state == null) { - state = AccessoryValue.RED == val ? 0 : 1; - } - - if (states > 2) { - if (accessory.getState() > 1) { - address = address + 1; - val = AccessoryValue.get(state - 2); - } - } - - Logger.trace("Changing accessory with address: " + address + ", " + accessory.getName() + " to " + val.getValue()); - changeAccessory(address, protocol.getValue(), val, switchTime); - } - - private void changeAccessory(final Integer address, final String protocol, final AccessoryValue value, final Integer switchTime) { - if (!AWT_THREAD.equals(Thread.currentThread().getName())) { - for (AccessoryController ac : accessoryControllers.values()) { - ac.switchAccessory(address, protocol, value, switchTime); - } - } else { - executor.execute(() -> { - for (AccessoryController ac : accessoryControllers.values()) { - ac.switchAccessory(address, protocol, value, switchTime); - } - }); - } - } - - @Override - public void addSensorEventListener(SensorEventListener listener) { - sensorListeners.add(listener); - } - - @Override - public void removeSensorEventListener(SensorEventListener listener) { - sensorListeners.remove(listener); - } - - @Override - public void addAccessoryEventListener(AccessoryEventListener listener) { - accessoryEventListeners.add(listener); - } - - @Override - public void removeAccessoryEventListener(AccessoryEventListener listener) { - accessoryEventListeners.remove(listener); - } - - @Override - public void addLocomotiveFunctionEventListener(LocomotiveFunctionEventListener listener) { - locomotiveFunctionEventListeners.add(listener); - } - - @Override - public void removeLocomotiveFunctionEventListener(LocomotiveFunctionEventListener listener) { - locomotiveFunctionEventListeners.remove(listener); - } - - @Override - public void addLocomotiveDirectionEventListener(LocomotiveDirectionEventListener listener) { - locomotiveDirectionEventListeners.add(listener); - } - - @Override - public void removeLocomotiveDirectionEventListener(LocomotiveDirectionEventListener listener) { - this.locomotiveDirectionEventListeners.remove(listener); - } - - @Override - public void addLocomotiveSpeedEventListener(LocomotiveSpeedEventListener listener) { - locomotiveSpeedEventListeners.add(listener); - } - - @Override - public void removeLocomotiveSpeedEventListener(LocomotiveSpeedEventListener listener) { - locomotiveSpeedEventListeners.remove(listener); - } - - @Override - public void addDisconnectionEventListener(ConnectionEventListener listener) { - if (decoderController != null) { - decoderController.addConnectionEventListener(listener); - } - for (AccessoryController ac : accessoryControllers.values()) { - if (ac != decoderController) { - ac.addConnectionEventListener(listener); - } - } - - for (FeedbackController fc : feedbackControllers.values()) { - if (fc != decoderController) { - fc.addConnectionEventListener(listener); - } - } - } - - @Override - public void addPowerEventListener(PowerEventListener listener) { - if (decoderController != null) { - decoderController.addPowerEventListener(listener); - } - } - - @Override - public void removePowerEventListener(PowerEventListener listener) { - if (decoderController != null) { - decoderController.removePowerEventListener(listener); - } - } - - @Override - public void addMeasurementEventListener(MeasurementEventListener listener) { - if (decoderController != null && decoderController.isSupportTrackMeasurements()) { - decoderController.addMeasurementEventListener(listener); - } - } - - @Override - public void removeMeasurementListener(MeasurementEventListener listener) { - if (decoderController != null && decoderController.isSupportTrackMeasurements()) { - decoderController.removeMeasurementEventListener(listener); - } - } - - @Override - public DecoderController getDecoderController() { - return decoderController; - } - - @Override - public List getAccessoryControllers() { - return accessoryControllers.values().stream().collect(Collectors.toList()); - } - - @Override - public List getFeedbackControllers() { - return feedbackControllers.values().stream().collect(Collectors.toList()); - } - -// private class TrackMeasurementTask extends TimerTask { -// -// private final JCSCommandStationImpl Controller; -// private boolean debuglog = false; -// -// TrackMeasurementTask(JCSCommandStationImpl Controller) { -// this.Controller = Controller; -// this.debuglog = System.getProperty("debug.measurements", "false").equalsIgnoreCase("true"); -// } -// -// @Override -// public void run() { -// if (this.Controller != null && this.Controller.decoderController != null) { -// Map measurements = this.Controller.decoderController.getTrackMeasurements(); -// for (ChannelBean ch : measurements.values()) { -// -// if (ch != null && ch.isChanged()) { -// MeasurementEvent me = new MeasurementEvent(ch); -// if (debuglog) { -// Logger.trace("Changed Channel " + ch.getNumber() + ", " + ch.getName() + ": " + ch.getHumanValue() + " " + ch.getUnit()); -// } -// for (MeasurementEventListener mel : this.Controller.measurementEventListeners) { -// mel.onMeasurement(me); -// } -// } -// } -// } -// } -// } - private class SensorChangeEventListener implements SensorEventListener { - - private final JCSCommandStationImpl commandStation; - - SensorChangeEventListener(JCSCommandStationImpl commandStation) { - this.commandStation = commandStation; - } - - @Override - public void onSensorChange(SensorEvent event) { - SensorBean sb = event.getSensorBean(); - boolean newValue = event.isActive(); - SensorBean dbsb = PersistenceFactory.getService().getSensor(sb.getDeviceId(), sb.getContactId()); - - if (dbsb != null) { - sb.setId(dbsb.getId()); - sb.setName(dbsb.getName()); - sb.setActive(newValue); - PersistenceFactory.getService().persist(sb); - } - - //Avoid concurrent modification exceptions - List snapshot = new ArrayList<>(commandStation.sensorListeners); - - for (SensorEventListener sl : snapshot) { - if (sl != null) { - sl.onSensorChange(event); - } - } - } - } - - private class AccessoryChangeEventListener implements AccessoryEventListener { - - private final JCSCommandStationImpl trackService; - - AccessoryChangeEventListener(JCSCommandStationImpl trackService) { - this.trackService = trackService; - } - - @Override - public void onAccessoryChange(AccessoryEvent event) { - AccessoryBean ab = event.getAccessoryBean(); - - int address = ab.getAddress(); - String commandStationId = ab.getCommandStationId(); - - AccessoryBean dbab = PersistenceFactory.getService().getAccessoryByAddressAndCommandStationId(address, commandStationId); - if (dbab == null) { - //check if address is even, might be the second address of a signal - if (address % 2 == 0) { - address = address - 1; - dbab = PersistenceFactory.getService().getAccessoryByAddressAndCommandStationId(address, commandStationId); - if (dbab != null && dbab.isSignal() && dbab.getStates() > 2) { - ab.setAddress(address); - int p = ab.getState() + 2; - ab.setState(p); - } else { - dbab = null; - } - } - } - - if (dbab != null) { - //set all properties - ab.setId(dbab.getId()); - ab.setDecoder(dbab.getDecoder()); - ab.setDecType(dbab.getDecType()); - ab.setName(dbab.getName()); - ab.setType(dbab.getType()); - ab.setGroup(dbab.getGroup()); - ab.setIcon(dbab.getIcon()); - ab.setIconFile(dbab.getIconFile()); - ab.setStates(dbab.getStates()); - ab.setCommandStationId(dbab.getCommandStationId()); - //might be set by the event - if (ab.getSwitchTime() == null) { - ab.setSwitchTime(dbab.getSwitchTime()); - } - - PersistenceFactory.getService().persist(ab); - - for (AccessoryEventListener al : this.trackService.accessoryEventListeners) { - al.onAccessoryChange(event); - } - } - } - } - - private class LocomotiveFunctionChangeEventListener implements LocomotiveFunctionEventListener { - - private final JCSCommandStationImpl trackService; - - LocomotiveFunctionChangeEventListener(JCSCommandStationImpl trackService) { - this.trackService = trackService; - } - - @Override - public void onFunctionChange(LocomotiveFunctionEvent functionEvent) { - FunctionBean fb = functionEvent.getFunctionBean(); - - FunctionBean dbfb = null; - String commandStationId = trackService.getDecoderController().getCommandStationBean().getId(); - - if ("marklin.cs".equals(commandStationId) || "esu-ecos".equals(commandStationId)) { - dbfb = PersistenceFactory.getService().getLocomotiveFunction(fb.getLocomotiveId(), fb.getNumber()); - } else { - Integer address = fb.getLocomotiveId().intValue(); - - LocomotiveBean dblb = PersistenceFactory.getService().getLocomotive(address, DecoderType.get(fb.getDecoderTypeString()), fb.getCommandStationId()); - if (dblb != null) { - dbfb = PersistenceFactory.getService().getLocomotiveFunction(dblb.getId(), fb.getNumber()); - } - } - - if (dbfb != null) { - if (!Objects.equals(dbfb.getValue(), fb.getValue())) { - dbfb.setValue(fb.getValue()); - if (!dbfb.isMomentary()) { - PersistenceFactory.getService().persist(dbfb); - functionEvent.setFunctionBean(dbfb); - } - for (LocomotiveFunctionEventListener fl : trackService.locomotiveFunctionEventListeners) { - fl.onFunctionChange(functionEvent); - } - } - } - } - } - - private class LocomotiveDirectionChangeEventListener implements LocomotiveDirectionEventListener { - - private final JCSCommandStationImpl trackService; - - LocomotiveDirectionChangeEventListener(JCSCommandStationImpl trackService) { - this.trackService = trackService; - } - - @Override - public void onDirectionChange(LocomotiveDirectionEvent directionEvent) { - LocomotiveBean lb = directionEvent.getLocomotiveBean(); - if (lb != null) { - LocomotiveBean dblb = null; - //For marklin and Ecos use the ID - if ("marklin.cs".equals(lb.getCommandStationId()) || "esu-ecos".equals(lb.getCommandStationId())) { - dblb = PersistenceFactory.getService().getLocomotive(lb.getId()); - } else { - Integer address; - if (lb.getAddress() != null) { - address = lb.getAddress(); - } else { - address = lb.getId().intValue(); - } - if (lb.getDecoderType() != null) { - dblb = PersistenceFactory.getService().getLocomotive(address, lb.getDecoderType(), lb.getCommandStationId()); - } else { - //Try to match one... - Set protocols = PersistenceFactory.getService().getDefaultCommandStation().getSupportedProtocols(); - for (Protocol protocol : protocols) { - DecoderType decoder = DecoderType.get(protocol.getProtocol()); - dblb = PersistenceFactory.getService().getLocomotive(address, decoder, lb.getCommandStationId()); - if (dblb != null) { - break; - } - } - } - } - - if (dblb != null) { - if (!Objects.equals(dblb.getRichtung(), lb.getRichtung())) { - Integer richtung = lb.getRichtung(); - dblb.setRichtung(richtung); - PersistenceFactory.getService().persist(dblb); - - Logger.trace(dblb.getId() + ", " + dblb.getName() + ": " + dblb.getDirection().getDirection()); - - directionEvent.setLocomotiveBean(dblb); - - for (LocomotiveDirectionEventListener dl : this.trackService.locomotiveDirectionEventListeners) { - dl.onDirectionChange(directionEvent); - } - } - } else { - Logger.trace("No loc found for " + lb.toLogString()); - } - } - } - } - - private class LocomotiveSpeedChangeEventListener implements LocomotiveSpeedEventListener { - - private final JCSCommandStationImpl trackService; - - LocomotiveSpeedChangeEventListener(JCSCommandStationImpl trackService) { - this.trackService = trackService; - } - - @Override - public void onSpeedChange(LocomotiveSpeedEvent speedEvent) { - LocomotiveBean lb = speedEvent.getLocomotiveBean(); - if (lb != null) { - LocomotiveBean dblb; - //For marklin and Ecos use the ID - if ("marklin.cs".equals(lb.getCommandStationId()) || "esu-ecos".equals(lb.getCommandStationId())) { - dblb = PersistenceFactory.getService().getLocomotive(lb.getId()); - } else { - Integer address; - if (lb.getAddress() != null) { - address = lb.getAddress(); - } else { - address = lb.getId().intValue(); - } - dblb = PersistenceFactory.getService().getLocomotive(address, lb.getDecoderType(), lb.getCommandStationId()); - } - - if (dblb != null) { - Integer velocity = lb.getVelocity(); - dblb.setVelocity(velocity); - PersistenceFactory.getService().persist(dblb); - - speedEvent.setLocomotiveBean(dblb); - for (LocomotiveSpeedEventListener dl : trackService.locomotiveSpeedEventListeners) { - if (dl != null) { - dl.onSpeedChange(speedEvent); - } - } - } else { - if ("marklin.cs".equals(lb.getCommandStationId()) || "esu-ecos".equals(lb.getCommandStationId())) { - Logger.trace("No loc with id " + lb.getId() + ", " + lb.getCommandStationId()); - } else { - Logger.trace("No loc found for " + lb.toLogString()); - } - } - } - } - } - - private class ConnectionListener implements ConnectionEventListener { - - private final JCSCommandStationImpl jcsCommandStationImpl; - - ConnectionListener(JCSCommandStationImpl jcsCommandStationImpl) { - this.jcsCommandStationImpl = jcsCommandStationImpl; - } - - @Override - public void onConnectionChange(ConnectionEvent event) { - if (event.isConnected()) { - Logger.trace(event.getSource() + " has re-connected!"); - } else { - Logger.trace(event.getSource() + " is Disconnected!"); - //jcsCommandStationImpl.disconnect(); - } - } - } - -} diff --git a/src/main/java/jcs/commandStation/autopilot/AutoPilot.java b/src/main/java/jcs/commandStation/autopilot/AutoPilot.java index b86d8554..ec5a5670 100644 --- a/src/main/java/jcs/commandStation/autopilot/AutoPilot.java +++ b/src/main/java/jcs/commandStation/autopilot/AutoPilot.java @@ -457,7 +457,7 @@ public static boolean isGostDetected() { } private static void handleGhost(SensorEvent event) { - Logger.trace("Check for possible Ghost! @ Sensor " + event.getIdString()); + Logger.trace("Check for possible Ghost! @ Sensor " + event.getSensorId()); List blocks = PersistenceFactory.getService().getBlocks(); Integer sensorId = event.getSensorId(); for (BlockBean block : blocks) { @@ -487,13 +487,13 @@ private static void handleGhost(SensorEvent event) { static void handleSensorEvent(SensorEvent event) { if (event.isChanged()) { - SensorEventHandler sh = sensorHandlers.get(event.getIdString()); - Boolean registered = sh != null; //sensorHandlers.containsKey(event.getIdString()); - Logger.trace((registered ? "Registered " : "") + event.getIdString() + " has changed " + event.isChanged()); + SensorEventHandler sh = sensorHandlers.get(event.getSensorId()); + Boolean registered = sh != null; + + Logger.trace((registered ? "Registered " : "") + event.getSensorId() + " has changed " + event.isChanged()); if (sh != null) { //there is a handler registered for this id, pass the event through - //SensorEventHandler sh = sensorHandlers.get(event.getIdString()); sh.handleEvent(event); } else { //sensor is not registered and thus not expected! @@ -680,7 +680,7 @@ private static class SensorListener implements SensorEventListener { @Override public void onSensorChange(SensorEvent event) { - if (sensorId.equals(event.getIdString())) { + if (sensorId.equals(event.getSensorId())) { AutoPilot.handleSensorEvent(event); } } diff --git a/src/main/java/jcs/commandStation/autopilot/state/EnterBlockState.java b/src/main/java/jcs/commandStation/autopilot/state/EnterBlockState.java index 7addc660..bf72abfd 100644 --- a/src/main/java/jcs/commandStation/autopilot/state/EnterBlockState.java +++ b/src/main/java/jcs/commandStation/autopilot/state/EnterBlockState.java @@ -105,7 +105,7 @@ public void onSensorChange(SensorEvent sensorEvent) { if (this.inSensorId.equals(sensorEvent.getSensorId())) { if (sensorEvent.isActive()) { this.canAdvanceToNextState = true; - Logger.trace("In Event from Sensor " + sensorEvent.getIdString()); + Logger.trace("In Event from Sensor " + sensorEvent.getSensorId()); synchronized (this) { this.notifyAll(); } diff --git a/src/main/java/jcs/commandStation/autopilot/state/StartState.java b/src/main/java/jcs/commandStation/autopilot/state/StartState.java index e6cae22d..7e9ad095 100644 --- a/src/main/java/jcs/commandStation/autopilot/state/StartState.java +++ b/src/main/java/jcs/commandStation/autopilot/state/StartState.java @@ -115,7 +115,7 @@ public void onSensorChange(SensorEvent sensorEvent) { if (enterSensorId.equals(sensorEvent.getSensorId())) { if (sensorEvent.isActive()) { canAdvanceToNextState = true; - Logger.trace("Enter Event from Sensor " + sensorEvent.getIdString()); + Logger.trace("Enter Event from Sensor " + sensorEvent.getSensorId()); synchronized (this) { this.notifyAll(); } diff --git a/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java b/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java index bb006236..78e2fed3 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java @@ -712,9 +712,9 @@ public static void main(String[] a) { List feedbackModules = cs.getFeedbackModules(); Logger.trace("There are "+feedbackModules+" Feedback Modules"); for(FeedbackModuleBean fm : feedbackModules) { - Logger.trace("Module id: "+fm.getId()+" nr: "+fm.getModuleNumber()+" ports: "+fm.getPortCount()); - Logger.trace("Module id: "+fm.getId()+" S 1 id:"+fm.getSensor(0).getId()+" cid: "+fm.getSensor(0).getContactId()+" did: "+fm.getSensor(0).getDeviceId()); - Logger.trace("Module id: "+fm.getId()+" S 15 id:"+fm.getSensor(15).getId()+" cid: "+fm.getSensor(15).getContactId()+" did: "+fm.getSensor(15).getDeviceId()); + Logger.trace("Module id: "+fm.getId()+" Module nr: "+fm.getModuleNumber()+" ports: "+fm.getPortCount()+" NodeId: "+fm.getIdentifier()+" BusNr: "+fm.getBusNumber()); + Logger.trace("FBModule id: "+fm.getId()+" S 1 id:"+fm.getSensor(0).getId()+" contactId: "+fm.getSensor(0).getContactId()+" ModuleNr: "+fm.getSensor(0).getDeviceId()+" Name "+fm.getSensor(0).getName()); + Logger.trace("FBModule id: "+fm.getId()+" S 15 id:"+fm.getSensor(15).getId()+" contactId: "+fm.getSensor(15).getContactId()+" ModuleNr: "+fm.getSensor(15).getDeviceId()+" Name "+fm.getSensor(15).getName()); } // power = cs.power(true); // Logger.trace("4 Power is " + (power ? "On" : "Off")); @@ -792,13 +792,7 @@ public static void main(String[] a) { // //reply = cs.connection.sendMessage(new EcosMessage("help(65000,attribute)")); // //Logger.trace(reply.getMessage() + " ->\n" + reply.getResponse()); // - List fbml = cs.getFeedbackModules(); - for (FeedbackModuleBean fbm : fbml) { - Logger.trace(fbm); - Logger.trace("p-1 " + fbm.getSensor(0).getId()); - Logger.trace("p-15 " + fbm.getSensor(15).getId()); - } - + // // reply = cs.connection.sendMessage(new EcosMessage("request(65000,volt")); // Logger.trace(reply.getMessage() + " ->\n" + reply.getResponse()); diff --git a/src/main/java/jcs/commandStation/esu/ecos/FeedbackManager.java b/src/main/java/jcs/commandStation/esu/ecos/FeedbackManager.java index 3982bc08..ec5a89b7 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/FeedbackManager.java +++ b/src/main/java/jcs/commandStation/esu/ecos/FeedbackManager.java @@ -57,7 +57,7 @@ private List parse(EcosMessage message) { } else { feedbackModule = new FeedbackModuleBean(); feedbackModule.setId(objectId); - feedbackModule.setAddressOffset(S88_OFFSET); + feedbackModule.setAddressOffset(0); feedbackModule.setModuleNumber(objectId - S88_OFFSET); //ESU ECoS has 1 bus feedbackModule.setIdentifier(0); @@ -78,7 +78,7 @@ private List parse(EcosMessage message) { updatePorts(state, feedbackModule); } modules.put(objectId, feedbackModule); - changedSensors = feedbackModule.getChangedSensors(); + changedSensors = feedbackModule.getChangedSensorEvents(); if (event) { if (ecosCommandStation != null) { @@ -93,7 +93,7 @@ private List parse(EcosMessage message) { int size = Integer.parseInt(values.get(Ecos.SIZE).toString()); for (int i = 0; i < size; i++) { FeedbackModuleBean fbmb = new FeedbackModuleBean(); - fbmb.setAddressOffset(S88_OFFSET); + fbmb.setAddressOffset(0); fbmb.setModuleNumber(i); fbmb.setId(S88_OFFSET + i); fbmb.setPortCount(S88_DEFAULT_PORT_COUNT); diff --git a/src/main/java/jcs/commandStation/events/SensorEvent.java b/src/main/java/jcs/commandStation/events/SensorEvent.java index 7127a9cd..3cb14f62 100755 --- a/src/main/java/jcs/commandStation/events/SensorEvent.java +++ b/src/main/java/jcs/commandStation/events/SensorEvent.java @@ -42,22 +42,10 @@ public Integer getSensorId() { return sensorBean.getId(); } + @Deprecated @Override public String getIdString() { -// if (sensorBean.getIdString() != null) { return sensorBean.getId().toString(); -// } else { -// //TODO: Number format? check with both CS 3 and HSI 88 life sensors -// Integer deviceId = sensorBean.getDeviceId(); -// Integer contactId = sensorBean.getContactId(); -// String cn = ((contactId) > 9 ? "" : "0"); -// if (cn.length() == 2) { -// cn = "00" + cn; -// } else if (cn.length() == 3) { -// cn = "0" + cn; -// } -// return deviceId + "-" + cn; -// } } public Integer getDeviceId() { diff --git a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java index 6e922548..7d045f02 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java +++ b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java @@ -442,7 +442,7 @@ public InfoBean getCommandStationInfo() { @Override public List getFeedbackModules() { - //Feedbackmodules can be queried from the Link S88 if avalable. + //Feedbackmodules can be queried from the Link S88 if available. //In case of a CS 3 Plus or CS 2 there should be a node "0" which could have max 32 S88 modules. //TODO: Test with CS-3Plus and CS2. //Link S88 @@ -468,32 +468,23 @@ public List getFeedbackModules() { //Bus 1 offset 1000, Bus 2 offset 2000 and Bus 3 offset 3000 FeedbackModuleBean l = new FeedbackModuleBean(); l.setId(0); + l.setAddressOffset(0); l.setModuleNumber(0); l.setPortCount(16); l.setIdentifier(nodeId); + l.setBusNumber(0); feedbackModules.add(l); -// if (bus0len != null) { -// for (int i = 0; i < (bus0len * 16); i++) { -// SensorBean sb = new SensorBean(); -// sb.setDeviceId(deviceId); -// sb.setContactId((i + 1)); -// sb.setName("B0-S-" + (i + 1)); -// String id = sb.getIdString(); -// sensorBeans.put(id, sb); -// } -// } - - - for (int i = 0; i < bus1Len; i++) { FeedbackModuleBean b1 = new FeedbackModuleBean(); + //Use the offset plus module nr as the id b1.setId(1000+i); b1.setAddressOffset(1000); b1.setModuleNumber(i); b1.setPortCount(16); b1.setIdentifier(nodeId); + b1.setBusNumber(1); feedbackModules.add(b1); } for (int i = 0; i < bus2Len; i++) { @@ -503,6 +494,7 @@ public List getFeedbackModules() { b2.setModuleNumber(i); b2.setPortCount(16); b2.setIdentifier(nodeId); + b2.setBusNumber(2); feedbackModules.add(b2); } for (int i = 0; i < bus3Len; i++) { @@ -512,19 +504,14 @@ public List getFeedbackModules() { b3.setModuleNumber(i); b3.setPortCount(16); b3.setIdentifier(nodeId); + b3.setBusNumber(3); feedbackModules.add(b3); } - } return feedbackModules; } -// @Override -// public List getFeedbackModules() { -// List feedbackModules = new ArrayList<>(this.feedbackManager.getModules().values()); -// return feedbackModules; -// } /** * Query the System Status * @@ -1207,9 +1194,9 @@ public static void main(String[] a) { List feedbackModules = cs.getFeedbackModules(); Logger.trace("There are "+feedbackModules+" Feedback Modules"); for(FeedbackModuleBean fm : feedbackModules) { - Logger.trace("Module id: "+fm.getId()+" nr: "+fm.getModuleNumber()+" ports: "+fm.getPortCount()); - Logger.trace("Module id: "+fm.getId()+" S 1 id:"+fm.getSensor(0).getId()+" cid: "+fm.getSensor(0).getContactId()+" did: "+fm.getSensor(0).getDeviceId()); - Logger.trace("Module id: "+fm.getId()+" S 15 id:"+fm.getSensor(15).getId()+" cid: "+fm.getSensor(15).getContactId()+" did: "+fm.getSensor(15).getDeviceId()); + Logger.trace("Module id: "+fm.getId()+" Module nr: "+fm.getModuleNumber()+" ports: "+fm.getPortCount()+" NodeId: "+fm.getIdentifier()+" BusNr: "+fm.getBusNumber()); + Logger.trace("FBModule id: "+fm.getId()+" S 1 id:"+fm.getSensor(0).getId()+" contactId: "+fm.getSensor(0).getContactId()+" ModuleNr: "+fm.getSensor(0).getDeviceId()+" Name "+fm.getSensor(0).getName()); + Logger.trace("FBModule id: "+fm.getId()+" S 15 id:"+fm.getSensor(15).getId()+" contactId: "+fm.getSensor(15).getContactId()+" ModuleNr: "+fm.getSensor(15).getDeviceId()+" Name "+fm.getSensor(15).getName()); } //cs.getLocomotivesViaCAN(); diff --git a/src/main/java/jcs/commandStation/marklin/cs/can/parser/FeedbackEventMessage.java b/src/main/java/jcs/commandStation/marklin/cs/can/parser/FeedbackEventMessage.java index ab1819ea..9fc4a9cc 100644 --- a/src/main/java/jcs/commandStation/marklin/cs/can/parser/FeedbackEventMessage.java +++ b/src/main/java/jcs/commandStation/marklin/cs/can/parser/FeedbackEventMessage.java @@ -46,7 +46,7 @@ public static SensorBean parse(CanMessage message, Date eventDate) { Integer millis = ByteUtil.toInt(new byte[]{data[6], data[7]}) * 10; - SensorBean sensorBean = new SensorBean(contactId, null, contactId, contactId, identifier, status, previousStatus, millis, System.currentTimeMillis()); + SensorBean sensorBean = new SensorBean(contactId, null, null, null, identifier, status, previousStatus, millis, System.currentTimeMillis()); return sensorBean; } else { Logger.warn("Can't parse message, not a Sensor Response! " + resp); diff --git a/src/main/java/jcs/entities/FeedbackModuleBean.java b/src/main/java/jcs/entities/FeedbackModuleBean.java index 777c8190..9020bbca 100644 --- a/src/main/java/jcs/entities/FeedbackModuleBean.java +++ b/src/main/java/jcs/entities/FeedbackModuleBean.java @@ -18,6 +18,7 @@ import java.util.ArrayList; import java.util.List; import jcs.commandStation.events.SensorEvent; +import org.tinylog.Logger; /** * Represents 1 Feedback Module (S88) with a number of ports (usually 16) @@ -29,6 +30,7 @@ public class FeedbackModuleBean { private Integer portCount; private Integer addressOffset; private Integer identifier; + private Integer busNumber; private int[] ports; private int[] prevPorts; @@ -100,6 +102,14 @@ public void setIdentifier(Integer identifier) { this.identifier = identifier; } + public Integer getBusNumber() { + return busNumber; + } + + public void setBusNumber(Integer busNumber) { + this.busNumber = busNumber; + } + public int[] getPorts() { return ports; } @@ -142,98 +152,70 @@ public void setPrevPorts(int[] prevPorts) { this.prevPorts = prevPorts; } -// public static Integer calculateModuleNumber(int contactId) { -// int module = (contactId - 1) / 16 + 1; -// return module; -// } -// public static int calculatePortNumber(int contactId) { -// int module = (contactId - 1) / 16 + 1; -// int mport = contactId - (module - 1) * 16; -// return mport; -// } -// public static int calculateContactId(int module, int port) { -// //Bei einer CS2 errechnet sich der richtige Kontakt mit der Formel M - 1 * 16 + N -// module = module - 1; -// int contactId = module * 16; -// return contactId + port; - // } public SensorBean getSensor(int port) { - //Marklin addressOffset is 0, 1000, 2000 or 3000 - //Sensor address is addressOffset + moduleNumber * portCount + port - //ESU 1st feedbackmodule start a 100 this has portCount sensors. 100 has sensors 0 - 15. - // 2nd Module is 101 which has sensors 16 - 31 - the node can be setto d the module id address ofset is 0 - //Sensor address is addressOffset(0) + moduleNumber * portCount + port - - int sid = addressOffset + moduleNumber * portCount + port; + int sid; + int offset = 0; + String name; + if (busNumber == null || busNumber < 0) { + //Not part of a Bus. Check the Address offset if it need an offset + if (addressOffset != null) { + offset = addressOffset; + } + sid = offset + moduleNumber * portCount + port; + name = "M" + String.format("%02d", moduleNumber) + "-C" + String.format("%02d", port); + } else { + //Part of a bus, there should be an offset... + if (addressOffset != null) { + offset = addressOffset; + } else { + Logger.warn("Module connected to bus " + busNumber + " but bus address offset is not specified!"); + } + sid = offset + moduleNumber * portCount + port; + name = "B" + busNumber.toString() + "-M" + String.format("%02d", moduleNumber) + "-C" + String.format("%02d", port); + } + int status = ports[port]; int prevStatus = prevPorts[port]; SensorBean sb = new SensorBean(sid, moduleNumber, port, identifier, status, prevStatus); + sb.setName(name); return sb; } -// here are [FeedbackModuleBean{id=100, moduleNumber=0, portCount=16, addressOffset=100, identifier=0}, FeedbackModuleBean{id=101, moduleNumber=1, portCount=16, addressOffset=100, identifier=0}, FeedbackModuleBean{id=102, moduleNumber=2, portCount=16, addressOffset=100, identifier=0}] Feedback Modules -//TRACE 2025-05-12 21:05:57.782 [main] EsuEcosCommandStationImpl.main(): Module id: 100 nr: 0 ports: 16 -//TRACE 2025-05-12 21:05:57.784 [main] EsuEcosCommandStationImpl.main(): Module id: 100 S 1 id:100 cid: 0 did: 0 -//TRACE 2025-05-12 21:05:57.785 [main] EsuEcosCommandStationImpl.main(): Module id: 100 S 15 id:115 cid: 15 did: 0 -//TRACE 2025-05-12 21:05:57.785 [main] EsuEcosCommandStationImpl.main(): Module id: 101 nr: 1 ports: 16 -//TRACE 2025-05-12 21:05:57.785 [main] EsuEcosCommandStationImpl.main(): Module id: 101 S 1 id:116 cid: 0 did: 1 -//TRACE 2025-05-12 21:05:57.785 [main] EsuEcosCommandStationImpl.main(): Module id: 101 S 15 id:131 cid: 15 did: 1 -//TRACE 2025-05-12 21:05:57.785 [main] EsuEcosCommandStationImpl.main(): Module id: 102 nr: 2 ports: 16 -//TRACE 2025-05-12 21:05:57.785 [main] EsuEcosCommandStationImpl.main(): Module id: 102 S 1 id:132 cid: 0 did: 2 -//TRACE 2025-05-12 21:05:57.785 [main] EsuEcosCommandStationImpl.main(): Module id: 102 S 15 id:147 cid: 15 did: 2 -// - - - -//TRACE 2025-05-12 21:08:01.425 [main] MarklinCentralStationImpl.getFeedbackModules(): nodeId: 65, bus1Len: 2, bus2Len: 2, bus3Len: 1 -//TRACE 2025-05-12 21:08:01.429 [main] MarklinCentralStationImpl.main(): There are [FeedbackModuleBean{id=0, moduleNumber=0, portCount=16, addressOffset=0, identifier=65}, FeedbackModuleBean{id=1000, moduleNumber=0, portCount=16, addressOffset=1000, identifier=65}, FeedbackModuleBean{id=1001, moduleNumber=1, portCount=16, addressOffset=1000, identifier=65}, FeedbackModuleBean{id=2000, moduleNumber=0, portCount=16, addressOffset=2000, identifier=65}, FeedbackModuleBean{id=2001, moduleNumber=1, portCount=16, addressOffset=2000, identifier=65}, FeedbackModuleBean{id=3000, moduleNumber=0, portCount=16, addressOffset=3000, identifier=65}] Feedback Modules -//TRACE 2025-05-12 21:08:01.429 [main] MarklinCentralStationImpl.main(): Module id: 0 nr: 0 ports: 16 -//TRACE 2025-05-12 21:08:01.432 [main] MarklinCentralStationImpl.main(): Module id: 0 S 1 id:0 cid: 0 did: 0 -//TRACE 2025-05-12 21:08:01.432 [main] MarklinCentralStationImpl.main(): Module id: 0 S 15 id:15 cid: 15 did: 0 -//TRACE 2025-05-12 21:08:01.432 [main] MarklinCentralStationImpl.main(): Module id: 1000 nr: 0 ports: 16 -//TRACE 2025-05-12 21:08:01.432 [main] MarklinCentralStationImpl.main(): Module id: 1000 S 1 id:1000 cid: 0 did: 0 -//TRACE 2025-05-12 21:08:01.432 [main] MarklinCentralStationImpl.main(): Module id: 1000 S 15 id:1015 cid: 15 did: 0 -//TRACE 2025-05-12 21:08:01.432 [main] MarklinCentralStationImpl.main(): Module id: 1001 nr: 1 ports: 16 -//TRACE 2025-05-12 21:08:01.432 [main] MarklinCentralStationImpl.main(): Module id: 1001 S 1 id:1016 cid: 0 did: 1 -//TRACE 2025-05-12 21:08:01.432 [main] MarklinCentralStationImpl.main(): Module id: 1001 S 15 id:1031 cid: 15 did: 1 -//TRACE 2025-05-12 21:08:01.432 [main] MarklinCentralStationImpl.main(): Module id: 2000 nr: 0 ports: 16 -//TRACE 2025-05-12 21:08:01.432 [main] MarklinCentralStationImpl.main(): Module id: 2000 S 1 id:2000 cid: 0 did: 0 -//TRACE 2025-05-12 21:08:01.432 [main] MarklinCentralStationImpl.main(): Module id: 2000 S 15 id:2015 cid: 15 did: 0 -//TRACE 2025-05-12 21:08:01.433 [main] MarklinCentralStationImpl.main(): Module id: 2001 nr: 1 ports: 16 -//TRACE 2025-05-12 21:08:01.433 [main] MarklinCentralStationImpl.main(): Module id: 2001 S 1 id:2016 cid: 0 did: 1 -//TRACE 2025-05-12 21:08:01.433 [main] MarklinCentralStationImpl.main(): Module id: 2001 S 15 id:2031 cid: 15 did: 1 -//TRACE 2025-05-12 21:08:01.433 [main] MarklinCentralStationImpl.main(): Module id: 3000 nr: 0 ports: 16 -//TRACE 2025-05-12 21:08:01.433 [main] MarklinCentralStationImpl.main(): Module id: 3000 S 1 id:3000 cid: 0 did: 0 -//TRACE 2025-05-12 21:08:01.433 [main] MarklinCentralStationImpl.main(): Module id: 3000 S 15 id:3015 cid: 15 did: 0 - - - - - - public List getChangedSensors() { - List changedSensors = new ArrayList<>(ports.length); + public List getSensors() { + List sensors = new ArrayList<>(ports.length); + + for (int i = 0; i < ports.length; i++) { + SensorBean sb = getSensor(i); + sensors.add(sb); + } + + return sensors; + } + + public List getChangedSensors() { + List changedSensors = new ArrayList<>(ports.length); for (int i = 0; i < ports.length; i++) { if (ports[i] != prevPorts[i]) { - SensorBean sb = null; //new SensorBean(moduleNumber, i + 1, ports[i]); - SensorEvent se = new SensorEvent(sb); - changedSensors.add(se); + SensorBean sb = getSensor(i); + changedSensors.add(sb); } } return changedSensors; } - public List getSensors() { - List sensors = new ArrayList<>(ports.length); + public List getChangedSensorEvents() { + List changedSensorEvents = new ArrayList<>(ports.length); for (int i = 0; i < ports.length; i++) { if (ports[i] != prevPorts[i]) { - SensorBean sb = null; //new SensorBean(moduleNumber, i + 1, ports[i]); - sensors.add(sb); + SensorBean sb = getSensor(i); + SensorEvent se = new SensorEvent(sb); + changedSensorEvents.add(se); } } - return sensors; + return changedSensorEvents; } public String portToString() { @@ -255,3 +237,19 @@ public String toString() { } } +// +// public static Integer calculateModuleNumber(int contactId) { +// int module = (contactId - 1) / 16 + 1; +// return module; +// } +// public static int calculatePortNumber(int contactId) { +// int module = (contactId - 1) / 16 + 1; +// int mport = contactId - (module - 1) * 16; +// return mport; +// } +// public static int calculateContactId(int module, int port) { +// //Bei einer CS2 errechnet sich der richtige Kontakt mit der Formel M - 1 * 16 + N +// module = module - 1; +// int contactId = module * 16; +// return contactId + port; +// } diff --git a/src/main/java/jcs/persistence/H2PersistenceService.java b/src/main/java/jcs/persistence/H2PersistenceService.java index 81618f28..23b276df 100755 --- a/src/main/java/jcs/persistence/H2PersistenceService.java +++ b/src/main/java/jcs/persistence/H2PersistenceService.java @@ -27,7 +27,6 @@ import java.util.HashSet; import java.util.LinkedList; import java.util.List; -import java.util.Map; import java.util.Set; import javax.imageio.ImageIO; import jcs.entities.AccessoryBean; @@ -57,13 +56,17 @@ public H2PersistenceService() { imageCache = new HashMap<>(); functionImageCache = new HashMap<>(); changeSupport = new PropertyChangeSupport(this); - setJCSPropertiesAsSystemProperties(); + postInit(); } private void initConnect() { connect(); } + private void postInit() { + setJCSPropertiesAsSystemProperties(); + } + protected void connect() { Logger.debug("Connecting to: " + System.getProperty("norm.jdbcUrl") + " with db user: " + System.getProperty("norm.user")); database = new Database(); @@ -159,6 +162,12 @@ public SensorBean persist(SensorBean sensor) { return sensor; } + @Override + public List persistSensorBeans(List sensors) { + sensors.forEach(s -> persist(s)); + return sensors; + } + @Override public void remove(SensorBean sensor) { // First ensure the linked tile records are decoupled @@ -173,66 +182,15 @@ public void remove(SensorBean sensor) { } @Override - @Deprecated - public List generateSensorBeans(Integer deviceId, Integer bus0len, Integer bus1len, Integer bus2len, Integer bus3len) { - Map sensorBeans = new HashMap<>(); - - if (bus0len != null) { - for (int i = 0; i < (bus0len * 16); i++) { - SensorBean sb = new SensorBean(); - sb.setDeviceId(deviceId); - sb.setContactId((i + 1)); - sb.setName("B0-S-" + (i + 1)); - Integer id = sb.getId(); - sensorBeans.put(id, sb); - } - } - - if (bus1len != null) { - for (int i = 0; i < (bus1len * 16); i++) { - SensorBean sb = new SensorBean(); - sb.setDeviceId(deviceId); - sb.setContactId((i + 1001)); - sb.setName("B1-S-" + (i + 1001)); - Integer id = sb.getId(); - sensorBeans.put(id, sb); - } - } - - if (bus2len != null) { - for (int i = 0; i < (bus2len * 16); i++) { - SensorBean sb = new SensorBean(); - sb.setDeviceId(deviceId); - sb.setContactId((i + 2001)); - sb.setName("B2-S-" + (i + 2001)); - Integer id = sb.getId(); - sensorBeans.put(id, sb); - } - } - - if (bus3len != null) { - for (int i = 0; i < (bus3len * 16); i++) { - SensorBean sb = new SensorBean(); - sb.setContactId((i + 3001)); - sb.setName("B3-S-" + (i + 3001)); - Integer id = sb.getId(); - sensorBeans.put(id, sb); - } - } - - List existing = getSensors(); - for (SensorBean sb : existing) { - if (!sensorBeans.containsKey(sb.getId())) { - Logger.trace("Removing " + sb); - remove(sb); - } - } - - for (SensorBean sb : sensorBeans.values()) { - persist(sb); - } + public void removeAllSensors() { + // First ensure the linked tile records are decoupled + database.sql("update tiles set sensor_id = null").execute(); + // Also update the blocks + database.sql("update blocks set min_sensor_id = null").execute(); + database.sql("update blocks set plus_sensor_id = null").execute(); - return getSensors(); + int rows = database.sql("delete from sensors").execute().getRowsAffected(); + Logger.trace("All " + rows + " Sensors deleted"); } @Override @@ -672,8 +630,8 @@ public synchronized void remove(TileBean tileBean) { } @Override - public synchronized void persist(List tiles) { - List dbTiles = this.getTileBeans(); + public synchronized List persist(List tiles) { + List dbTiles = getTileBeans(); Set newTileIds = new HashSet<>(); for (TileBean tb : tiles) { newTileIds.add(tb.getId()); @@ -692,12 +650,13 @@ public synchronized void persist(List tiles) { } for (TileBean tb : tilesToRemove) { - this.remove(tb); + remove(tb); } for (TileBean tb : tiles) { persist(tb); } + return tiles; } private RouteElementBean addRelatedObjects(RouteElementBean routeElementBean) { diff --git a/src/main/java/jcs/persistence/PersistenceService.java b/src/main/java/jcs/persistence/PersistenceService.java index ddd12548..a6ea3a7a 100755 --- a/src/main/java/jcs/persistence/PersistenceService.java +++ b/src/main/java/jcs/persistence/PersistenceService.java @@ -119,6 +119,14 @@ public interface PersistenceService { */ SensorBean persist(SensorBean sensor); + /** + * Persists a list of SensorBeans + * + * @param sensors a list of SensorBeans top persist + * @return the persisted list + */ + List persistSensorBeans(List sensors); + /** * Removes a SensorBean. * @@ -127,17 +135,11 @@ public interface PersistenceService { void remove(SensorBean sensor); /** - * Generates a list of SensorBeans based on bus lengths. + * Removes all SensorBean from de persistent store.
* - * @param deviceId The device ID. - * @param bus0len Length of bus 0. - * @param bus1len Length of bus 1. - * @param bus2len Length of bus 2. - * @param bus3len Length of bus 3. - * @return A List of generated SensorBeans. + * Also references to BlockBeans and TileBeans are removed */ - @Deprecated - List generateSensorBeans(Integer deviceId, Integer bus0len, Integer bus1len, Integer bus2len, Integer bus3len); + void removeAllSensors(); // Locomotive /** @@ -370,7 +372,7 @@ public interface PersistenceService { * * @param tiles The list of TileBeans to persist. */ - void persist(List tiles); + List persist(List tiles); /** * Removes a TileBean. diff --git a/src/main/java/jcs/ui/settings/CommandStationPanel.java b/src/main/java/jcs/ui/settings/CommandStationPanel.java index b826b0b2..1cf378d6 100644 --- a/src/main/java/jcs/ui/settings/CommandStationPanel.java +++ b/src/main/java/jcs/ui/settings/CommandStationPanel.java @@ -1370,13 +1370,15 @@ private void virtualCBActionPerformed(ActionEvent evt) {//GEN-FIRST:event_virtua }//GEN-LAST:event_virtualCBActionPerformed private void recreateSensors() { - int deviceId = Integer.parseInt(this.selectedCommandStation.getFeedbackModuleIdentifier()); - Integer bus0 = this.selectedCommandStation.getFeedbackBus0ModuleCount(); - Integer bus1 = this.selectedCommandStation.getFeedbackBus1ModuleCount(); - Integer bus2 = this.selectedCommandStation.getFeedbackBus2ModuleCount(); - Integer bus3 = this.selectedCommandStation.getFeedbackBus3ModuleCount(); - PersistenceFactory.getService().generateSensorBeans(deviceId, bus0, bus1, bus2, bus3); + if (selectedCommandStation.isFeedbackSupport()) { + List feedbackModules = ((FeedbackController) selectedCommandStation).getFeedbackModules(); + PersistenceFactory.getService().removeAllSensors(); + + for (FeedbackModuleBean fm : feedbackModules) { + PersistenceFactory.getService().persistSensorBeans(fm.getSensors()); + } + } } @Override diff --git a/src/test/java/jcs/commandStation/autopilot/AutoPilotTest.java b/src/test/java/jcs/commandStation/autopilot/AutoPilotTest.java index 5164833e..ad4cd0a2 100644 --- a/src/test/java/jcs/commandStation/autopilot/AutoPilotTest.java +++ b/src/test/java/jcs/commandStation/autopilot/AutoPilotTest.java @@ -595,7 +595,7 @@ private class TestSensorHandler implements SensorEventHandler { @Override public void handleEvent(SensorEvent event) { - if (this.sensorId.equals(event.getIdString())) { + if (this.sensorId.equals(event.getSensorId())) { this.autoPilotTest.sensorHandlerEvents.add(event); } } diff --git a/src/test/java/jcs/commandStation/autopilot/state/StateMachineStepByStepTest.java b/src/test/java/jcs/commandStation/autopilot/state/StateMachineStepByStepTest.java index f0574b14..abde0114 100644 --- a/src/test/java/jcs/commandStation/autopilot/state/StateMachineStepByStepTest.java +++ b/src/test/java/jcs/commandStation/autopilot/state/StateMachineStepByStepTest.java @@ -179,7 +179,7 @@ private void pause(int millis) { } } - //@Test + @Test @Order(1) public void testBk1ToBk4() { //StateMachine functionality test, runs in 1 single thread. @@ -278,7 +278,7 @@ public void testBk1ToBk4() { //Now lets Toggle the enter sensor Integer enterSensorId = dispatcher.getEnterSensorId(); - assertEquals("0-0013", enterSensorId); + assertEquals(13, enterSensorId); //Check if the enterSensor is registered a a "knownEvent" else we get a Ghost! assertTrue(AutoPilot.isSensorHandlerRegistered(enterSensorId)); @@ -312,7 +312,7 @@ public void testBk1ToBk4() { //Now lets Toggle the in sensor Integer inSensorId = dispatcher.getInSensorId(); - assertEquals("0-0012", inSensorId); + assertEquals(12, inSensorId); //Check if the inSensor is registered a a "knownEvent" else we get a Ghost! assertTrue(AutoPilot.isSensorHandlerRegistered(inSensorId)); @@ -362,7 +362,7 @@ public void testBk1ToBk4() { assertEquals("IdleState", stateMachine.getDispatcherStateName()); } - //@Test + @Test @Order(2) public void testFromBk1ToBk4andViceVersa() { Logger.info("fromBk1ToBk4andViceVersa"); @@ -453,10 +453,10 @@ public void testFromBk1ToBk4andViceVersa() { assertNotNull(enterSensorId); assertNotNull(inSensorId); - assertEquals("0-0001", occupancySensorId); - assertEquals("0-0002", exitSensorId); - assertEquals("0-0013", enterSensorId); - assertEquals("0-0012", inSensorId); + assertEquals(1, occupancySensorId); + assertEquals(2, exitSensorId); + assertEquals(13, enterSensorId); + assertEquals(12, inSensorId); //Execute the StartState stateMachine.handleState(); @@ -476,7 +476,7 @@ public void testFromBk1ToBk4andViceVersa() { assertEquals("StartState", stateMachine.getDispatcherStateName()); //Now lets Toggle the enter sensor - assertEquals("0-0013", enterSensorId); + assertEquals(13, enterSensorId); //Check if the enterSensor is registered a a "knownEvent" else we get a Ghost! assertTrue(AutoPilot.isSensorHandlerRegistered(enterSensorId)); @@ -509,7 +509,7 @@ public void testFromBk1ToBk4andViceVersa() { assertEquals("EnterBlockState", stateMachine.getDispatcherStateName()); //Now lets Toggle the in sensor - assertEquals("0-0012", inSensorId); + assertEquals(12, inSensorId); //Check if the inSensor is registered a a "knownEvent" else we get a Ghost! assertTrue(AutoPilot.isSensorHandlerRegistered(inSensorId)); @@ -599,10 +599,10 @@ public void testFromBk1ToBk4andViceVersa() { assertNotNull(enterSensorId); assertNotNull(inSensorId); - assertEquals("0-0001", inSensorId); - assertEquals("0-0002", enterSensorId); - assertEquals("0-0013", exitSensorId); - assertEquals("0-0012", occupancySensorId); + assertEquals(1, inSensorId); + assertEquals(2, enterSensorId); + assertEquals(13, exitSensorId); + assertEquals(12, occupancySensorId); assertEquals("StartState", stateMachine.getDispatcherStateName()); @@ -703,6 +703,7 @@ public void testFromBk1ToBk4andViceVersa() { assertEquals("IdleState", stateMachine.getDispatcherStateName()); } + //TODO !!!!!! //@Test @Order(3) public void testFromBk1ToBk4Gost() { @@ -801,7 +802,7 @@ public void testFromBk1ToBk4Gost() { assertTrue(JCS.getJcsCommandStation().isPowerOn()); Integer inSensorId = dispatcher.getInSensorId(); - assertNotEquals("0-0013", inSensorId); + assertNotEquals(13, inSensorId); //Check if the enterSensor is registered a a "knownEvent" else we get a Ghost! assertFalse(AutoPilot.isSensorHandlerRegistered(inSensorId)); diff --git a/src/test/java/jcs/entities/FeedbackModuleBeanTest.java b/src/test/java/jcs/entities/FeedbackModuleBeanTest.java index 8de9ad62..c20e233a 100644 --- a/src/test/java/jcs/entities/FeedbackModuleBeanTest.java +++ b/src/test/java/jcs/entities/FeedbackModuleBeanTest.java @@ -15,17 +15,13 @@ */ package jcs.entities; +import java.util.ArrayList; import java.util.List; -import jcs.commandStation.events.SensorEvent; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; -/** - * - * @author frans - */ public class FeedbackModuleBeanTest { public FeedbackModuleBeanTest() { @@ -209,8 +205,8 @@ public void testGetPrevPorts() { } @Test - public void testGetSensor() { - System.out.println("getSensor"); + public void testGetSensorMarklin() { + System.out.println("getSensorMarklin"); int port = 1; FeedbackModuleBean instance = new FeedbackModuleBean(); instance.setId(0); @@ -218,6 +214,7 @@ public void testGetSensor() { instance.setPortCount(16); instance.setAddressOffset(1000); instance.setIdentifier(65); + instance.setBusNumber(1); SensorBean expResult = new SensorBean(); expResult.setId(1001); @@ -227,13 +224,10 @@ public void testGetSensor() { expResult.setNodeId(65); expResult.setStatus(0); expResult.setPreviousStatus(0); - expResult.setName("00-0001"); + expResult.setName("B1-M00-C01"); SensorBean result = instance.getSensor(port); assertEquals(expResult, result); - -//expected: -// but was: } @Test @@ -245,7 +239,7 @@ public void testGetSensorEsu() { instance.setModuleNumber(1); instance.setPortCount(16); instance.setAddressOffset(0); - instance.setIdentifier(101); + instance.setIdentifier(null); instance.setPortValue(5, true); SensorBean expResult = new SensorBean(); @@ -253,56 +247,76 @@ public void testGetSensorEsu() { expResult.setContactId(5); expResult.setDeviceId(1); - expResult.setNodeId(101); + expResult.setNodeId(null); expResult.setStatus(1); expResult.setPreviousStatus(0); - expResult.setName("01-0005"); + expResult.setName("M01-C05"); SensorBean result = instance.getSensor(port); assertEquals(expResult, result); - -//expected: -// but was: - } - - - //@Test - public void testGetChangedSensors() { - System.out.println("getChangedSensors"); - FeedbackModuleBean instance = new FeedbackModuleBean(); - List expResult = null; - List result = instance.getChangedSensors(); - assertEquals(expResult, result); - fail("The test case is a prototype."); } - //@Test + @Test public void testGetSensors() { System.out.println("getSensors"); FeedbackModuleBean instance = new FeedbackModuleBean(); - List expResult = null; + instance.setId(102); + instance.setIdentifier(0); + instance.setModuleNumber(2); + instance.setPortCount(FeedbackModuleBean.DEFAULT_PORT_COUNT); + instance.setAddressOffset(0); + + List expResult = new ArrayList<>(); + + for (int i = 0; i < FeedbackModuleBean.DEFAULT_PORT_COUNT; i++) { + SensorBean sb = new SensorBean(); + sb.setId(2 * FeedbackModuleBean.DEFAULT_PORT_COUNT + i); + sb.setContactId(i); + sb.setDeviceId(2); + sb.setStatus(0); + sb.setNodeId(0); + sb.setPreviousStatus(0); + sb.setName("M02-C" + String.format("%02d", i)); + expResult.add(sb); + } + List result = instance.getSensors(); assertEquals(expResult, result); - fail("The test case is a prototype."); } - //@Test - public void testPortToString() { - System.out.println("portToString"); + @Test + public void testGetChangedSensors() { + System.out.println("getChangedSensors"); + int port = 5; FeedbackModuleBean instance = new FeedbackModuleBean(); - String expResult = ""; - String result = instance.portToString(); + instance.setId(100); + instance.setIdentifier(0); + instance.setModuleNumber(0); + instance.setPortCount(FeedbackModuleBean.DEFAULT_PORT_COUNT); + instance.setAddressOffset(0); + + List expResult = new ArrayList<>(); + List result = instance.getChangedSensors(); + assertEquals(expResult, result); - fail("The test case is a prototype."); - } - //@Test - public void testToString() { - System.out.println("toString"); - FeedbackModuleBean instance = new FeedbackModuleBean(); - String expResult = ""; - String result = instance.toString(); + instance.setPortValue(5, true); + + result = instance.getChangedSensors(); + + SensorBean expChangedResult = new SensorBean(); + expChangedResult.setId(5); + + expChangedResult.setContactId(5); + expChangedResult.setDeviceId(0); + expChangedResult.setNodeId(0); + expChangedResult.setStatus(1); + expChangedResult.setPreviousStatus(0); + expChangedResult.setName("M00-C05"); + + expResult.add(expChangedResult); + assertEquals(expResult, result); - fail("The test case is a prototype."); } + } diff --git a/src/test/resources/autopilot_test_layout.sql b/src/test/resources/autopilot_test_layout.sql index 4e5f7acb..6d366d0e 100644 --- a/src/test/resources/autopilot_test_layout.sql +++ b/src/test/resources/autopilot_test_layout.sql @@ -48,64 +48,64 @@ commit; INSERT INTO sensors (id,name,device_id,contact_id,status,previous_status,millis,last_updated) -VALUES ('0-0002','B0-S-2',0,2,0,1,NULL,NULL), - ('0-0013','B0-S-13',0,13,0,1,NULL,NULL), - ('0-0001','B0-S-1',0,1,0,1,0,NULL), - ('0-0012','B0-S-12',0,12,0,1,NULL,NULL), - ('0-0004','B0-S-4',0,4,0,1,NULL,NULL), - ('0-0015','B0-S-15',0,15,0,NULL,NULL,NULL), - ('0-0003','B0-S-3',0,3,0,1,0,NULL), - ('0-0014','B0-S-14',0,14,0,NULL,NULL,NULL), - ('0-0006','B0-S-6',0,6,0,NULL,NULL,NULL), - ('0-0005','B0-S-5',0,5,0,NULL,NULL,NULL); +VALUES (2,'M00-C02',0,2,0,1,NULL,NULL), + (13,'M00-C13',0,13,0,1,NULL,NULL), + (1,'M00-C01',0,1,0,1,0,NULL), + (12,'M00-C12',0,12,0,1,NULL,NULL), + (4,'M00-C04',0,4,0,1,NULL,NULL), + (15,'M00-C15',0,15,0,NULL,NULL,NULL), + (3,'M00-C03',0,3,0,1,0,NULL), + (14,'M00-C14',0,14,0,NULL,NULL,NULL), + (6,'M00-C06',0,6,0,NULL,NULL,NULL), + (5,'M00-C05',0,5,0,NULL,NULL,NULL); INSERT INTO sensors (id,name,device_id,contact_id,status,previous_status,millis,last_updated) -VALUES ('0-0016','B0-S-16',0,16,0,NULL,NULL,NULL), - ('0-0008','B0-S-8',0,8,0,NULL,NULL,NULL), - ('0-0007','B0-S-7',0,7,0,NULL,NULL,NULL), - ('0-0009','B0-S-9',0,9,0,NULL,NULL,NULL), - ('0-0011','B0-S-11',0,11,0,1,1,null), - ('0-0010','B0-S-10',0,10,0,1,1,null); +VALUES (16,'M00-C16',0,16,0,NULL,NULL,NULL), + (8,'M00-C08',0,8,0,NULL,NULL,NULL), + (7,'M00-C07',0,7,0,NULL,NULL,NULL), + (9,'M00-C09',0,9,0,NULL,NULL,NULL), + (11,'M00-C11',0,11,0,1,1,null), + (10,'M00-C10',0,10,0,1,1,null); commit; INSERT INTO tiles (id,tile_type,orientation,direction,x,y,signal_type,accessory_id,sensor_id) VALUES - ('se-1','Sensor','East','Center',260,60,NULL,NULL,'0-0001'), + ('se-1','Sensor','East','Center',260,60,NULL,NULL,1), ('ct-2','Curved','South','Center',500,60,NULL,NULL,NULL), ('sw-1','Switch','West','Left',580,100,NULL,'001',NULL), ('bk-2','Block','East','Center',340,100,NULL,NULL,NULL), - ('se-2','Sensor','East','Center',420,60,NULL,NULL,'0-0002'), + ('se-2','Sensor','East','Center',420,60,NULL,NULL,2), ('st-2','Straight','East','Center',460,60,NULL,NULL,NULL), ('sw-2','Switch','East','Right',500,100,NULL,'002',NULL), ('st-5','Straight','West','Center',220,100,NULL,NULL,NULL), ('st-4','Straight','East','Center',540,100,NULL,NULL,NULL), - ('se-4','Sensor','East','Center',420,100,NULL,NULL,'0-0004'); + ('se-4','Sensor','East','Center',420,100,NULL,NULL,4); INSERT INTO tiles (id,tile_type,orientation,direction,x,y,signal_type,accessory_id,sensor_id) VALUES ('st-1','Straight','East','Center',220,60,NULL,NULL,NULL), ('bk-3','Block','East','Center',740,60,NULL,NULL,NULL), - ('se-3','Sensor','East','Center',260,100,NULL,NULL,'0-0003'), + ('se-3','Sensor','East','Center',260,100,NULL,NULL,3), ('bk-1','Block','West','Center',340,60,NULL,NULL,NULL), ('ct-1','Curved','East','Center',580,60,NULL,NULL,NULL), ('st-3','Straight','East','Center',460,100,NULL,NULL,NULL), ('st-11','Straight','West','Center',860,60,NULL,NULL,NULL), ('st-13','Straight','West','Center',620,60,NULL,NULL,NULL), ('st-14','Straight','West','Center',860,100,NULL,NULL,NULL), - ('se-5','Sensor','West','Center',660,60,NULL,NULL,'0-0011'); + ('se-5','Sensor','West','Center',660,60,NULL,NULL,11); INSERT INTO tiles (id,tile_type,orientation,direction,x,y,signal_type,accessory_id,sensor_id) VALUES - ('se-6','Sensor','West','Center',820,60,NULL,NULL,'0-0010'), + ('se-6','Sensor','West','Center',820,60,NULL,NULL,10), ('et-5','End','West','Center',180,60,NULL,NULL,NULL), - ('se-9','Sensor','West','Center',820,100,NULL,NULL,'0-0012'), + ('se-9','Sensor','West','Center',820,100,NULL,NULL,12), ('et-7','End','East','Center',900,100,NULL,NULL,NULL), ('et-6','End','East','Center',900,60,NULL,NULL,NULL), ('et-8','End','West','Center',180,100,NULL,NULL,NULL), - ('se-10','Sensor','West','Center',660,100,NULL,NULL,'0-0013'), + ('se-10','Sensor','West','Center',660,100,NULL,NULL,13), ('st-17','Straight','West','Center',620,100,NULL,NULL,NULL), ('bk-4','Block','West','Center',740,100,NULL,NULL,NULL); commit; INSERT INTO blocks (id,tile_id,description,plus_sensor_id,min_sensor_id,plus_signal_id,min_signal_id,locomotive_id,reverse_arrival_side,status,incoming_suffix, always_stop) VALUES - ('bk-1','bk-1','Blok 1','0-0001','0-0002',NULL,NULL,NULL,false,'Free',NULL,true), - ('bk-2','bk-2','Blok 2','0-0004','0-0003',NULL,NULL,NULL,false,'Free',null,true), - ('bk-3','bk-3','Blok 3','0-0010','0-0011',NULL,NULL,NULL,false,'Free',null,true), - ('bk-4','bk-4','Blok 4','0-0013','0-0012',NULL,NULL,NULL,false,'Free',NULL,true); + ('bk-1','bk-1','Blok 1',1,2,NULL,NULL,NULL,false,'Free',NULL,true), + ('bk-2','bk-2','Blok 2',4,3,NULL,NULL,NULL,false,'Free',null,true), + ('bk-3','bk-3','Blok 3',10,11,NULL,NULL,NULL,false,'Free',null,true), + ('bk-4','bk-4','Blok 4',13,12,NULL,NULL,NULL,false,'Free',NULL,true); commit; From 06c7cfd62a135207294717c0ccd6cd3d0132a633 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Sun, 18 May 2025 12:43:45 +0200 Subject: [PATCH 62/70] More refactoring added command_station_id to sensors --- .../esu/ecos/FeedbackManager.java | 16 + .../marklin/cs/MarklinCentralStationImpl.java | 30 +- .../cs/can/parser/FeedbackEventMessage.java | 4 +- .../virtual/VirtualCommandStationImpl.java | 40 +- .../java/jcs/entities/FeedbackModuleBean.java | 20 +- src/main/java/jcs/entities/SensorBean.java | 36 +- .../jcs/persistence/H2PersistenceService.java | 5 + .../jcs/persistence/PersistenceService.java | 6 + .../ui/settings/CommandStationDialog1.form | 548 +++++++++++++++++ .../ui/settings/CommandStationDialog1.java | 582 ++++++++++++++++++ .../jcs/ui/settings/CommandStationPanel.java | 2 +- src/main/resources/media/branch-24.png | Bin 0 -> 484 bytes src/main/resources/media/chat-24.png | Bin 0 -> 538 bytes src/main/resources/media/controller-24.png | Bin 309 -> 0 bytes .../resources/media/controller-console-24.png | Bin 0 -> 1269 bytes src/main/resources/media/spanner-24.png | Bin 0 -> 575 bytes .../resources/media/train-controller-24.png | Bin 0 -> 532 bytes src/main/resources/update-jcs-db-002.sql | 3 + .../ecos/EsuEcosCommandStationImplTest.java | 42 -- .../persistence/PersistenceServiceTest.java | 8 +- src/test/resources/autopilot_test_layout.sql | 37 +- src/test/resources/ecos_test_data.sql | 36 +- src/test/resources/jcs-test-data-h2.sql | 6 +- 23 files changed, 1271 insertions(+), 150 deletions(-) create mode 100644 src/main/java/jcs/ui/settings/CommandStationDialog1.form create mode 100644 src/main/java/jcs/ui/settings/CommandStationDialog1.java create mode 100755 src/main/resources/media/branch-24.png create mode 100755 src/main/resources/media/chat-24.png delete mode 100755 src/main/resources/media/controller-24.png create mode 100755 src/main/resources/media/controller-console-24.png create mode 100755 src/main/resources/media/spanner-24.png create mode 100755 src/main/resources/media/train-controller-24.png diff --git a/src/main/java/jcs/commandStation/esu/ecos/FeedbackManager.java b/src/main/java/jcs/commandStation/esu/ecos/FeedbackManager.java index ec5a89b7..85f87512 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/FeedbackManager.java +++ b/src/main/java/jcs/commandStation/esu/ecos/FeedbackManager.java @@ -33,6 +33,8 @@ class FeedbackManager { public static final int S88_OFFSET = 100; public static final int S88_DEFAULT_PORT_COUNT = 16; + private static final String ESU_ECOS_CS = "esu-ecos"; + private final EsuEcosCommandStationImpl ecosCommandStation; private final Map modules; @@ -61,6 +63,12 @@ private List parse(EcosMessage message) { feedbackModule.setModuleNumber(objectId - S88_OFFSET); //ESU ECoS has 1 bus feedbackModule.setIdentifier(0); + //In Unit Testcase the command station is null + if (ecosCommandStation != null) { + feedbackModule.setCommandStationId(ecosCommandStation.getCommandStationBean().getId()); + } else { + feedbackModule.setCommandStationId(ESU_ECOS_CS); + } } if (values.containsKey(Ecos.PORTS)) { @@ -98,6 +106,14 @@ private List parse(EcosMessage message) { fbmb.setId(S88_OFFSET + i); fbmb.setPortCount(S88_DEFAULT_PORT_COUNT); fbmb.setIdentifier(0); + + //In Unit Testcase the command station is null + if (ecosCommandStation != null) { + fbmb.setCommandStationId(ecosCommandStation.getCommandStationBean().getId()); + } else { + fbmb.setCommandStationId(ESU_ECOS_CS); + } + modules.put(fbmb.getId(), fbmb); } } diff --git a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java index 7d045f02..d2e2576f 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java +++ b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java @@ -468,43 +468,49 @@ public List getFeedbackModules() { //Bus 1 offset 1000, Bus 2 offset 2000 and Bus 3 offset 3000 FeedbackModuleBean l = new FeedbackModuleBean(); l.setId(0); - + l.setAddressOffset(0); l.setModuleNumber(0); l.setPortCount(16); l.setIdentifier(nodeId); l.setBusNumber(0); + l.setCommandStationId(commandStationBean.getId()); feedbackModules.add(l); - + for (int i = 0; i < bus1Len; i++) { FeedbackModuleBean b1 = new FeedbackModuleBean(); //Use the offset plus module nr as the id - b1.setId(1000+i); + b1.setId(1000 + i); b1.setAddressOffset(1000); b1.setModuleNumber(i); b1.setPortCount(16); b1.setIdentifier(nodeId); b1.setBusNumber(1); + b1.setCommandStationId(commandStationBean.getId()); feedbackModules.add(b1); } for (int i = 0; i < bus2Len; i++) { FeedbackModuleBean b2 = new FeedbackModuleBean(); - b2.setId(2000+i); + b2.setId(2000 + i); b2.setAddressOffset(2000); b2.setModuleNumber(i); b2.setPortCount(16); b2.setIdentifier(nodeId); b2.setBusNumber(2); + b2.setCommandStationId(commandStationBean.getId()); + feedbackModules.add(b2); } for (int i = 0; i < bus3Len; i++) { FeedbackModuleBean b3 = new FeedbackModuleBean(); - b3.setId(3000+i); + b3.setId(3000 + i); b3.setAddressOffset(3000); b3.setModuleNumber(i); b3.setPortCount(16); b3.setIdentifier(nodeId); b3.setBusNumber(3); + b3.setCommandStationId(commandStationBean.getId()); + feedbackModules.add(b3); } } @@ -1191,13 +1197,13 @@ public static void main(String[] a) { // // Logger.debug("Switch Accessory 2 to Green"); //cs.switchAccessory(2, AccessoryValue.GREEN, 250); - List feedbackModules = cs.getFeedbackModules(); - Logger.trace("There are "+feedbackModules+" Feedback Modules"); - for(FeedbackModuleBean fm : feedbackModules) { - Logger.trace("Module id: "+fm.getId()+" Module nr: "+fm.getModuleNumber()+" ports: "+fm.getPortCount()+" NodeId: "+fm.getIdentifier()+" BusNr: "+fm.getBusNumber()); - Logger.trace("FBModule id: "+fm.getId()+" S 1 id:"+fm.getSensor(0).getId()+" contactId: "+fm.getSensor(0).getContactId()+" ModuleNr: "+fm.getSensor(0).getDeviceId()+" Name "+fm.getSensor(0).getName()); - Logger.trace("FBModule id: "+fm.getId()+" S 15 id:"+fm.getSensor(15).getId()+" contactId: "+fm.getSensor(15).getContactId()+" ModuleNr: "+fm.getSensor(15).getDeviceId()+" Name "+fm.getSensor(15).getName()); - } + List feedbackModules = cs.getFeedbackModules(); + Logger.trace("There are " + feedbackModules + " Feedback Modules"); + for (FeedbackModuleBean fm : feedbackModules) { + Logger.trace("Module id: " + fm.getId() + " Module nr: " + fm.getModuleNumber() + " ports: " + fm.getPortCount() + " NodeId: " + fm.getIdentifier() + " BusNr: " + fm.getBusNumber()); + Logger.trace("FBModule id: " + fm.getId() + " S 1 id:" + fm.getSensor(0).getId() + " contactId: " + fm.getSensor(0).getContactId() + " ModuleNr: " + fm.getSensor(0).getDeviceId() + " Name " + fm.getSensor(0).getName()); + Logger.trace("FBModule id: " + fm.getId() + " S 15 id:" + fm.getSensor(15).getId() + " contactId: " + fm.getSensor(15).getContactId() + " ModuleNr: " + fm.getSensor(15).getDeviceId() + " Name " + fm.getSensor(15).getName()); + } //cs.getLocomotivesViaCAN(); //cs.getAccessoriesViaCan(); diff --git a/src/main/java/jcs/commandStation/marklin/cs/can/parser/FeedbackEventMessage.java b/src/main/java/jcs/commandStation/marklin/cs/can/parser/FeedbackEventMessage.java index 9fc4a9cc..5d400446 100644 --- a/src/main/java/jcs/commandStation/marklin/cs/can/parser/FeedbackEventMessage.java +++ b/src/main/java/jcs/commandStation/marklin/cs/can/parser/FeedbackEventMessage.java @@ -27,6 +27,8 @@ */ public class FeedbackEventMessage { + private static final String MARKLIN_CS = "marklin.cs"; + public static SensorBean parse(CanMessage message, Date eventDate) { CanMessage resp; if (!message.isResponseMessage()) { @@ -46,7 +48,7 @@ public static SensorBean parse(CanMessage message, Date eventDate) { Integer millis = ByteUtil.toInt(new byte[]{data[6], data[7]}) * 10; - SensorBean sensorBean = new SensorBean(contactId, null, null, null, identifier, status, previousStatus, millis, System.currentTimeMillis()); + SensorBean sensorBean = new SensorBean(contactId, null, null, null, identifier, status, previousStatus, millis, System.currentTimeMillis(), MARKLIN_CS); return sensorBean; } else { Logger.warn("Can't parse message, not a Sensor Response! " + resp); diff --git a/src/main/java/jcs/commandStation/virtual/VirtualCommandStationImpl.java b/src/main/java/jcs/commandStation/virtual/VirtualCommandStationImpl.java index 040e8417..f83e1ece 100644 --- a/src/main/java/jcs/commandStation/virtual/VirtualCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/virtual/VirtualCommandStationImpl.java @@ -50,7 +50,8 @@ */ public class VirtualCommandStationImpl extends AbstractController implements DecoderController, AccessoryController, FeedbackController { - //private DeviceBean mainDevice; + public static final String VIRTUAL_CS = "virtual"; + private InfoBean infoBean; private DriveSimulator simulator; @@ -84,11 +85,10 @@ public synchronized boolean connect() { // mainDevice.setSerial("1"); // mainDevice.setIdentifier(this.commandStationBean.getIdString()); // mainDevice.setName(this.commandStationBean.getDescription()); - infoBean = new InfoBean(); infoBean.setProductName(commandStationBean.getDescription()); infoBean.setArticleNumber(commandStationBean.getShortName()); - infoBean.setHostname(this.getIp()); + infoBean.setHostname(getIp()); power(true); @@ -112,20 +112,6 @@ public InfoBean getCommandStationInfo() { return this.infoBean; } -// @Override -// public DeviceBean getDevice() { -// return this.mainDevice; -// } - -// @Override -// public List getDevices() { -// List devices = new ArrayList<>(); -// if (mainDevice != null) { -// devices.add(this.mainDevice); -// } -// return devices; -// } - @Override public String getIp() { return NetworkUtil.getIPv4HostAddress().getHostAddress(); @@ -255,21 +241,6 @@ public boolean isSupportTrackMeasurements() { return false; } - -// @Override -// public void switchAccessory(Integer address, AccessoryBean.AccessoryValue value) { -// switchAccessory(address, value, 200); -// } - -// @Override -// public void switchAccessory(String id, AccessoryBean.AccessoryValue value) { -// throw new UnsupportedOperationException("Not supported yet."); -// } -// @Override -// public void switchAccessory(Integer address, AccessoryBean.AccessoryValue value, Integer switchTime) { -// switchAccessory(address, "dcc", value, switchTime); -// } - @Override public void switchAccessory(Integer address, String protocol, AccessoryBean.AccessoryValue value, Integer switchTime) { if (this.power && connected) { @@ -309,11 +280,6 @@ public List getAccessories() { throw new UnsupportedOperationException("Not supported yet."); } -// @Override -// public DeviceBean getFeedbackDevice() { -// throw new UnsupportedOperationException("Not supported yet."); -// } - @Override public List getFeedbackModules() { throw new UnsupportedOperationException("Not supported yet."); diff --git a/src/main/java/jcs/entities/FeedbackModuleBean.java b/src/main/java/jcs/entities/FeedbackModuleBean.java index 9020bbca..9cdfdaa5 100644 --- a/src/main/java/jcs/entities/FeedbackModuleBean.java +++ b/src/main/java/jcs/entities/FeedbackModuleBean.java @@ -31,6 +31,7 @@ public class FeedbackModuleBean { private Integer addressOffset; private Integer identifier; private Integer busNumber; + private String commandStationId; private int[] ports; private int[] prevPorts; @@ -40,19 +41,20 @@ public class FeedbackModuleBean { public static int DEFAULT_IDENTIFIER = 0; public FeedbackModuleBean() { - this(null, null); + this(null, null, null); } - public FeedbackModuleBean(Integer id, Integer moduleNumber) { - this(id, moduleNumber, DEFAULT_PORT_COUNT, DEFAULT_ADDRESS_OFFSET, DEFAULT_IDENTIFIER); + public FeedbackModuleBean(Integer id, Integer moduleNumber, String commandStationId) { + this(id, moduleNumber, DEFAULT_PORT_COUNT, DEFAULT_ADDRESS_OFFSET, DEFAULT_IDENTIFIER, commandStationId); } - public FeedbackModuleBean(Integer id, Integer moduleNumber, Integer portCount, Integer addressOffset, Integer identifier) { + public FeedbackModuleBean(Integer id, Integer moduleNumber, Integer portCount, Integer addressOffset, Integer identifier, String commandStationId) { this.id = id; this.moduleNumber = moduleNumber; this.portCount = portCount; this.addressOffset = addressOffset; this.identifier = identifier; + this.commandStationId = commandStationId; ports = new int[portCount]; prevPorts = new int[portCount]; @@ -152,6 +154,14 @@ public void setPrevPorts(int[] prevPorts) { this.prevPorts = prevPorts; } + public String getCommandStationId() { + return commandStationId; + } + + public void setCommandStationId(String commandStationId) { + this.commandStationId = commandStationId; + } + public SensorBean getSensor(int port) { int sid; int offset = 0; @@ -177,7 +187,7 @@ public SensorBean getSensor(int port) { int status = ports[port]; int prevStatus = prevPorts[port]; - SensorBean sb = new SensorBean(sid, moduleNumber, port, identifier, status, prevStatus); + SensorBean sb = new SensorBean(sid, moduleNumber, port, identifier, status, prevStatus, commandStationId); sb.setName(name); return sb; } diff --git a/src/main/java/jcs/entities/SensorBean.java b/src/main/java/jcs/entities/SensorBean.java index 50ec67b0..b9b53162 100755 --- a/src/main/java/jcs/entities/SensorBean.java +++ b/src/main/java/jcs/entities/SensorBean.java @@ -37,24 +37,25 @@ public class SensorBean { private Integer millis; private Long lastUpdated; private Integer nodeId; + private String commandStationId; public SensorBean() { - this(null, null, null, null, null, null); + this(null, null, null, null, null, null, null); } - public SensorBean(Integer id, Integer deviceId, Integer contactId, Integer nodeId, Integer status, Integer previousStatus) { - this(id, null, deviceId, contactId, nodeId, status, previousStatus, (Integer) null, (Long) null); + public SensorBean(Integer id, Integer deviceId, Integer contactId, Integer nodeId, Integer status, Integer previousStatus, String commandStationId) { + this(id, null, deviceId, contactId, nodeId, status, previousStatus, (Integer) null, (Long) null, commandStationId); } - public SensorBean(Integer id, String name, Integer deviceId, Integer contactId, Integer nodeId, Integer status, Integer previousStatus, Integer millis) { - this(id, name, deviceId, contactId, nodeId, status, previousStatus, millis, (Long) null); + public SensorBean(Integer id, String name, Integer deviceId, Integer contactId, Integer nodeId, Integer status, Integer previousStatus, Integer millis, String commandStationId) { + this(id, name, deviceId, contactId, nodeId, status, previousStatus, millis, (Long) null, commandStationId); } - public SensorBean(Integer id, String name, Integer deviceId, Integer contactId, Integer nodeId, Integer status, Integer previousStatus, Integer millis, Date lastUpdated) { - this(id, name, deviceId, contactId, nodeId, status, previousStatus, millis, (lastUpdated != null ? lastUpdated.getTime() : null)); + public SensorBean(Integer id, String name, Integer deviceId, Integer contactId, Integer nodeId, Integer status, Integer previousStatus, Integer millis, Date lastUpdated, String commandStationId) { + this(id, name, deviceId, contactId, nodeId, status, previousStatus, millis, (lastUpdated != null ? lastUpdated.getTime() : null), commandStationId); } - public SensorBean(Integer id, String name, Integer deviceId, Integer contactId, Integer nodeId, Integer status, Integer previousStatus, Integer millis, Long lastUpdated) { + public SensorBean(Integer id, String name, Integer deviceId, Integer contactId, Integer nodeId, Integer status, Integer previousStatus, Integer millis, Long lastUpdated, String commandStationId) { this.id = id; this.name = name; this.status = status; @@ -64,6 +65,7 @@ public SensorBean(Integer id, String name, Integer deviceId, Integer contactId, this.nodeId = nodeId; this.millis = millis; this.lastUpdated = lastUpdated; + this.commandStationId = commandStationId; if (name == null) { this.name = generateName(); @@ -158,6 +160,15 @@ public void setPreviousStatus(Integer previousStatus) { this.previousStatus = previousStatus; } + @Column(name = "command_station_id", length = 255, nullable = false) + public String getCommandStationId() { + return commandStationId; + } + + public void setCommandStationId(String commandStationId) { + this.commandStationId = commandStationId; + } + @Transient public void toggle() { if (status == null) { @@ -261,6 +272,7 @@ public int hashCode() { hash = 41 * hash + Objects.hashCode(this.previousStatus); hash = 41 * hash + Objects.hashCode(this.millis); hash = 41 * hash + Objects.hashCode(this.lastUpdated); + hash = 41 * hash + Objects.hashCode(this.commandStationId); return hash; } @@ -300,6 +312,9 @@ public boolean equals(Object obj) { if (!Objects.equals(this.millis, other.millis)) { return false; } + if (!Objects.equals(this.commandStationId, other.commandStationId)) { + return false; + } return Objects.equals(this.lastUpdated, other.lastUpdated); } @@ -314,6 +329,9 @@ public boolean equalsDeviceIdAndContactId(Object obj) { return false; } final SensorBean other = (SensorBean) obj; + if (!Objects.equals(this.commandStationId, other.commandStationId)) { + return false; + } if (!Objects.equals(this.deviceId, other.deviceId)) { return false; } @@ -367,6 +385,8 @@ public String toLogString() { + millis + ", lastUpdated=" + lastUpdated + + ", commandStationId=" + + commandStationId + "}"; } } diff --git a/src/main/java/jcs/persistence/H2PersistenceService.java b/src/main/java/jcs/persistence/H2PersistenceService.java index 23b276df..7a2aba4b 100755 --- a/src/main/java/jcs/persistence/H2PersistenceService.java +++ b/src/main/java/jcs/persistence/H2PersistenceService.java @@ -943,6 +943,11 @@ public CommandStationBean getDefaultCommandStation() { return database.where("default_cs=true").first(CommandStationBean.class); } + @Override + public CommandStationBean getEnabledFeedbackProvider() { + return database.where("default_cs=false and supports_feedback=true and supports_decoder_control=false and enabled=true").first(CommandStationBean.class); + } + @Override public synchronized CommandStationBean persist(CommandStationBean commandStationBean) { CommandStationBean prev = database.where("id=?", commandStationBean.getId()).first(CommandStationBean.class); diff --git a/src/main/java/jcs/persistence/PersistenceService.java b/src/main/java/jcs/persistence/PersistenceService.java index a6ea3a7a..73bf2e5f 100755 --- a/src/main/java/jcs/persistence/PersistenceService.java +++ b/src/main/java/jcs/persistence/PersistenceService.java @@ -504,6 +504,12 @@ public interface PersistenceService { */ CommandStationBean getDefaultCommandStation(); + /** + * + * @return the enabled feedback provider + */ + CommandStationBean getEnabledFeedbackProvider(); + /** * Persists a CommandStationBean. * diff --git a/src/main/java/jcs/ui/settings/CommandStationDialog1.form b/src/main/java/jcs/ui/settings/CommandStationDialog1.form new file mode 100644 index 00000000..4788f402 --- /dev/null +++ b/src/main/java/jcs/ui/settings/CommandStationDialog1.form @@ -0,0 +1,548 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/jcs/ui/settings/CommandStationDialog1.java b/src/main/java/jcs/ui/settings/CommandStationDialog1.java new file mode 100644 index 00000000..978712fc --- /dev/null +++ b/src/main/java/jcs/ui/settings/CommandStationDialog1.java @@ -0,0 +1,582 @@ +/* + * Copyright 2025 fransjacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.settings; + +import com.fazecast.jSerialComm.SerialPort; +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import javax.swing.ComboBoxModel; +import javax.swing.DefaultComboBoxModel; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; +import jcs.JCS; +import jcs.commandStation.marklin.cs.net.CSConnectionFactory; +import jcs.entities.CommandStationBean; +import jcs.persistence.PersistenceFactory; +import org.tinylog.Logger; + +/** + * + * @author fransjacobs + */ +public class CommandStationDialog1 extends javax.swing.JDialog { + + private ComboBoxModel commandStationCBM; + private ComboBoxModel feedbackCBM; + private ComboBoxModel serialPortCBM; + private ComboBoxModel fbpSerialPortCBM; + private CommandStationBean selectedCommandStation; + private CommandStationBean selectedFeedbackProvider; + + private final ExecutorService executor; + + private CommandStationBean emptyCS; + private CommandStationBean emptyFB; + + private static final String MARKLIN_CS = "marklin.cs"; + private static final String ESU_ECOS = "esu-ecos"; + + + /** + * Creates new form CommandStationDialog1 + */ + public CommandStationDialog1(java.awt.Frame parent, boolean modal) { + super(parent, modal); + initComponents(); + this.executor = Executors.newSingleThreadExecutor(); + if (PersistenceFactory.getService() != null) { + initModels(null); + } + + } + + private void initModels(CommandStationBean selected) { + if (selected == null) { + selectedCommandStation = PersistenceFactory.getService().getDefaultCommandStation(); + } else { + selectedCommandStation = selected; + } + + if (!selectedCommandStation.isFeedbackSupport()) { + selectedFeedbackProvider = PersistenceFactory.getService().getEnabledFeedbackProvider(); + } + + List allCommandStations = PersistenceFactory.getService().getCommandStations(); + + List commandStations = new ArrayList<>(); + List feedbackProviders = new ArrayList<>(); + + for (CommandStationBean csb : allCommandStations) { + if (csb.isDecoderControlSupport()) { + commandStations.add(csb); + } else { + feedbackProviders.add(csb); + } + } + + emptyCS = new CommandStationBean(); + emptyCS.setDecoderControlSupport(true); + emptyFB = new CommandStationBean(); + emptyFB.setFeedbackSupport(true); + + commandStations.add(emptyCS); + feedbackProviders.add(emptyFB); + + if (selectedCommandStation == null) { + selectedCommandStation = emptyCS; + } + + if (selectedFeedbackProvider == null) { + selectedFeedbackProvider = emptyFB; + } + + CommandStationBean[] csba = new CommandStationBean[commandStations.size()]; + CommandStationBean[] fbpa = new CommandStationBean[feedbackProviders.size()]; + commandStations.toArray(csba); + feedbackProviders.toArray(fbpa); + + commandStationCBM = new DefaultComboBoxModel<>(csba); + commandStationCBM.setSelectedItem(selectedCommandStation); + commandStationCB.setModel(commandStationCBM); + + feedbackCBM = new DefaultComboBoxModel<>(fbpa); + feedbackCBM.setSelectedItem(selectedFeedbackProvider); + feedbackCB.setModel(feedbackCBM); + + SerialPort comPorts[] = SerialPort.getCommPorts(); + String[] ports = new String[comPorts.length]; + for (int i = 0; i < comPorts.length; i++) { + ports[i] = comPorts[i].getSystemPortName(); + } + + serialPortCBM = new DefaultComboBoxModel<>(ports); + fbpSerialPortCBM = new DefaultComboBoxModel<>(ports); + serialCB.setModel(serialPortCBM); + fbpSerialCB.setModel(fbpSerialPortCBM); + + if (CommandStationBean.ConnectionType.SERIAL == selectedCommandStation.getConnectionType()) { + String port = selectedCommandStation.getSerialPort(); + serialCB.setSelectedItem(port); + serialRB.setSelected(true); + } else { + networkRB.setSelected(true); + } + + if (CommandStationBean.ConnectionType.SERIAL == selectedFeedbackProvider.getConnectionType()) { + String port = selectedFeedbackProvider.getSerialPort(); + fbpSerialCB.setSelectedItem(port); + } + + setComponents(); + //enableFields(false); + //this.progressBar.setVisible(false); + } + + /** + * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + connectionTypeBG = new javax.swing.ButtonGroup(); + topPanel = new javax.swing.JPanel(); + mainCSPanel = new javax.swing.JPanel(); + commandStationLbl = new javax.swing.JLabel(); + commandStationCB = new javax.swing.JComboBox<>(); + ipOrPortLbl = new javax.swing.JLabel(); + ipTF = new javax.swing.JTextField(); + serialCB = new javax.swing.JComboBox<>(); + controllerLbl = new javax.swing.JLabel(); + accessoryControllerLbl = new javax.swing.JLabel(); + feedbackProviderLbl = new javax.swing.JLabel(); + discoverBtn = new javax.swing.JButton(); + networkRB = new javax.swing.JRadioButton(); + serialRB = new javax.swing.JRadioButton(); + feedbackCSPanel = new javax.swing.JPanel(); + feedbackLbl = new javax.swing.JLabel(); + feedbackCB = new javax.swing.JComboBox<>(); + secondfbpLbl = new javax.swing.JLabel(); + fbpSerialLbl = new javax.swing.JLabel(); + fbpSerialCB = new javax.swing.JComboBox<>(); + filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 23), new java.awt.Dimension(0, 23), new java.awt.Dimension(32767, 23)); + jPanel3 = new javax.swing.JPanel(); + jPanel4 = new javax.swing.JPanel(); + connectBtn = new javax.swing.JButton(); + jPanel5 = new javax.swing.JPanel(); + jScrollPane1 = new javax.swing.JScrollPane(); + jTree1 = new javax.swing.JTree(); + jPanel2 = new javax.swing.JPanel(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + + jcs.ui.swing.layout.VerticalFlowLayout verticalFlowLayout1 = new jcs.ui.swing.layout.VerticalFlowLayout(); + verticalFlowLayout1.sethAlignment(0); + topPanel.setLayout(verticalFlowLayout1); + + mainCSPanel.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT)); + + commandStationLbl.setLabelFor(commandStationCB); + commandStationLbl.setText("Command Station"); + commandStationLbl.setPreferredSize(new java.awt.Dimension(110, 17)); + mainCSPanel.add(commandStationLbl); + + commandStationCB.setPreferredSize(new java.awt.Dimension(200, 23)); + commandStationCB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + commandStationCBActionPerformed(evt); + } + }); + mainCSPanel.add(commandStationCB); + + ipOrPortLbl.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); + ipOrPortLbl.setLabelFor(ipTF); + ipOrPortLbl.setText("ip Address:"); + ipOrPortLbl.setPreferredSize(new java.awt.Dimension(105, 17)); + mainCSPanel.add(ipOrPortLbl); + + ipTF.setPreferredSize(new java.awt.Dimension(120, 23)); + ipTF.addFocusListener(new java.awt.event.FocusAdapter() { + public void focusLost(java.awt.event.FocusEvent evt) { + ipTFFocusLost(evt); + } + }); + ipTF.addMouseListener(new java.awt.event.MouseAdapter() { + public void mouseExited(java.awt.event.MouseEvent evt) { + ipTFMouseExited(evt); + } + }); + ipTF.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + ipTFActionPerformed(evt); + } + }); + mainCSPanel.add(ipTF); + + serialCB.setPreferredSize(new java.awt.Dimension(120, 23)); + serialCB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + serialCBActionPerformed(evt); + } + }); + mainCSPanel.add(serialCB); + + controllerLbl.setIcon(new javax.swing.ImageIcon(getClass().getResource("/media/controller-console-24.png"))); // NOI18N + controllerLbl.setToolTipText("Decoder Controller"); + mainCSPanel.add(controllerLbl); + + accessoryControllerLbl.setIcon(new javax.swing.ImageIcon(getClass().getResource("/media/branch-24.png"))); // NOI18N + accessoryControllerLbl.setToolTipText("Accessory Controller"); + mainCSPanel.add(accessoryControllerLbl); + + feedbackProviderLbl.setIcon(new javax.swing.ImageIcon(getClass().getResource("/media/chat-24.png"))); // NOI18N + feedbackProviderLbl.setToolTipText("Feedback Provider"); + mainCSPanel.add(feedbackProviderLbl); + + discoverBtn.setText("Discover"); + discoverBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + discoverBtnActionPerformed(evt); + } + }); + mainCSPanel.add(discoverBtn); + + connectionTypeBG.add(networkRB); + networkRB.setText("Network"); + networkRB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + networkRBActionPerformed(evt); + } + }); + mainCSPanel.add(networkRB); + + connectionTypeBG.add(serialRB); + serialRB.setText("Serialport"); + serialRB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + serialRBActionPerformed(evt); + } + }); + mainCSPanel.add(serialRB); + + topPanel.add(mainCSPanel); + + java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); + flowLayout1.setAlignOnBaseline(true); + feedbackCSPanel.setLayout(flowLayout1); + + feedbackLbl.setLabelFor(feedbackCB); + feedbackLbl.setText("Feedback Device"); + feedbackLbl.setPreferredSize(new java.awt.Dimension(110, 17)); + feedbackCSPanel.add(feedbackLbl); + + feedbackCB.setPreferredSize(new java.awt.Dimension(200, 23)); + feedbackCB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + feedbackCBActionPerformed(evt); + } + }); + feedbackCSPanel.add(feedbackCB); + + secondfbpLbl.setIcon(new javax.swing.ImageIcon(getClass().getResource("/media/chat-24.png"))); // NOI18N + secondfbpLbl.setToolTipText("Feedback Provicer"); + secondfbpLbl.setPreferredSize(new java.awt.Dimension(25, 24)); + feedbackCSPanel.add(secondfbpLbl); + + fbpSerialLbl.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); + fbpSerialLbl.setText("Serial Port:"); + fbpSerialLbl.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING); + fbpSerialLbl.setPreferredSize(new java.awt.Dimension(75, 17)); + feedbackCSPanel.add(fbpSerialLbl); + + fbpSerialCB.setPreferredSize(new java.awt.Dimension(120, 23)); + fbpSerialCB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + fbpSerialCBActionPerformed(evt); + } + }); + feedbackCSPanel.add(fbpSerialCB); + feedbackCSPanel.add(filler1); + + topPanel.add(feedbackCSPanel); + + getContentPane().add(topPanel, java.awt.BorderLayout.PAGE_START); + + javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3); + jPanel3.setLayout(jPanel3Layout); + jPanel3Layout.setHorizontalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 1083, Short.MAX_VALUE) + ); + jPanel3Layout.setVerticalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 100, Short.MAX_VALUE) + ); + + getContentPane().add(jPanel3, java.awt.BorderLayout.PAGE_END); + + connectBtn.setText("Connect"); + connectBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + connectBtnActionPerformed(evt); + } + }); + jPanel4.add(connectBtn); + + getContentPane().add(jPanel4, java.awt.BorderLayout.LINE_END); + + jPanel5.setPreferredSize(new java.awt.Dimension(200, 400)); + jPanel5.setLayout(new java.awt.BorderLayout()); + + jScrollPane1.setViewportView(jTree1); + + jPanel5.add(jScrollPane1, java.awt.BorderLayout.CENTER); + + getContentPane().add(jPanel5, java.awt.BorderLayout.LINE_START); + + javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2); + jPanel2.setLayout(jPanel2Layout); + jPanel2Layout.setHorizontalGroup( + jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 0, Short.MAX_VALUE) + ); + jPanel2Layout.setVerticalGroup( + jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 417, Short.MAX_VALUE) + ); + + getContentPane().add(jPanel2, java.awt.BorderLayout.CENTER); + + pack(); + }// //GEN-END:initComponents + + private void commandStationCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_commandStationCBActionPerformed + CommandStationBean newSelectedCommandStation = (CommandStationBean) commandStationCBM.getSelectedItem(); + + if (!selectedCommandStation.getId().equals(newSelectedCommandStation.getId())) { + try { + if (JCS.getJcsCommandStation() != null) { + JCS.getJcsCommandStation().switchPower(false); + } + if (JCS.getParentFrame() != null) { + JCS.getParentFrame().connect(false); + } + } catch (Exception e) { + Logger.error(e.getMessage()); + } + } + + selectedCommandStation = (CommandStationBean) commandStationCBM.getSelectedItem(); + + executor.execute(() -> changeDefaultCommandStation(selectedCommandStation)); + + setComponents(); + //this.enableFields(this.enableEditCB.isSelected()); + Logger.trace("Selected CS: " + this.selectedCommandStation.getDescription()); + }//GEN-LAST:event_commandStationCBActionPerformed + + private void setComponents() { + controllerLbl.setVisible(selectedCommandStation.isDecoderControlSupport()); + accessoryControllerLbl.setVisible(selectedCommandStation.isAccessoryControlSupport()); + feedbackProviderLbl.setVisible(selectedCommandStation.isFeedbackSupport()); + + discoverBtn.setVisible(selectedCommandStation.isIpAutoConfiguration()); + ipTF.setText(selectedCommandStation.getIpAddress()); + + serialCB.setVisible(CommandStationBean.ConnectionType.SERIAL == selectedCommandStation.getConnectionType()); + ipTF.setVisible(CommandStationBean.ConnectionType.NETWORK == selectedCommandStation.getConnectionType()); + + networkRB.setVisible(selectedCommandStation.getSupportedConnectionTypes().size() > 1); + serialRB.setVisible(selectedCommandStation.getSupportedConnectionTypes().size() > 1); + networkRB.setSelected(CommandStationBean.ConnectionType.NETWORK == selectedCommandStation.getConnectionType()); + + if (serialCB.isVisible()) { + ipOrPortLbl.setText("Serial Port:"); + } else { + ipOrPortLbl.setText("ip Address:"); + } + + //no main controller feedback support, enable the secondary + feedbackCB.setVisible(!selectedCommandStation.isFeedbackSupport()); + feedbackCB.setEnabled(!selectedCommandStation.isFeedbackSupport()); + feedbackLbl.setVisible(!selectedCommandStation.isFeedbackSupport()); + + secondfbpLbl.setVisible(!selectedCommandStation.isFeedbackSupport() && selectedFeedbackProvider.isFeedbackSupport() && selectedFeedbackProvider.getId() != null); + } + + private void changeDefaultCommandStation(final CommandStationBean newDefault) { + PersistenceFactory.getService().changeDefaultCommandStation(newDefault); + java.awt.EventQueue.invokeLater(() -> { + setComponents(); + }); + } + + private void persistCommandStation(final CommandStationBean commandStation) { + PersistenceFactory.getService().persist(commandStation); + setComponents(); + } + + private void discoverBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_discoverBtnActionPerformed + Logger.trace("Try to discover " + selectedCommandStation.getDescription()); + }//GEN-LAST:event_discoverBtnActionPerformed + + private void feedbackCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_feedbackCBActionPerformed + CommandStationBean newSelectedFeedbackProvider = (CommandStationBean) feedbackCBM.getSelectedItem(); + //Check if it is not the empty one + if (feedbackCB.isEnabled()) { + if (selectedFeedbackProvider != null && selectedFeedbackProvider.getId() != null && newSelectedFeedbackProvider.getId() == null) { + //Disable the curren selected provider + selectedFeedbackProvider.setEnabled(false); + PersistenceFactory.getService().persist(selectedFeedbackProvider); + selectedFeedbackProvider = newSelectedFeedbackProvider; + } else { + selectedFeedbackProvider = newSelectedFeedbackProvider; + selectedFeedbackProvider.setEnabled(newSelectedFeedbackProvider.getId() != null); + //Persist the change + PersistenceFactory.getService().persist(selectedFeedbackProvider); + } + secondfbpLbl.setVisible(selectedFeedbackProvider.isFeedbackSupport() && selectedFeedbackProvider.getId() != null); + } + }//GEN-LAST:event_feedbackCBActionPerformed + + private void serialCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_serialCBActionPerformed + String selectedPort = (String) serialCB.getSelectedItem(); + selectedCommandStation.setSerialPort(selectedPort); + persistCommandStation(selectedCommandStation); + }//GEN-LAST:event_serialCBActionPerformed + + private void fbpSerialCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fbpSerialCBActionPerformed + String selectedPort = (String) fbpSerialCB.getSelectedItem(); + selectedFeedbackProvider.setSerialPort(selectedPort); + persistCommandStation(selectedFeedbackProvider); + }//GEN-LAST:event_fbpSerialCBActionPerformed + + private void networkRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_networkRBActionPerformed + if (networkRB.isSelected()) { + selectedCommandStation.setConnectionType(CommandStationBean.ConnectionType.NETWORK); + selectedCommandStation.setSerialPort(null); + } else { + selectedCommandStation.setConnectionType(CommandStationBean.ConnectionType.SERIAL); + } + persistCommandStation(selectedCommandStation); + }//GEN-LAST:event_networkRBActionPerformed + + private void serialRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_serialRBActionPerformed + if (networkRB.isSelected()) { + selectedCommandStation.setConnectionType(CommandStationBean.ConnectionType.NETWORK); + } else { + selectedCommandStation.setConnectionType(CommandStationBean.ConnectionType.SERIAL); + } + persistCommandStation(selectedCommandStation); + }//GEN-LAST:event_serialRBActionPerformed + + private void ipTFActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ipTFActionPerformed + Logger.trace("ip Address: "+this.ipTF.getText()); + selectedCommandStation.setIpAddress(ipTF.getText()); + }//GEN-LAST:event_ipTFActionPerformed + + private void ipTFFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_ipTFFocusLost + Logger.trace("ip Address: "+this.ipTF.getText()); + selectedCommandStation.setIpAddress(ipTF.getText()); + }//GEN-LAST:event_ipTFFocusLost + + private void ipTFMouseExited(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_ipTFMouseExited + Logger.trace("ip Address: "+this.ipTF.getText()); + selectedCommandStation.setIpAddress(ipTF.getText()); + }//GEN-LAST:event_ipTFMouseExited + + private void connectBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_connectBtnActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_connectBtnActionPerformed + + + private void discover() { + //Start een wacht dialog box... + if(MARKLIN_CS.equals(selectedCommandStation.getId())) { + InetAddress csAddress = CSConnectionFactory.discoverCs(); + } else if(ESU_ECOS.equals(selectedCommandStation.getId())) { + + } + } + + + + /** + * @param args the command line arguments + */ + public static void main(String args[]) { + /* Set the FlatLightLaf look and feel */ + // + try { + UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { + Logger.warn("Can't set the LookAndFeel: " + ex); + } + // + + /* Create and display the dialog */ + java.awt.EventQueue.invokeLater(() -> { + CommandStationDialog1 dialog = new CommandStationDialog1(new javax.swing.JFrame(), true); + dialog.addWindowListener(new java.awt.event.WindowAdapter() { + @Override + public void windowClosing(java.awt.event.WindowEvent e) { + System.exit(0); + } + }); + + dialog.pack(); + dialog.setLocationRelativeTo(null); + dialog.setVisible(true); + + }); + } + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel accessoryControllerLbl; + private javax.swing.JComboBox commandStationCB; + private javax.swing.JLabel commandStationLbl; + private javax.swing.JButton connectBtn; + private javax.swing.ButtonGroup connectionTypeBG; + private javax.swing.JLabel controllerLbl; + private javax.swing.JButton discoverBtn; + private javax.swing.JComboBox fbpSerialCB; + private javax.swing.JLabel fbpSerialLbl; + private javax.swing.JComboBox feedbackCB; + private javax.swing.JPanel feedbackCSPanel; + private javax.swing.JLabel feedbackLbl; + private javax.swing.JLabel feedbackProviderLbl; + private javax.swing.Box.Filler filler1; + private javax.swing.JLabel ipOrPortLbl; + private javax.swing.JTextField ipTF; + private javax.swing.JPanel jPanel2; + private javax.swing.JPanel jPanel3; + private javax.swing.JPanel jPanel4; + private javax.swing.JPanel jPanel5; + private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JTree jTree1; + private javax.swing.JPanel mainCSPanel; + private javax.swing.JRadioButton networkRB; + private javax.swing.JLabel secondfbpLbl; + private javax.swing.JComboBox serialCB; + private javax.swing.JRadioButton serialRB; + private javax.swing.JPanel topPanel; + // End of variables declaration//GEN-END:variables + +} diff --git a/src/main/java/jcs/ui/settings/CommandStationPanel.java b/src/main/java/jcs/ui/settings/CommandStationPanel.java index 1cf378d6..580eab0a 100644 --- a/src/main/java/jcs/ui/settings/CommandStationPanel.java +++ b/src/main/java/jcs/ui/settings/CommandStationPanel.java @@ -98,7 +98,7 @@ private void initModels(CommandStationBean selected) { commandStations.add(selectedCommandStation); } - commandStationComboBoxModel = new DefaultComboBoxModel(cmdSts); + commandStationComboBoxModel = new DefaultComboBoxModel<>(cmdSts); commandStationComboBoxModel.setSelectedItem(selectedCommandStation); commandStationComboBox.setModel(commandStationComboBoxModel); diff --git a/src/main/resources/media/branch-24.png b/src/main/resources/media/branch-24.png new file mode 100755 index 0000000000000000000000000000000000000000..30433dbb7c3a8c2bc256da1b60f24b52584c8a39 GIT binary patch literal 484 zcmVPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0eMM8K~zXf?Ub=f z13?gm|GCZWq&Ojk#T6EpE~O7(5wNfnd;xs}AH-6uQY5{VWx9Z**DjENDJ=pP9)V3* z#v;4NX3->tX*3@!+|GBm|LyH?z=1yx`3q()LXoCvS(fF@P3z2@hu#=715g4$mSxAw z6abVjD5b_kGzL%rxUkkPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0k26!K~zXf?UXT# z6hRP$-@9q5hGD@C3@$r^4K^?kG!g>^1H%n8@CS&Ikv~Ggz(g~}L=mG)4244!^*}H& zxI{1zx!{5egtN!3E`!@ydYjqvE_Od?sDAajitgziV8x2#&@|0DfMKZvKvfFIMMTCS zgtH-pk-NVl`8K8Wv-F(^RUL`QGgbYgs-6!Kd8ewE%QefWRrTS5P}i4K^`I==Gw$W< zm`^%HWI}Qiz-M>gtE%djnSCL7y7VsLPK@yp0IcO|(=_WMvNbCX02fH^r<5iqC=PeO z+r@ca7}}%z65YR(@MSqcpPJVJ{SyYGaIFpc4Lg+OJhg=t4L)!umRv3fStB&-vcCC%(byr$8nDhMS zSu8d)!t#~j`UTf+trFK+SeluZet&7D%i`+~u6w-Xdme9BDwiBw3G@|%r>mdKI;Vst E09u}d%m4rY diff --git a/src/main/resources/media/controller-console-24.png b/src/main/resources/media/controller-console-24.png new file mode 100755 index 0000000000000000000000000000000000000000..8a61588980f6ac41c83916d5a56dd50ae55ed839 GIT binary patch literal 1269 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjEa{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBDAAG{;hE;^%b*2hb1<+n z3NbJPS&Tr)z$nE4G7ZRL@M4sPvx68lplX;H7}_%#SfFa6fHVjs05M1pgl1mAh%j*h z6I`{#0%imosG8wl(3eag#aZAHS8?tx|+mh4$+(B?3=B+Vo-U3d9=unl*k=eAiX1OKsk(E5w2_5{g-8jyj4>9w?MtSeVe>HF?Em3rhX*AHZzZFPd_bvVcPS`-X+B^MXMI?mz^JZ`LWfD@4xLM9$W1w z46FQVvFBTQpU0dM8_z>hf3gKwep?-QR+KKXI=E*0?YDKCYoq)`Cny{^TVr=WU_r-E z{l)bT|MkpDEKizduu0t!-e&qJZ-KnivyJQ@!iO)1GtIHqQ>-C2~XQ-_Ez@ zMtnCXN!XoScBgUOgA&gTDt8!!n?CWcIda}%;a_tDz2M%USMtD&8!pWLl($2@|thbN-F7WzL(MbvS*$8 zi?U!#z8BBtoiH+D3bTmyW#@c;Er1u}6ZA1KZ*2yyeZA6Ujsr{MrEm5|Nooh@2W>6Cr2QSby?=5)hAwn8uV+fVd3AjqPkfb4B%}JV ZZ`|$DXU!B|pYa4`W=~f?mvv4FO#ns@#-0EG literal 0 HcmV?d00001 diff --git a/src/main/resources/media/spanner-24.png b/src/main/resources/media/spanner-24.png new file mode 100755 index 0000000000000000000000000000000000000000..d89617dfa7db934c10cc921429877db4750ff856 GIT binary patch literal 575 zcmV-F0>J%=P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0n|xEK~zXf?Uk`> z6hRcmzqfPqeY4AfDFa#rjF8gO!ouPTMLPwrh;T*zfD{%Mf&>d2dl7{oDNdf{819<-9Z3(Wiz{;BuP`!j+r$lQ|2UuuwL(VIek~l?Gnk&v3dd0G(A^ugQQoII+Lms zBB>?mQMLEpwxBlZ9Q N002ovPDHLkV1oI@2I&9* literal 0 HcmV?d00001 diff --git a/src/main/resources/media/train-controller-24.png b/src/main/resources/media/train-controller-24.png new file mode 100755 index 0000000000000000000000000000000000000000..c4f61f3add2443d761fab868b5ab82f2e95a29f3 GIT binary patch literal 532 zcmV+v0_**WP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0jWtuK~zXf-IcLx z6j2byzwfx6*@G=CQu-(O4+w#zu(-m)!a^a9pxBx&P2fO;K#CMrA%ca4jg4TDE@dn% zQrHNBmiGr(WFEIWDY6N>bGLgrQkh?~y!qz6kC}PA1@1IimOT@Zr!js-p6BZ#@+QVt zLRI${nbe1W1Tc(R6UG1lh{$`AF9GCH>tF`pi*#0oT%y~CJkbsiHICjRdr894x*;2Z{596)uX62=`{d= z!C=ri2a<~_Ytd_vQrZSEt-meIY!|@P%w9#UNv{Ebb2B>z@GlBWv}+dKqKUh|25=m; zC5%ZPn%Uf-TZCKGqU)xhM_bmSTl4=LtUBZ|$*H@aMd8Ln7LgqhIgRmUbPai~g3)Mn zzpAP~?*6@gC2s`D^|CA<&StY8t$1^BMV4g`NIoHX{noqt2FWu3n*hGHcK~Hsev5~% z!cas$;qphbB_fYwLKh1w0Dz(>)>2CQBy)FvMDnk@|HNfGw(1uC2JkDTv={f^9WDUT WxQ!Z@P;LDH0000 expResult = new ArrayList<>(); -// expResult.add(db); -// -// List result = instance.getDevices(); -// assertEquals(expResult, result); -// } -// } /** * Test of getIp method, of class EsuEcosCommandStationImpl. */ diff --git a/src/test/java/jcs/persistence/PersistenceServiceTest.java b/src/test/java/jcs/persistence/PersistenceServiceTest.java index 183a1e8c..fd652e0e 100644 --- a/src/test/java/jcs/persistence/PersistenceServiceTest.java +++ b/src/test/java/jcs/persistence/PersistenceServiceTest.java @@ -101,10 +101,10 @@ public void setUp() { jcsPropertyList.add(p10); jcsPropertyList.add(p11); - SensorBean s1 = new SensorBean(1, "M1", 65, 1, null, 0, 0, 0); + SensorBean s1 = new SensorBean(1, "M1", 65, 1, null, 0, 0, 0,"marklin.cs"); sensors.add(s1); - SensorBean s2 = new SensorBean(2, "M2", 65, 2, null, 1, 1, 0); + SensorBean s2 = new SensorBean(2, "M2", 65, 2, null, 1, 1, 0,"marklin.cs"); sensors.add(s2); LocomotiveBean loco2 = new LocomotiveBean(2L, "BR 81 002", 2L, 2, "DB BR 81 008", "mm_prg", 120, 1, 0, 0, false, true, true); @@ -378,7 +378,7 @@ public void testGetSensorIntegerInteger() { @Order(8) public void testPersistSensorBean() { System.out.println("persistSensorBean"); - SensorBean sensor = new SensorBean(3, "M1P3", 0, 3, 65, 0, 1, 0); + SensorBean sensor = new SensorBean(3, "M1P3", 0, 3, 65, 0, 1, 0, "marklin.cs"); PersistenceService instance = PersistenceFactory.getService(); @@ -405,7 +405,7 @@ public void testPersistSensorBean() { @Order(9) public void testRemoveSensorBean() { System.out.println("removeSensorBean"); - SensorBean sensor = new SensorBean(4, "M1P4", 1, 4, 65, 0, 1, 0); + SensorBean sensor = new SensorBean(4, "M1P4", 1, 4, 65, 0, 1, 0,"marklin.cs"); PersistenceService instance = PersistenceFactory.getService(); diff --git a/src/test/resources/autopilot_test_layout.sql b/src/test/resources/autopilot_test_layout.sql index 6d366d0e..e82660d2 100644 --- a/src/test/resources/autopilot_test_layout.sql +++ b/src/test/resources/autopilot_test_layout.sql @@ -47,24 +47,24 @@ VALUES (39,0,1,1,'fkticon_a_001',false), commit; -INSERT INTO sensors (id,name,device_id,contact_id,status,previous_status,millis,last_updated) -VALUES (2,'M00-C02',0,2,0,1,NULL,NULL), - (13,'M00-C13',0,13,0,1,NULL,NULL), - (1,'M00-C01',0,1,0,1,0,NULL), - (12,'M00-C12',0,12,0,1,NULL,NULL), - (4,'M00-C04',0,4,0,1,NULL,NULL), - (15,'M00-C15',0,15,0,NULL,NULL,NULL), - (3,'M00-C03',0,3,0,1,0,NULL), - (14,'M00-C14',0,14,0,NULL,NULL,NULL), - (6,'M00-C06',0,6,0,NULL,NULL,NULL), - (5,'M00-C05',0,5,0,NULL,NULL,NULL); -INSERT INTO sensors (id,name,device_id,contact_id,status,previous_status,millis,last_updated) -VALUES (16,'M00-C16',0,16,0,NULL,NULL,NULL), - (8,'M00-C08',0,8,0,NULL,NULL,NULL), - (7,'M00-C07',0,7,0,NULL,NULL,NULL), - (9,'M00-C09',0,9,0,NULL,NULL,NULL), - (11,'M00-C11',0,11,0,1,1,null), - (10,'M00-C10',0,10,0,1,1,null); +INSERT INTO sensors (id,name,device_id,contact_id,status,previous_status,millis,last_updated,command_station_id) +VALUES (2,'M00-C02',0,2,0,1,NULL,NULL,'virtual'), + (13,'M00-C13',0,13,0,1,NULL,NULL,'virtual'), + (1,'M00-C01',0,1,0,1,0,NULL,'virtual'), + (12,'M00-C12',0,12,0,1,NULL,NULL,'virtual'), + (4,'M00-C04',0,4,0,1,NULL,NULL,'virtual'), + (15,'M00-C15',0,15,0,NULL,NULL,NULL,'virtual'), + (3,'M00-C03',0,3,0,1,0,NULL,'virtual'), + (14,'M00-C14',0,14,0,NULL,NULL,NULL,'virtual'), + (6,'M00-C06',0,6,0,NULL,NULL,NULL,'virtual'), + (5,'M00-C05',0,5,0,NULL,NULL,NULL,'virtual'); +INSERT INTO sensors (id,name,device_id,contact_id,status,previous_status,millis,last_updated,command_station_id) +VALUES (16,'M00-C16',0,16,0,NULL,NULL,NULL,'virtual'), + (8,'M00-C08',0,8,0,NULL,NULL,NULL,'virtual'), + (7,'M00-C07',0,7,0,NULL,NULL,NULL,'virtual'), + (9,'M00-C09',0,9,0,NULL,NULL,NULL,'virtual'), + (11,'M00-C11',0,11,0,1,1,null,'virtual'), + (10,'M00-C10',0,10,0,1,1,null,'virtual'); commit; INSERT INTO tiles (id,tile_type,orientation,direction,x,y,signal_type,accessory_id,sensor_id) VALUES @@ -108,7 +108,6 @@ INSERT INTO blocks (id,tile_id,description,plus_sensor_id,min_sensor_id,plus_sig ('bk-4','bk-4','Blok 4',13,12,NULL,NULL,NULL,false,'Free',NULL,true); commit; - INSERT INTO routes (id,from_tile_id,from_suffix,to_tile_id,to_suffix,route_color,locked,status) VALUES ('[bk-1-]->[bk-3-]','bk-1','-','bk-3','-',NULL,false,NULL), ('[bk-4+]->[bk-2+]','bk-4','+','bk-2','+',NULL,false,NULL), diff --git a/src/test/resources/ecos_test_data.sql b/src/test/resources/ecos_test_data.sql index f5fb65ea..9d723a75 100644 --- a/src/test/resources/ecos_test_data.sql +++ b/src/test/resources/ecos_test_data.sql @@ -387,23 +387,23 @@ INSERT INTO accessories (id,address,name,"type",state,states,switch_time,protoco commit; -INSERT INTO sensors (id,name,device_id,contact_id,status,previous_status,millis,last_updated,node_id) VALUES - (11,'B0-S-11',0,11,0,NULL,NULL,NULL,0), - (10,'B0-S-10',0,10,1,NULL,NULL,NULL,0), - (2,'B0-S-2',0,2,0,NULL,NULL,NULL,0), - (13,'B0-S-13',0,13,0,1,NULL,NULL,0), - (1,'B0-S-1',0,1,0,NULL,NULL,NULL,0), - (12,'B0-S-12',0,12,0,NULL,NULL,NULL,0), - (4,'B0-S-4',0,4,0,NULL,NULL,NULL,0), - (15,'B0-S-15',0,15,0,1,NULL,NULL,0), - (3,'B0-S-3',0,3,0,NULL,NULL,NULL,0), - (14,'B0-S-14',0,14,0,1,NULL,NULL,0); -INSERT INTO sensors (id,name,device_id,contact_id,status,previous_status,millis,last_updated,node_id) VALUES - (6,'B0-S-6',0,6,0,1,NULL,NULL,0), - (5,'B0-S-5',0,5,0,1,NULL,NULL,0), - (16,'B0-S-16',0,16,0,1,NULL,NULL,0), - (8,'B0-S-8',0,8,0,1,NULL,NULL,0), - (7,'B0-S-7',0,7,0,1,NULL,NULL,0), - (9,'B0-S-9',0,9,0,NULL,NULL,NULL,0); +INSERT INTO sensors (id,name,device_id,contact_id,status,previous_status,millis,last_updated,node_id, command_station_id) VALUES + (11,'B0-S-11',0,11,0,NULL,NULL,NULL,0,'esu-ecos'), + (10,'B0-S-10',0,10,1,NULL,NULL,NULL,0,'esu-ecos'), + (2,'B0-S-2',0,2,0,NULL,NULL,NULL,0,'esu-ecos'), + (13,'B0-S-13',0,13,0,1,NULL,NULL,0,'esu-ecos'), + (1,'B0-S-1',0,1,0,NULL,NULL,NULL,0,'esu-ecos'), + (12,'B0-S-12',0,12,0,NULL,NULL,NULL,0,'esu-ecos'), + (4,'B0-S-4',0,4,0,NULL,NULL,NULL,0,'esu-ecos'), + (15,'B0-S-15',0,15,0,1,NULL,NULL,0,'esu-ecos'), + (3,'B0-S-3',0,3,0,NULL,NULL,NULL,0,'esu-ecos'), + (14,'B0-S-14',0,14,0,1,NULL,NULL,0,'esu-ecos'); +INSERT INTO sensors (id,name,device_id,contact_id,status,previous_status,millis,last_updated,node_id,command_station_id) VALUES + (6,'B0-S-6',0,6,0,1,NULL,NULL,0,'esu-ecos'), + (5,'B0-S-5',0,5,0,1,NULL,NULL,0,'esu-ecos'), + (16,'B0-S-16',0,16,0,1,NULL,NULL,0,'esu-ecos'), + (8,'B0-S-8',0,8,0,1,NULL,NULL,0,'esu-ecos'), + (7,'B0-S-7',0,7,0,1,NULL,NULL,0,'esu-ecos'), + (9,'B0-S-9',0,9,0,NULL,NULL,NULL,0,'esu-ecos'); commit; diff --git a/src/test/resources/jcs-test-data-h2.sql b/src/test/resources/jcs-test-data-h2.sql index 6f41af6f..5576a4df 100755 --- a/src/test/resources/jcs-test-data-h2.sql +++ b/src/test/resources/jcs-test-data-h2.sql @@ -23,9 +23,9 @@ insert into jcs_properties(p_key,p_value) values commit; -insert into sensors (id,name,device_id,contact_id,status,previous_status,millis,last_updated,node_id) values - (1, 'M1',65,1,0,0,0,null,null), - (2, 'M2',65,2,1,1,0,null,null); +insert into sensors (id,name,device_id,contact_id,status,previous_status,millis,last_updated,node_id, command_station_id) values + (1, 'M1',65,1,0,0,0,null,null,'marklin.cs'), + (2, 'M2',65,2,1,1,0,null,null,'marklin.cs'); commit; From 437ef74ed6650ee1885d8e8536d39ca97b3bc87c Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Sun, 18 May 2025 19:19:58 +0200 Subject: [PATCH 63/70] Added discovery --- .../java/jcs/entities/CommandStationBean.java | 6 +- .../ui/settings/CommandStationDialog1.java | 71 ++++++++++++++----- 2 files changed, 58 insertions(+), 19 deletions(-) diff --git a/src/main/java/jcs/entities/CommandStationBean.java b/src/main/java/jcs/entities/CommandStationBean.java index bee8946d..820400fd 100644 --- a/src/main/java/jcs/entities/CommandStationBean.java +++ b/src/main/java/jcs/entities/CommandStationBean.java @@ -116,7 +116,11 @@ public void setConnectVia(String connectVia) { @Transient public ConnectionType getConnectionType() { - return ConnectionType.get(connectVia); + if (connectVia != null) { + return ConnectionType.get(connectVia); + } else { + return null; + } } @Transient diff --git a/src/main/java/jcs/ui/settings/CommandStationDialog1.java b/src/main/java/jcs/ui/settings/CommandStationDialog1.java index 978712fc..fd84407c 100644 --- a/src/main/java/jcs/ui/settings/CommandStationDialog1.java +++ b/src/main/java/jcs/ui/settings/CommandStationDialog1.java @@ -16,20 +16,25 @@ package jcs.ui.settings; import com.fazecast.jSerialComm.SerialPort; -import java.net.InetAddress; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import javax.swing.ComboBoxModel; import javax.swing.DefaultComboBoxModel; +import javax.swing.JOptionPane; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import jcs.JCS; +import jcs.commandStation.esu.ecos.net.EcosConnectionFactory; import jcs.commandStation.marklin.cs.net.CSConnectionFactory; import jcs.entities.CommandStationBean; import jcs.persistence.PersistenceFactory; import org.tinylog.Logger; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.net.InetAddress; +import javax.swing.JDialog; /** * @@ -48,10 +53,9 @@ public class CommandStationDialog1 extends javax.swing.JDialog { private CommandStationBean emptyCS; private CommandStationBean emptyFB; - + private static final String MARKLIN_CS = "marklin.cs"; private static final String ESU_ECOS = "esu-ecos"; - /** * Creates new form CommandStationDialog1 @@ -138,7 +142,7 @@ private void initModels(CommandStationBean selected) { networkRB.setSelected(true); } - if (CommandStationBean.ConnectionType.SERIAL == selectedFeedbackProvider.getConnectionType()) { + if (selectedFeedbackProvider.getConnectionType() != null && CommandStationBean.ConnectionType.SERIAL == selectedFeedbackProvider.getConnectionType()) { String port = selectedFeedbackProvider.getSerialPort(); fbpSerialCB.setSelectedItem(port); } @@ -434,6 +438,7 @@ private void persistCommandStation(final CommandStationBean commandStation) { private void discoverBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_discoverBtnActionPerformed Logger.trace("Try to discover " + selectedCommandStation.getDescription()); + executor.execute(() -> discover(selectedCommandStation)); }//GEN-LAST:event_discoverBtnActionPerformed private void feedbackCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_feedbackCBActionPerformed @@ -472,7 +477,7 @@ private void networkRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIR selectedCommandStation.setConnectionType(CommandStationBean.ConnectionType.NETWORK); selectedCommandStation.setSerialPort(null); } else { - selectedCommandStation.setConnectionType(CommandStationBean.ConnectionType.SERIAL); + selectedCommandStation.setConnectionType(CommandStationBean.ConnectionType.SERIAL); } persistCommandStation(selectedCommandStation); }//GEN-LAST:event_networkRBActionPerformed @@ -487,17 +492,17 @@ private void serialRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRS }//GEN-LAST:event_serialRBActionPerformed private void ipTFActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ipTFActionPerformed - Logger.trace("ip Address: "+this.ipTF.getText()); + Logger.trace("ip Address: " + this.ipTF.getText()); selectedCommandStation.setIpAddress(ipTF.getText()); }//GEN-LAST:event_ipTFActionPerformed private void ipTFFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_ipTFFocusLost - Logger.trace("ip Address: "+this.ipTF.getText()); + Logger.trace("ip Address: " + this.ipTF.getText()); selectedCommandStation.setIpAddress(ipTF.getText()); }//GEN-LAST:event_ipTFFocusLost private void ipTFMouseExited(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_ipTFMouseExited - Logger.trace("ip Address: "+this.ipTF.getText()); + Logger.trace("ip Address: " + this.ipTF.getText()); selectedCommandStation.setIpAddress(ipTF.getText()); }//GEN-LAST:event_ipTFMouseExited @@ -505,18 +510,48 @@ private void connectBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FI // TODO add your handling code here: }//GEN-LAST:event_connectBtnActionPerformed - - private void discover() { - //Start een wacht dialog box... - if(MARKLIN_CS.equals(selectedCommandStation.getId())) { - InetAddress csAddress = CSConnectionFactory.discoverCs(); - } else if(ESU_ECOS.equals(selectedCommandStation.getId())) { - + private InetAddress discover(final CommandStationBean commandStation) { + final JOptionPane optionPane = new JOptionPane("Try to discovering a " + commandStation.getDescription(), + JOptionPane.INFORMATION_MESSAGE, + JOptionPane.OK_OPTION); + + final JDialog discoverDialog = new JDialog(this, "Discovering..."); + discoverDialog.setContentPane(optionPane); + discoverDialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); + discoverDialog.pack(); + discoverDialog.setLocationRelativeTo(null); + discoverDialog.setVisible(true); + + InetAddress inetAddress = null; + if (MARKLIN_CS.equals(commandStation.getId())) { + inetAddress = CSConnectionFactory.discoverCs(); + } else if (ESU_ECOS.equals(commandStation.getId())) { + inetAddress = EcosConnectionFactory.discoverEcos(); + } + +// optionPane.addPropertyChangeListener((PropertyChangeEvent e) -> { +// String prop = e.getPropertyName(); +// +// if (discoverDialog.isVisible() +// && (e.getSource() == optionPane) +// && (prop.equals(JOptionPane.VALUE_PROPERTY))) { +// discoverDialog.setVisible(false); +// } +// }); + if (inetAddress != null) { + Logger.trace("Discovered host " + inetAddress.getHostAddress() + " for " + commandStation.getDescription()); + commandStation.setIpAddress(inetAddress.getHostAddress()); } + + java.awt.EventQueue.invokeLater(() -> { + setComponents(); + discoverDialog.setVisible(false); + discoverDialog.dispose(); + }); + + return inetAddress; } - - - + /** * @param args the command line arguments */ From c0709e5ce51c6cc5d3b17841a04354eea331b937 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Mon, 19 May 2025 21:53:38 +0200 Subject: [PATCH 64/70] Fixed some null pointers, readded icon. Added check for network --- .../jcs/commandStation/JCSCommandStation.java | 8 ++- .../marklin/cs/MarklinCentralStationImpl.java | 12 +++- .../ui/settings/CommandStationDialog1.form | 13 +++- .../ui/settings/CommandStationDialog1.java | 63 ++++++++++++++---- src/main/resources/media/controller-24.png | Bin 0 -> 309 bytes 5 files changed, 75 insertions(+), 21 deletions(-) create mode 100644 src/main/resources/media/controller-24.png diff --git a/src/main/java/jcs/commandStation/JCSCommandStation.java b/src/main/java/jcs/commandStation/JCSCommandStation.java index 3fbcccd8..977c55a6 100755 --- a/src/main/java/jcs/commandStation/JCSCommandStation.java +++ b/src/main/java/jcs/commandStation/JCSCommandStation.java @@ -396,8 +396,12 @@ public void switchPower(boolean on) { //Logger.trace("Switch Power " + (on ? "On" : "Off")); if (decoderController != null && !AWT_THREAD.equals(Thread.currentThread().getName())) { decoderController.power(on); - } else if (decoderController != null) { - executor.execute(() -> decoderController.power(on)); + } else { + executor.execute(() -> { + if (decoderController != null) { + decoderController.power(on); + } + }); } } diff --git a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java index d2e2576f..49c1db9d 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java +++ b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java @@ -261,7 +261,9 @@ CanDevice getGFP() { InfoBean createInfoBean(Map canDevices) { InfoBean ib = new InfoBean(commandStationBean); - ib.setIpAddress(connection.getControllerAddress().getHostAddress()); + if (connection != null && connection.getControllerAddress() != null) { + ib.setIpAddress(connection.getControllerAddress().getHostAddress()); + } for (CanDevice d : canDevices.values()) { Logger.trace("Checking device: " + d); @@ -560,8 +562,12 @@ public boolean power(boolean on) { public void disconnect() { Logger.trace("Start disconnecting..."); //Stop all schedules - measurementTimer.cancel(); - watchDogTimer.cancel(); + if (measurementTimer != null) { + measurementTimer.cancel(); + } + if (watchDogTimer != null) { + watchDogTimer.cancel(); + } //Stop Threads if (executor != null) { executor.shutdown(); diff --git a/src/main/java/jcs/ui/settings/CommandStationDialog1.form b/src/main/java/jcs/ui/settings/CommandStationDialog1.form index 4788f402..37c3e654 100644 --- a/src/main/java/jcs/ui/settings/CommandStationDialog1.form +++ b/src/main/java/jcs/ui/settings/CommandStationDialog1.form @@ -22,7 +22,7 @@ - +
@@ -133,6 +133,15 @@ + + + + + + + + + @@ -466,7 +475,7 @@ - + diff --git a/src/main/java/jcs/ui/settings/CommandStationDialog1.java b/src/main/java/jcs/ui/settings/CommandStationDialog1.java index fd84407c..b7d74afb 100644 --- a/src/main/java/jcs/ui/settings/CommandStationDialog1.java +++ b/src/main/java/jcs/ui/settings/CommandStationDialog1.java @@ -31,10 +31,9 @@ import jcs.entities.CommandStationBean; import jcs.persistence.PersistenceFactory; import org.tinylog.Logger; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; import java.net.InetAddress; import javax.swing.JDialog; +import jcs.util.Ping; /** * @@ -148,6 +147,10 @@ private void initModels(CommandStationBean selected) { } setComponents(); + if (CommandStationBean.ConnectionType.NETWORK == selectedCommandStation.getConnectionType() && selectedCommandStation.getIpAddress() != null && selectedCommandStation.getIpAddress().length() > 8) { + executor.execute(() -> checkConnection(selectedCommandStation)); + } + //enableFields(false); //this.progressBar.setVisible(false); } @@ -171,6 +174,7 @@ private void initComponents() { accessoryControllerLbl = new javax.swing.JLabel(); feedbackProviderLbl = new javax.swing.JLabel(); discoverBtn = new javax.swing.JButton(); + checkBtn = new javax.swing.JButton(); networkRB = new javax.swing.JRadioButton(); serialRB = new javax.swing.JRadioButton(); feedbackCSPanel = new javax.swing.JPanel(); @@ -261,6 +265,15 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { }); mainCSPanel.add(discoverBtn); + checkBtn.setText("Check"); + checkBtn.setToolTipText("Check Connection"); + checkBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + checkBtnActionPerformed(evt); + } + }); + mainCSPanel.add(checkBtn); + connectionTypeBG.add(networkRB); networkRB.setText("Network"); networkRB.addActionListener(new java.awt.event.ActionListener() { @@ -326,7 +339,7 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { jPanel3.setLayout(jPanel3Layout); jPanel3Layout.setHorizontalGroup( jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 1083, Short.MAX_VALUE) + .addGap(0, 1113, Short.MAX_VALUE) ); jPanel3Layout.setVerticalGroup( jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -416,6 +429,12 @@ private void setComponents() { ipOrPortLbl.setText("ip Address:"); } + checkBtn.setVisible(CommandStationBean.ConnectionType.NETWORK == selectedCommandStation.getConnectionType() && selectedCommandStation.getIpAddress() != null && selectedCommandStation.getIpAddress().length() > 8); + + if (selectedCommandStation.getIpAddress() == null || selectedCommandStation.getIpAddress().length() > 8) { + ipTF.setBackground(new java.awt.Color(255, 255, 255)); + } + //no main controller feedback support, enable the secondary feedbackCB.setVisible(!selectedCommandStation.isFeedbackSupport()); feedbackCB.setEnabled(!selectedCommandStation.isFeedbackSupport()); @@ -433,7 +452,9 @@ private void changeDefaultCommandStation(final CommandStationBean newDefault) { private void persistCommandStation(final CommandStationBean commandStation) { PersistenceFactory.getService().persist(commandStation); - setComponents(); + java.awt.EventQueue.invokeLater(() -> { + setComponents(); + }); } private void discoverBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_discoverBtnActionPerformed @@ -494,22 +515,29 @@ private void serialRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRS private void ipTFActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ipTFActionPerformed Logger.trace("ip Address: " + this.ipTF.getText()); selectedCommandStation.setIpAddress(ipTF.getText()); + persistCommandStation(selectedCommandStation); }//GEN-LAST:event_ipTFActionPerformed private void ipTFFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_ipTFFocusLost Logger.trace("ip Address: " + this.ipTF.getText()); selectedCommandStation.setIpAddress(ipTF.getText()); + persistCommandStation(selectedCommandStation); }//GEN-LAST:event_ipTFFocusLost private void ipTFMouseExited(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_ipTFMouseExited Logger.trace("ip Address: " + this.ipTF.getText()); selectedCommandStation.setIpAddress(ipTF.getText()); + persistCommandStation(selectedCommandStation); }//GEN-LAST:event_ipTFMouseExited private void connectBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_connectBtnActionPerformed // TODO add your handling code here: }//GEN-LAST:event_connectBtnActionPerformed + private void checkBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_checkBtnActionPerformed + executor.execute(() -> checkConnection(selectedCommandStation)); + }//GEN-LAST:event_checkBtnActionPerformed + private InetAddress discover(final CommandStationBean commandStation) { final JOptionPane optionPane = new JOptionPane("Try to discovering a " + commandStation.getDescription(), JOptionPane.INFORMATION_MESSAGE, @@ -529,15 +557,6 @@ private InetAddress discover(final CommandStationBean commandStation) { inetAddress = EcosConnectionFactory.discoverEcos(); } -// optionPane.addPropertyChangeListener((PropertyChangeEvent e) -> { -// String prop = e.getPropertyName(); -// -// if (discoverDialog.isVisible() -// && (e.getSource() == optionPane) -// && (prop.equals(JOptionPane.VALUE_PROPERTY))) { -// discoverDialog.setVisible(false); -// } -// }); if (inetAddress != null) { Logger.trace("Discovered host " + inetAddress.getHostAddress() + " for " + commandStation.getDescription()); commandStation.setIpAddress(inetAddress.getHostAddress()); @@ -546,12 +565,27 @@ private InetAddress discover(final CommandStationBean commandStation) { java.awt.EventQueue.invokeLater(() -> { setComponents(); discoverDialog.setVisible(false); - discoverDialog.dispose(); + discoverDialog.dispose(); }); return inetAddress; } + private void checkConnection(final CommandStationBean commandStation) { + String ip = commandStation.getIpAddress(); + boolean canConnect = Ping.IsReachable(ip); + + java.awt.EventQueue.invokeLater(() -> { + if (canConnect) { + ipTF.setBackground(new java.awt.Color(204, 255, 204)); + } else { + ipTF.setBackground(new java.awt.Color(255, 255, 255)); + + JOptionPane.showMessageDialog(this, "Can't connect with host " + ip, "Can't Connect", JOptionPane.WARNING_MESSAGE); + } + }); + } + /** * @param args the command line arguments */ @@ -585,6 +619,7 @@ public void windowClosing(java.awt.event.WindowEvent e) { // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JLabel accessoryControllerLbl; + private javax.swing.JButton checkBtn; private javax.swing.JComboBox commandStationCB; private javax.swing.JLabel commandStationLbl; private javax.swing.JButton connectBtn; diff --git a/src/main/resources/media/controller-24.png b/src/main/resources/media/controller-24.png new file mode 100644 index 0000000000000000000000000000000000000000..f130ffd9a789c02d2dd019d16c40fee8115d6763 GIT binary patch literal 309 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1quc!Bd_tjv*f2Pbb~wWHJCC%(byr$8nDhMS zSu8d)!t#~j`UTf+trFK+SeluZet&7D%i`+~u6w-Xdme9BDwiBw3G@|%r>mdKI;Vst E09u}d%m4rY literal 0 HcmV?d00001 From f2503ce0072801cc86a99aa47e0dfa8847a58614 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Thu, 22 May 2025 21:25:57 +0200 Subject: [PATCH 65/70] More refactoring for the connection factories --- .../esu/ecos/AccessoryManager.java | 4 +- .../esu/ecos/EsuEcosCommandStationImpl.java | 188 ++++++++------- .../esu/ecos/net/EcosConnectionFactory.java | 168 ++++++------- .../esu/ecos/net/EcosTCPConnection.java | 50 ++-- .../marklin/cs/MarklinCentralStationImpl.java | 63 +++-- .../marklin/cs/net/CSConnectionFactory.java | 221 +++++++----------- .../ui/settings/CommandStationDialog1.form | 194 ++++++++++++++- .../ui/settings/CommandStationDialog1.java | 192 +++++++++++++-- .../cs/net/CSConnectionFactoryTest.java | 159 ------------- 9 files changed, 699 insertions(+), 540 deletions(-) delete mode 100644 src/test/java/jcs/commandStation/marklin/cs/net/CSConnectionFactoryTest.java diff --git a/src/main/java/jcs/commandStation/esu/ecos/AccessoryManager.java b/src/main/java/jcs/commandStation/esu/ecos/AccessoryManager.java index 8b91ccd2..f4e09865 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/AccessoryManager.java +++ b/src/main/java/jcs/commandStation/esu/ecos/AccessoryManager.java @@ -60,7 +60,7 @@ private void parse(EcosMessage message) { //Details accessory = parseValues(values, event); } - this.accessories.put(accessory.getId(), accessory); + accessories.put(accessory.getId(), accessory); } if (values.containsKey(Ecos.SIZE)) { @@ -122,6 +122,8 @@ private AccessoryBean parseValues(Map values, boolean event) { switch (protocol) { case "MOT" -> accessory.setProtocol(AccessoryBean.Protocol.MM); + case "MM" -> + accessory.setProtocol(AccessoryBean.Protocol.MM); case "DCC" -> accessory.setProtocol(AccessoryBean.Protocol.DCC); default -> diff --git a/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java b/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java index 78e2fed3..baf44829 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java @@ -19,6 +19,7 @@ import java.io.BufferedReader; import java.io.IOException; import java.net.InetAddress; +import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executors; @@ -53,7 +54,7 @@ import static jcs.entities.AccessoryBean.AccessoryValue.GREEN; import static jcs.entities.AccessoryBean.AccessoryValue.RED; import jcs.entities.LocomotiveBean; -import jcs.util.NetworkUtil; +import jcs.util.Ping; import org.tinylog.Logger; public class EsuEcosCommandStationImpl extends AbstractController implements DecoderController, AccessoryController, FeedbackController { @@ -99,7 +100,7 @@ public void setVirtual(boolean flag) { @Override public boolean connect() { if (!connected) { - Logger.trace("Connecting to a " + (this.virtual ? "Virtual " : "") + "ESU ECoS Command Station..."); + Logger.trace("Connecting to a " + (virtual ? "Virtual " : "") + "ESU ECoS Command Station..."); if (executor == null || executor.isShutdown()) { executor = Executors.newCachedThreadPool(); } @@ -113,79 +114,81 @@ public boolean connect() { CommandStationBean.ConnectionType conType = commandStationBean.getConnectionType(); - boolean canConnect = true; + boolean canConnect; if (conType == CommandStationBean.ConnectionType.NETWORK) { - if (commandStationBean.getIpAddress() != null) { - EcosConnectionFactory.writeLastUsedIpAddressProperty(commandStationBean.getIpAddress()); - } else { - - String ip; - if (!virtual) { - //try to discover the ECoS - InetAddress ecosAddr = EcosConnectionFactory.discoverEcos(); - ip = ecosAddr.getHostAddress(); + try { + InetAddress ecosAddr; + if (virtual) { + ecosAddr = InetAddress.getLocalHost(); } else { - ip = NetworkUtil.getIPv4HostAddress().getHostAddress(); - } - commandStationBean.setIpAddress(ip); - - EcosConnectionFactory.writeLastUsedIpAddressProperty(commandStationBean.getIpAddress()); - canConnect = ip != null; - if (!canConnect) { - Logger.error("Can't connect; IP Address not set"); + ecosAddr = InetAddress.getByName(commandStationBean.getIpAddress()); } + commandStationBean.setIpAddress(ecosAddr.getHostAddress()); + canConnect = ecosAddr.getHostAddress() != null; + } catch (UnknownHostException ex) { + Logger.error("Invalid ip address : " + commandStationBean.getIpAddress()); + return false; + } + } else { + if (virtual) { + canConnect = true; + } else { + canConnect = Ping.IsReachable(commandStationBean.getIpAddress()); } } - if (canConnect) { - connection = EcosConnectionFactory.getConnection(commandStationBean.isVirtual()); + if (!canConnect) { + Logger.error("Can't connect to " + (commandStationBean.getIpAddress() == null ? "ip Address not set" : "can't reach ip " + commandStationBean.getIpAddress())); + return false; + } - if (connection != null) { - long now = System.currentTimeMillis(); - long timeout = now + 5000L; + connection = EcosConnectionFactory.getConnection(commandStationBean); - while (!connected && now < timeout) { - connected = connection.isConnected(); - now = System.currentTimeMillis(); - } - if (!connected && now > timeout) { - Logger.error("Could not establish a connection"); - } + if (connection != null) { + long now = System.currentTimeMillis(); + long timeout = now + 5000L; - if (connected) { - //Start the EventHandler - eventMessageHandler = new EventHandler(this.connection); - eventMessageHandler.start(); + while (!connected && now < timeout) { + connected = connection.isConnected(); + now = System.currentTimeMillis(); + } + if (!connected && now > timeout) { + Logger.error("Could not establish a connection"); + } - //Obtain some info about the ECoS - initBaseObject(); + if (connected) { + //Start the EventHandler + eventMessageHandler = new EventHandler(this.connection); + eventMessageHandler.start(); - initLocomotiveManager(); - Logger.trace("There are " + this.locomotiveManager.getSize() + " locomotives"); + //Obtain some info about the ECoS + initBaseObject(); - initAccessoryManager(); - Logger.trace("There are " + this.accessoryManager.getSize() + " accessories"); + initLocomotiveManager(); + Logger.trace("There are " + this.locomotiveManager.getSize() + " locomotives"); - initFeedbackManager(); - Logger.trace("There are " + this.feedbackManager.getSize() + " feedback modules"); + initAccessoryManager(); + Logger.trace("There are " + this.accessoryManager.getSize() + " accessories"); - if (isVirtual()) { - simulator = new DriveSimulator(); - Logger.info("ECoS Virtual Mode Enabled!"); + initFeedbackManager(); + Logger.trace("There are " + this.feedbackManager.getSize() + " feedback modules"); - } + if (isVirtual()) { + simulator = new DriveSimulator(); + Logger.info("ECoS Virtual Mode Enabled!"); - } else { - Logger.warn("Can't connect with a ESU ECoS Command Station!"); - JCS.logProgress("Can't connect with ESU ECoS Command Station!"); } + + } else { + Logger.warn("Can't connect with a ESU ECoS Command Station!"); + JCS.logProgress("Can't connect with ESU ECoS Command Station!"); } } + } // Logger.trace("Connected with: " + (this.mainDevice != null ? this.mainDevice.getName() : "Unknown")); // JCS.logProgress("Power is " + (this.power ? "On" : "Off")); - return this.connected; - + return connected; } private void initBaseObject() { @@ -246,18 +249,38 @@ private void initFeedbackManager() { @Override public void disconnect() { try { - if (this.connected) { - this.connection.sendMessage(EcosMessageFactory.unSubscribeBaseObject()); - //TODO unsubscribe from all locomotives, accessories and sensors + if (connected) { + Logger.trace("Unsubsribe from " + feedbackManager.getSize() + " feedback modules..."); + for (FeedbackModuleBean fm : feedbackManager.getModules().values()) { + connection.sendMessage(EcosMessageFactory.unSubscribeFeedbackModule(fm.getId())); + } + Logger.trace("Unsubscribe from " + accessoryManager.getSize() + " accessories..."); + for (AccessoryBean a : this.accessoryManager.getAccessories().values()) { + connection.sendMessage(EcosMessageFactory.unSubscribeAccessory(a.getId())); + } + Logger.trace("Unsubscribe from " + locomotiveManager.getSize() + " locomotives..."); + for (LocomotiveBean l : this.locomotiveManager.getLocomotives().values()) { + connection.sendMessage(EcosMessageFactory.unSubscribeLocomotive(l.getId())); + } + connection.sendMessage(EcosMessageFactory.unSubscribeAccessoryManager()); + connection.sendMessage(EcosMessageFactory.unSubscribeLokManager()); + connection.sendMessage(EcosMessageFactory.unSubscribeFeedbackManager()); + connection.sendMessage(EcosMessageFactory.unSubscribeBaseObject()); } - if (this.eventMessageHandler != null) { - this.eventMessageHandler.quit(); + if (eventMessageHandler != null) { + Logger.trace("Stopping event handling..."); + eventMessageHandler.quit(); + eventMessageHandler.join(); + + eventMessageHandler = null; } - if (this.connected) { - this.connection.close(); - this.connected = false; + if (connected) { + connection.close(); + connected = false; } + + EcosConnectionFactory.disconnectAll(); } catch (Exception ex) { Logger.error(ex); } @@ -266,12 +289,12 @@ public void disconnect() { @Override public InfoBean getCommandStationInfo() { InfoBean ib = new InfoBean(commandStationBean); - if (this.ecosManager != null) { - + if (ecosManager != null) { ib.setArticleNumber(ecosManager.getName().replace(this.ecosManager.getCommandStationType() + "-", "")); ib.setDescription(ecosManager.getName()); ib.setArticleNumber(ecosManager.getName().replace(this.ecosManager.getCommandStationType() + "-", "")); ib.setSerialNumber(ecosManager.getSerialNumber()); + ib.setProductName(ecosManager.getName()); ib.setHardwareVersion(ecosManager.getHardwareVersion()); ib.setSoftwareVersion(ecosManager.getApplicationVersion()); ib.setHostname(getIp()); @@ -577,7 +600,6 @@ void firePowerEventListeners(final PowerEvent powerEvent) { //Communication from Ecos reply messages to JCS private class EventHandler extends Thread { - private boolean stop = false; private boolean quit = true; private BufferedReader reader; @@ -587,16 +609,9 @@ public EventHandler(EcosConnection connection) { eventQueue = connection.getEventQueue(); } - void quit() { + synchronized void quit() { this.quit = true; - } - - boolean isRunning() { - return !this.quit; - } - - boolean isFinished() { - return this.stop; + interrupt(); } @Override @@ -606,7 +621,7 @@ public void run() { Logger.trace("Event Handler Started..."); - while (isRunning()) { + while (!quit) { try { EcosMessage eventMessage = eventQueue.take(); Logger.trace("# " + (eventMessage.isEvent() ? "-> " + eventMessage.getResponse() : eventMessage.getMessage() + " -> " + eventMessage.getResponse())); @@ -639,17 +654,20 @@ public void run() { } } } catch (InterruptedException ex) { - Logger.error(ex); + if (!quit) { + Logger.error(ex); + } } } - Logger.debug("Stop receiving"); try { - reader.close(); + if (reader != null) { + reader.close(); + } } catch (IOException ex) { Logger.error(ex); } - stop = true; + Logger.debug("Stop receiving"); } } @@ -661,7 +679,7 @@ public static void main(String[] a) { System.setProperty("message.debug", "true"); //Discover the ECoS using mdns InetAddress ecosAddr = EcosConnectionFactory.discoverEcos(); - String ip = ecosAddr.getHostAddress(); + String ip = ecosAddr.getHostAddress(); if (1 == 1) { CommandStationBean csb = new CommandStationBean(); @@ -710,11 +728,11 @@ public static void main(String[] a) { // cs.pause(1000); // List feedbackModules = cs.getFeedbackModules(); - Logger.trace("There are "+feedbackModules+" Feedback Modules"); - for(FeedbackModuleBean fm : feedbackModules) { - Logger.trace("Module id: "+fm.getId()+" Module nr: "+fm.getModuleNumber()+" ports: "+fm.getPortCount()+" NodeId: "+fm.getIdentifier()+" BusNr: "+fm.getBusNumber()); - Logger.trace("FBModule id: "+fm.getId()+" S 1 id:"+fm.getSensor(0).getId()+" contactId: "+fm.getSensor(0).getContactId()+" ModuleNr: "+fm.getSensor(0).getDeviceId()+" Name "+fm.getSensor(0).getName()); - Logger.trace("FBModule id: "+fm.getId()+" S 15 id:"+fm.getSensor(15).getId()+" contactId: "+fm.getSensor(15).getContactId()+" ModuleNr: "+fm.getSensor(15).getDeviceId()+" Name "+fm.getSensor(15).getName()); + Logger.trace("There are " + feedbackModules + " Feedback Modules"); + for (FeedbackModuleBean fm : feedbackModules) { + Logger.trace("Module id: " + fm.getId() + " Module nr: " + fm.getModuleNumber() + " ports: " + fm.getPortCount() + " NodeId: " + fm.getIdentifier() + " BusNr: " + fm.getBusNumber()); + Logger.trace("FBModule id: " + fm.getId() + " S 1 id:" + fm.getSensor(0).getId() + " contactId: " + fm.getSensor(0).getContactId() + " ModuleNr: " + fm.getSensor(0).getDeviceId() + " Name " + fm.getSensor(0).getName()); + Logger.trace("FBModule id: " + fm.getId() + " S 15 id:" + fm.getSensor(15).getId() + " contactId: " + fm.getSensor(15).getContactId() + " ModuleNr: " + fm.getSensor(15).getDeviceId() + " Name " + fm.getSensor(15).getName()); } // power = cs.power(true); // Logger.trace("4 Power is " + (power ? "On" : "Off")); @@ -792,7 +810,7 @@ public static void main(String[] a) { // //reply = cs.connection.sendMessage(new EcosMessage("help(65000,attribute)")); // //Logger.trace(reply.getMessage() + " ->\n" + reply.getResponse()); // - + // // reply = cs.connection.sendMessage(new EcosMessage("request(65000,volt")); // Logger.trace(reply.getMessage() + " ->\n" + reply.getResponse()); diff --git a/src/main/java/jcs/commandStation/esu/ecos/net/EcosConnectionFactory.java b/src/main/java/jcs/commandStation/esu/ecos/net/EcosConnectionFactory.java index 897b06cb..389a6677 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/net/EcosConnectionFactory.java +++ b/src/main/java/jcs/commandStation/esu/ecos/net/EcosConnectionFactory.java @@ -20,10 +20,8 @@ import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Set; -import jcs.JCS; +import jcs.entities.CommandStationBean; import jcs.util.NetworkUtil; -import jcs.util.Ping; -import jcs.util.RunUtil; import net.straylightlabs.hola.dns.Domain; import net.straylightlabs.hola.sd.Instance; import net.straylightlabs.hola.sd.Query; @@ -34,120 +32,85 @@ * Try to connect with a ESU ECoS 50xxx. */ public class EcosConnectionFactory { - + private static final String ESU_MRTP_SERVICE = "_esu-mrtp._tcp"; - - private static EcosConnectionFactory instance; - - private EcosConnection controllerConnection; - private EcosHTTPConnection httpConnection; - private InetAddress controllerHost; - private boolean forceVirtual = false; - - private static final String LAST_USED_IP_PROP_FILE = RunUtil.DEFAULT_PATH + "last-used-esu-ecos-ip.properties"; - - private EcosConnectionFactory() { + + private static EcosConnection controllerConnection; + + private static EcosHTTPConnection httpConnection; + + private static InetAddress controllerHost; + private static boolean forceVirtual = false; + private static boolean virtual; + + static { forceVirtual = "true".equals(System.getProperty("connection.always.virtual", "false")); } - - public static EcosConnectionFactory getInstance() { - if (instance == null) { - instance = new EcosConnectionFactory(); - } - return instance; + + public static EcosConnection getConnection(CommandStationBean commandStation) { + return getConnection(commandStation, (virtual != commandStation.isVirtual())); } - - EcosConnection getConnectionImpl(boolean flag) { - boolean virtual = flag; + + public static EcosConnection getConnection(CommandStationBean commandStation, boolean reconnect) { + if (reconnect) { + disconnectAll(); + } + + virtual = commandStation.isVirtual(); if (!virtual && forceVirtual) { virtual = forceVirtual; Logger.info("Forcing a virtual connection!"); } - if (!virtual) { - if (controllerConnection == null) { - String lastUsedIp = RunUtil.readProperty(LAST_USED_IP_PROP_FILE, "ip-address"); - if (lastUsedIp != null) { - try { - if (Ping.IsReachable(lastUsedIp)) { - this.controllerHost = InetAddress.getByName(lastUsedIp); - Logger.trace("Using last used IP Address: " + lastUsedIp); - } else { - Logger.trace("Last used IP Address: " + lastUsedIp + " is not reachable"); - } - } catch (UnknownHostException ex) { - Logger.trace("Last used ESU ECoS IP: " + lastUsedIp + " is invalid!"); - lastUsedIp = null; - } - } - - if (this.controllerHost == null) { - Logger.trace("Try to discover a ESU ECoS..."); - JCS.logProgress("Discovering a ESU ECoS..."); - controllerHost = discoverEcos(); - } - - if (controllerHost != null) { - if (lastUsedIp == null) { - //Write the last used IP Addres for faster discovery next time - writeLastUsedIpAddressProperty(controllerHost.getHostAddress()); - } - Logger.trace("ESU ECoS ip: " + controllerHost.getHostName()); - - controllerConnection = new EcosTCPConnection(controllerHost); - } else { - Logger.warn("Can't find a ESU ECoS Controller host!"); - JCS.logProgress("Can't find a ESU ECoS Controller on the Network"); - } + + try { + if (virtual) { + controllerHost = InetAddress.getLocalHost(); + } else { + controllerHost = InetAddress.getByName(commandStation.getIpAddress()); } - } else { - //Virtual connection - controllerConnection = new EcosVirtualConnection(NetworkUtil.getIPv4HostAddress()); + } catch (UnknownHostException ex) { + Logger.error("Invalid ip address : " + commandStation.getIpAddress()); + return null; } - return this.controllerConnection; - } - - public static EcosConnection getConnection() { - return getInstance().getConnectionImpl(false); - } - - public static EcosConnection getConnection(boolean virtual) { - return getInstance().getConnectionImpl(virtual); + + if (controllerConnection == null) { + if (virtual) { + controllerConnection = new EcosVirtualConnection(controllerHost); + } else { + controllerConnection = new EcosTCPConnection(controllerHost); + } + } + return controllerConnection; } - - EcosHTTPConnection getHttpConnectionImpl() { + + public static EcosHTTPConnection getHttpConnection() { if (httpConnection == null) { httpConnection = new EcosHTTPConnection(controllerHost); } return httpConnection; } - - public static EcosHTTPConnection getHttpConnection() { - return getInstance().getHttpConnectionImpl(); - } - + public static void disconnectAll() { - if (instance.controllerConnection != null) { + httpConnection = null; + + if (controllerConnection != null) { try { - instance.controllerConnection.close(); + controllerConnection.close(); } catch (Exception ex) { Logger.trace("Error during disconnect " + ex); } } - instance.controllerConnection = null; - instance.controllerHost = null; + controllerConnection = null; + controllerHost = null; } - - String getControllerIpImpl() { - if (this.controllerHost != null) { - return this.controllerHost.getHostAddress(); + + public static String getControllerIp() { + if (controllerHost != null) { + return controllerHost.getHostAddress(); } else { return "Unknown"; } } - - public static String getControllerIp() { - return getInstance().getControllerIpImpl(); - } /** * Try to Automatically discover the ESU ECoS IP Address on the local network.
@@ -157,23 +120,23 @@ public static String getControllerIp() { */ public static InetAddress discoverEcos() { InetAddress ecosIp = null; - + try { Service ecosService = Service.fromName(ESU_MRTP_SERVICE); Query ecosQuery = Query.createFor(ecosService, Domain.LOCAL); - + Set ecosInstances = ecosQuery.runOnceOn(NetworkUtil.getIPv4HostAddress()); - + Logger.trace("Found " + ecosInstances.size()); - + if (ecosInstances.isEmpty()) { Logger.warn("Could not find a ESU ECoS host on the local network!"); return null; } - + Instance ecos = ecosInstances.iterator().next(); Logger.trace("ESU ECoS: " + ecos); - + Set addresses = ecos.getAddresses(); //Find the first ip4 address @@ -188,11 +151,10 @@ public static InetAddress discoverEcos() { } return ecosIp; } - - public static void writeLastUsedIpAddressProperty(String ipAddress) { - if (ipAddress != null) { - RunUtil.writeProperty(LAST_USED_IP_PROP_FILE, "ip-address", ipAddress); - } - } - + +// public static void writeLastUsedIpAddressProperty(String ipAddress) { +// if (ipAddress != null) { +// RunUtil.writeProperty(LAST_USED_IP_PROP_FILE, "ip-address", ipAddress); +// } +// } } diff --git a/src/main/java/jcs/commandStation/esu/ecos/net/EcosTCPConnection.java b/src/main/java/jcs/commandStation/esu/ecos/net/EcosTCPConnection.java index 98b6a828..a1cdd443 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/net/EcosTCPConnection.java +++ b/src/main/java/jcs/commandStation/esu/ecos/net/EcosTCPConnection.java @@ -69,22 +69,23 @@ private void checkConnection() { messageReceiver.start(); } } catch (IOException ex) { - this.clientSocket = null; + clientSocket = null; Logger.error("Can't (re)connect with ESU Ecos " + ecosAddress.getHostAddress() + ". Cause: " + ex.getMessage()); Logger.trace(ex); } } private void disconnect() { - this.messageReceiver.quit(); + messageReceiver.quit(); //wait until the messageReceiver has shut down long now = System.currentTimeMillis(); long start = now; - long timeout = now + TIMEOUT; - boolean finished = this.messageReceiver.isFinished(); + long timeout = now + TIMEOUT * 4; + boolean finished = messageReceiver.isFinished(); + while (!finished && now < timeout) { - finished = this.messageReceiver.isFinished(); + finished = messageReceiver.isFinished(); now = System.currentTimeMillis(); } @@ -144,7 +145,7 @@ public synchronized EcosMessage sendMessage(EcosMessage message) { } catch (IOException | InterruptedException ex) { Logger.error(ex); String msg = "Host " + ecosAddress.getHostName(); - ConnectionEvent de = new ConnectionEvent(msg,false); + ConnectionEvent de = new ConnectionEvent(msg, false); messageReceiver.messageListener.onDisconnect(de); messageReceiver.quit(); @@ -159,12 +160,12 @@ public void close() { @Override public boolean isConnected() { - return this.messageReceiver != null && this.messageReceiver.isRunning(); + return messageReceiver != null && messageReceiver.isRunning(); } @Override public TransferQueue getEventQueue() { - return this.eventQueue; + return eventQueue; } private class ClientMessageReceiver extends Thread { @@ -182,22 +183,28 @@ public ClientMessageReceiver(Socket socket) { } } - void quit() { - this.quit = true; + synchronized void quit() { + quit = true; + interrupt(); //Shutdown the socket input otherwise the receving thread can't stop try { - clientSocket.shutdownInput(); + if (!clientSocket.isClosed()) { + clientSocket.shutdownInput(); + } + if (reader != null) { + reader.close(); + } } catch (IOException ex) { Logger.error(ex); } } boolean isRunning() { - return !this.quit; + return !quit; } boolean isFinished() { - return this.stop; + return stop; } void setMessageListener(EcosMessageListener messageListener) { @@ -206,12 +213,12 @@ void setMessageListener(EcosMessageListener messageListener) { @Override public void run() { - this.quit = false; - this.setName("ESU-ECOS-RX"); + quit = false; + setName("ESU-ECOS-RX"); Logger.trace("Started listening on port " + clientSocket.getLocalPort() + " ..."); - while (isRunning()) { + while (!quit) { try { String rx = reader.readLine(); Logger.trace("RX: " + rx); @@ -247,7 +254,7 @@ public void run() { sb.append(rx); boolean complete = EcosMessage.isComplete(rx); - while (!complete && now < timeout) { + while (!complete && now < timeout && !quit) { rx = reader.readLine(); sb.append(rx); complete = EcosMessage.isComplete(sb.toString()); @@ -261,26 +268,27 @@ public void run() { eventQueue.offer(emsg); } - } } catch (SocketException se) { Logger.error(se.getMessage()); String msg = "Host " + ecosAddress.getHostName(); ConnectionEvent de = new ConnectionEvent(msg, false); - this.messageListener.onDisconnect(de); + messageListener.onDisconnect(de); quit(); } catch (IOException | InterruptedException ex) { Logger.error(ex); } } - Logger.debug("Stop receiving"); try { - reader.close(); + if (reader != null) { + reader.close(); + } } catch (IOException ex) { Logger.error(ex); } stop = true; + Logger.debug("Stopped receiving"); } } diff --git a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java index 49c1db9d..4282d261 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java +++ b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java @@ -18,6 +18,8 @@ import jcs.commandStation.marklin.cs.can.device.CanDevice; import jcs.commandStation.marklin.cs.can.parser.FeedbackEventMessage; import java.awt.Image; +import java.net.InetAddress; +import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; @@ -89,6 +91,7 @@ import jcs.commandStation.events.MeasurementEvent; import jcs.commandStation.events.MeasurementEventListener; import jcs.commandStation.marklin.parser.CanDeviceJSONParser; +import jcs.util.Ping; /** * Command Station Implementation for Marklin CS-2/3 @@ -176,14 +179,48 @@ public final synchronized boolean connect() { executor = Executors.newCachedThreadPool(); } - CSConnection csConnection = CSConnectionFactory.getConnection(virtual); + if (commandStationBean == null) { + Logger.error("Marklin Command Station Configuration NOT set!"); + return false; + } else { + Logger.trace("Connect using " + commandStationBean.getConnectionType()); + } + + CommandStationBean.ConnectionType conType = commandStationBean.getConnectionType(); + + boolean canConnect; + if (conType == CommandStationBean.ConnectionType.NETWORK) { + try { + InetAddress csAddr; + if (virtual) { + csAddr = InetAddress.getLocalHost(); + } else { + csAddr = InetAddress.getByName(commandStationBean.getIpAddress()); + } + commandStationBean.setIpAddress(csAddr.getHostAddress()); + canConnect = csAddr.getHostAddress() != null; + } catch (UnknownHostException ex) { + Logger.error("Invalid ip address : " + commandStationBean.getIpAddress()); + return false; + } + } else { + if (virtual) { + canConnect = true; + } else { + canConnect = Ping.IsReachable(commandStationBean.getIpAddress()); + } + } + + if (!canConnect) { + Logger.error("Can't connect to " + (commandStationBean.getIpAddress() == null ? "ip Address not set" : "can't reach ip " + commandStationBean.getIpAddress())); + return false; + } - connection = csConnection; + connection = CSConnectionFactory.getConnection(commandStationBean); if (connection != null) { - //Wait until the receiver thread has started long now = System.currentTimeMillis(); - long timeout = now + 1000L; + long timeout = now + 5000L; while (!connected && now < timeout) { connected = connection.isConnected(); @@ -196,7 +233,7 @@ public final synchronized boolean connect() { if (connected) { CanDevice gfp = getGFP(); canDevices.put(gfp.getUidInt(), gfp); - csUid = gfp.getUidInt(); //Integer.parseUnsignedInt(gfp.getUid().replace("0x", ""), 16); + csUid = gfp.getUidInt(); canBootLoaderLastCallMillis = System.currentTimeMillis(); @@ -217,7 +254,7 @@ public final synchronized boolean connect() { eventMessageHandler = new EventMessageHandler(connection); eventMessageHandler.start(); - csConnection.addDisconnectionEventListener(this); + connection.addDisconnectionEventListener(this); startWatchdog(); power = isPower(); @@ -253,7 +290,7 @@ public final synchronized boolean connect() { //Based on the info in this file it is quicker to know whether the CS is a version 2 or 3. //In case of a CS-3 the information can be retrieved via JSON else use CAN CanDevice getGFP() { - CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(virtual); + CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(); String geraet = httpCon.getInfoFile(); CanDevice gfp = GeraetParser.parseFile(geraet); return gfp; @@ -427,7 +464,7 @@ void queryDevice(CanDevice device) { * This data can also be obtained using the CAN Member PING command, but The JSON gives a little more detail. */ private List getCS3Devices() { - CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(virtual); + CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(); String devJson = httpCon.getDevicesJSON(); List devices = CanDeviceJSONParser.parse(devJson); @@ -771,14 +808,14 @@ List getLocomotivesViaCAN() { } List getLocomotivesViaHttp() { - CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(virtual); + CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(); String csLocos = httpCon.getLocomotivesFile(); LocomotiveBeanParser lp = new LocomotiveBeanParser(); return lp.parseLocomotivesFile(csLocos); } List getLocomotivesViaJSON() { - CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(virtual); + CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(); String json = httpCon.getLocomotivesJSON(); LocomotiveBeanJSONParser lp = new LocomotiveBeanJSONParser(); return lp.parseLocomotives(json); @@ -806,7 +843,7 @@ public List getLocomotives() { } List getAccessoriesViaHttp() { - CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(virtual); + CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(); if (isCS3() && System.getProperty("accessory.list.via", "JSON").equalsIgnoreCase("JSON")) { String json = httpCon.getAccessoriesJSON(); return AccessoryBeanParser.parseAccessoryJSON(json, commandStationBean.getId(), commandStationBean.getShortName()); @@ -836,14 +873,14 @@ public List getAccessories() { @Override public Image getLocomotiveImage(String icon) { - CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(virtual); + CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(); Image locIcon = httpCon.getLocomotiveImage(icon); return locIcon; } @Override public Image getLocomotiveFunctionImage(String icon) { - CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(virtual); + CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(); if (this.isCS3()) { if (!FunctionSvgToPngConverter.isSvgCacheLoaded()) { Logger.trace("Loading SVG Cache"); diff --git a/src/main/java/jcs/commandStation/marklin/cs/net/CSConnectionFactory.java b/src/main/java/jcs/commandStation/marklin/cs/net/CSConnectionFactory.java index bf6d8307..816e36e0 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/net/CSConnectionFactory.java +++ b/src/main/java/jcs/commandStation/marklin/cs/net/CSConnectionFactory.java @@ -26,8 +26,8 @@ import jcs.JCS; import jcs.commandStation.marklin.cs.can.CanMessage; import jcs.commandStation.marklin.cs.can.CanMessageFactory; +import jcs.entities.CommandStationBean; import jcs.util.NetworkUtil; -import jcs.util.Ping; import jcs.util.RunUtil; import net.straylightlabs.hola.dns.Domain; import net.straylightlabs.hola.sd.Instance; @@ -46,119 +46,126 @@ public class CSConnectionFactory { private static final String MARKLIN_CS_SERVICE = "_workstation._tcp"; - - private static CSConnectionFactory instance; - - private CSConnection controllerConnection; - private CSHTTPConnection httpConnection; - private InetAddress controllerHost; - private static final String BROADCAST_ADDRESS = "255.255.255.255"; - private static final String LAST_USED_IP_PROP_FILE = RunUtil.DEFAULT_PATH + "last-used-marklin-cs-ip.properties"; + private static InetAddress controllerHost; + private static boolean forceVirtual = false; + private static boolean virtual; - private boolean forceVirtual = false; + private static CSConnection controllerConnection; + private static CSHTTPConnection httpConnection; - private CSConnectionFactory() { + static { forceVirtual = "true".equals(System.getProperty("connection.always.virtual", "false")); } - public static CSConnectionFactory getInstance() { - if (instance == null) { - instance = new CSConnectionFactory(); - } - return instance; + public static CSConnection getConnection(CommandStationBean commandStation) { + return getConnection(commandStation, (virtual != commandStation.isVirtual())); } - CSConnection getConnectionImpl(boolean flag) { - boolean virtual = flag; + public static CSConnection getConnection(CommandStationBean commandStation, boolean reconnect) { + if (reconnect) { + disconnectAll(); + } + + virtual = commandStation.isVirtual(); if (!virtual && forceVirtual) { virtual = forceVirtual; Logger.info("Forcing a virtual connection!"); } - if (!virtual) { - if (controllerConnection == null) { - String lastUsedIp = RunUtil.readProperty(LAST_USED_IP_PROP_FILE, "ip-address"); - - if (lastUsedIp != null) { - try { - if (Ping.IsReachable(lastUsedIp)) { - controllerHost = InetAddress.getByName(lastUsedIp); - Logger.trace("Using last used IP Address: " + lastUsedIp); - } else { - Logger.trace("Last used IP Address: " + lastUsedIp + " is not reachable"); - } - } catch (UnknownHostException ex) { - Logger.trace("Last used CS IP: " + lastUsedIp + " is invalid!"); - lastUsedIp = null; - } - } - - if (controllerHost == null) { - Logger.trace("Try to discover a Marklin CS..."); - JCS.logProgress("Discovering a Marklin Central Station..."); - //First try with mdns - controllerHost = discoverCs(); - if (controllerHost == null) { - //try the "old" way by sending a "ping" - controllerHost = sendMobileAppPing(); - } - } - if (controllerHost != null) { - if (lastUsedIp == null) { - //Write the last used IP Addres for faster discovery next time - RunUtil.writeProperty(LAST_USED_IP_PROP_FILE, "ip-address", controllerHost.getHostAddress()); - } - Logger.trace("CS ip: " + controllerHost.getHostName()); + try { + if (virtual) { + controllerHost = InetAddress.getLocalHost(); + } else { + controllerHost = InetAddress.getByName(commandStation.getIpAddress()); + } + } catch (UnknownHostException ex) { + Logger.error("Invalid ip address : " + commandStation.getIpAddress()); + return null; + } - controllerConnection = new CSTCPConnection(controllerHost); - } else { - Logger.warn("Can't find a Marklin Controller host!"); - JCS.logProgress("Can't find a Marklin Central Station on the Network"); - } + if (controllerConnection == null) { + if (virtual) { + controllerConnection = new CSVirtualConnection(controllerHost); + } else { + controllerConnection = new CSTCPConnection(controllerHost); } - } else { - controllerConnection = new CSVirtualConnection(NetworkUtil.getIPv4HostAddress()); } - return this.controllerConnection; + return controllerConnection; } - public static CSConnection getConnection(boolean flag) { - return getInstance().getConnectionImpl(flag); + public static CSHTTPConnection getHTTPConnection() { + if (httpConnection == null) { + if (virtual) { + httpConnection = new CSHTTPConnectionVirt(controllerHost); + } else { + httpConnection = new CSHTTPConnectionImpl(controllerHost); + } + } + return httpConnection; } public static void disconnectAll() { - if (instance.controllerConnection != null) { + if (controllerConnection != null) { try { - instance.controllerConnection.close(); + controllerConnection.close(); } catch (Exception ex) { Logger.trace("Error during disconnect " + ex); } } - instance.controllerConnection = null; - instance.httpConnection = null; - instance.controllerHost = null; + controllerConnection = null; + httpConnection = null; + controllerHost = null; } - CSHTTPConnection getHTTPConnectionImpl(boolean flag) { - if (controllerConnection == null) { - getConnectionImpl(flag); + public static String getControllerIp() { + if (controllerHost != null) { + return controllerHost.getHostAddress(); + } else { + return "Unknown"; } - if (httpConnection == null) { - if (!flag) { - httpConnection = new CSHTTPConnectionImpl(controllerHost); - } else { - httpConnection = new CSHTTPConnectionVirt(controllerHost); + } + + /** + * Try to Automatically discover the Marklin Central Station IP Address on the local network.
+ * mDNS is now supported by the CS-3, not sure whether the CS-2 also supports it. + * + * @return the IP Address of the Marklin Central Station of null if not discovered. + */ + public static InetAddress discoverCs() { + InetAddress csIp = null; + try { + Service marklinService = Service.fromName(MARKLIN_CS_SERVICE); + Query marklinQuery = Query.createFor(marklinService, Domain.LOCAL); + + Set marklinInstances = marklinQuery.runOnceOn(NetworkUtil.getIPv4HostAddress()); + + Logger.trace("Found " + marklinInstances.size()); + + if (marklinInstances.isEmpty()) { + Logger.warn("Could not find a Marklin Central Station host on the local network!"); + return null; } - } - return httpConnection; - } - public static CSHTTPConnection getHTTPConnection(boolean flag) { - return getInstance().getHTTPConnectionImpl(flag); + Instance cs = marklinInstances.iterator().next(); + Logger.trace("Marklin Central Station: " + cs); + + Set addresses = cs.getAddresses(); + + //Find the first ip4 address + for (InetAddress ia : addresses) { + if (ia instanceof Inet4Address) { + csIp = ia; + break; + } + } + } catch (IOException ex) { + Logger.error(ex.getMessage()); + } + return csIp; } /** @@ -168,7 +175,7 @@ public static CSHTTPConnection getHTTPConnection(boolean flag) { * * @return the IP Address of the Marklin Central Station or null if not discovered. */ - public static InetAddress sendMobileAppPing() { + public static InetAddress discoverCsUsingMobileAppPing() { InetAddress csIp = null; try { InetAddress localAddress; @@ -215,56 +222,4 @@ public static InetAddress sendMobileAppPing() { return csIp; } - String getControllerIpImpl() { - if (controllerHost != null) { - return controllerHost.getHostAddress(); - } else { - return "Unknown"; - } - } - - public static String getControllerIp() { - return getInstance().getControllerIpImpl(); - } - - /** - * Try to Automatically discover the Marklin Central Station IP Address on the local network.
- * mDNS is now supported by the CS-3, not sure whether the CS-2 also supports it. - * - * @return the IP Address of the Marklin Central Station of null if not discovered. - */ - public static InetAddress discoverCs() { - InetAddress csIp = null; - - try { - Service marklinService = Service.fromName(MARKLIN_CS_SERVICE); - Query marklinQuery = Query.createFor(marklinService, Domain.LOCAL); - - Set marklinInstances = marklinQuery.runOnceOn(NetworkUtil.getIPv4HostAddress()); - - Logger.trace("Found " + marklinInstances.size()); - - if (marklinInstances.isEmpty()) { - Logger.warn("Could not find a Marklin Central Station host on the local network!"); - return null; - } - - Instance cs = marklinInstances.iterator().next(); - Logger.trace("Marklin Central Station: " + cs); - - Set addresses = cs.getAddresses(); - - //Find the first ip4 address - for (InetAddress ia : addresses) { - if (ia instanceof Inet4Address) { - csIp = ia; - break; - } - } - } catch (IOException ex) { - Logger.error(ex.getMessage()); - } - return csIp; - } - } diff --git a/src/main/java/jcs/ui/settings/CommandStationDialog1.form b/src/main/java/jcs/ui/settings/CommandStationDialog1.form index 37c3e654..b4832b62 100644 --- a/src/main/java/jcs/ui/settings/CommandStationDialog1.form +++ b/src/main/java/jcs/ui/settings/CommandStationDialog1.form @@ -540,18 +540,188 @@ - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/jcs/ui/settings/CommandStationDialog1.java b/src/main/java/jcs/ui/settings/CommandStationDialog1.java index b7d74afb..e9f52771 100644 --- a/src/main/java/jcs/ui/settings/CommandStationDialog1.java +++ b/src/main/java/jcs/ui/settings/CommandStationDialog1.java @@ -33,6 +33,10 @@ import org.tinylog.Logger; import java.net.InetAddress; import javax.swing.JDialog; +import jcs.commandStation.DecoderController; +import jcs.commandStation.entities.InfoBean; +import jcs.commandStation.esu.ecos.EsuEcosCommandStationImpl; +import jcs.commandStation.marklin.cs.MarklinCentralStationImpl; import jcs.util.Ping; /** @@ -55,6 +59,10 @@ public class CommandStationDialog1 extends javax.swing.JDialog { private static final String MARKLIN_CS = "marklin.cs"; private static final String ESU_ECOS = "esu-ecos"; + private static final String DCC_EX = "dcc-ex"; + private static final String HSI_S88 = "hsi-s88"; + + private DecoderController controller; /** * Creates new form CommandStationDialog1 @@ -191,6 +199,12 @@ private void initComponents() { jScrollPane1 = new javax.swing.JScrollPane(); jTree1 = new javax.swing.JTree(); jPanel2 = new javax.swing.JPanel(); + jPanel1 = new javax.swing.JPanel(); + controllerPanel = new javax.swing.JPanel(); + connectedToLbl = new javax.swing.JLabel(); + serialLbl = new javax.swing.JLabel(); + swVersionLbl = new javax.swing.JLabel(); + hwVersionLbl = new javax.swing.JLabel(); setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); @@ -367,17 +381,43 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { getContentPane().add(jPanel5, java.awt.BorderLayout.LINE_START); - javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2); - jPanel2.setLayout(jPanel2Layout); - jPanel2Layout.setHorizontalGroup( - jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 0, Short.MAX_VALUE) + jPanel2.setLayout(new java.awt.BorderLayout()); + + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); + jPanel1.setLayout(jPanel1Layout); + jPanel1Layout.setHorizontalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 825, Short.MAX_VALUE) ); - jPanel2Layout.setVerticalGroup( - jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 417, Short.MAX_VALUE) + jPanel1Layout.setVerticalGroup( + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 390, Short.MAX_VALUE) ); + jPanel2.add(jPanel1, java.awt.BorderLayout.CENTER); + + java.awt.FlowLayout flowLayout2 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); + flowLayout2.setAlignOnBaseline(true); + controllerPanel.setLayout(flowLayout2); + + connectedToLbl.setText("Connected to: command station"); + connectedToLbl.setPreferredSize(new java.awt.Dimension(200, 17)); + controllerPanel.add(connectedToLbl); + + serialLbl.setText("Serial: xxxxxx"); + serialLbl.setPreferredSize(new java.awt.Dimension(150, 17)); + controllerPanel.add(serialLbl); + + swVersionLbl.setText("Software version: xxxxxxx"); + swVersionLbl.setPreferredSize(new java.awt.Dimension(160, 17)); + controllerPanel.add(swVersionLbl); + + hwVersionLbl.setText("Hardware version: xxxxxx"); + hwVersionLbl.setPreferredSize(new java.awt.Dimension(160, 17)); + controllerPanel.add(hwVersionLbl); + + jPanel2.add(controllerPanel, java.awt.BorderLayout.PAGE_START); + getContentPane().add(jPanel2, java.awt.BorderLayout.CENTER); pack(); @@ -400,8 +440,8 @@ private void commandStationCBActionPerformed(java.awt.event.ActionEvent evt) {// } selectedCommandStation = (CommandStationBean) commandStationCBM.getSelectedItem(); - executor.execute(() -> changeDefaultCommandStation(selectedCommandStation)); + selectedCommandStation.setEnabled(true); setComponents(); //this.enableFields(this.enableEditCB.isSelected()); @@ -433,6 +473,9 @@ private void setComponents() { if (selectedCommandStation.getIpAddress() == null || selectedCommandStation.getIpAddress().length() > 8) { ipTF.setBackground(new java.awt.Color(255, 255, 255)); + connectBtn.setEnabled(true); + } else { + connectBtn.setEnabled(false); } //no main controller feedback support, enable the secondary @@ -441,6 +484,41 @@ private void setComponents() { feedbackLbl.setVisible(!selectedCommandStation.isFeedbackSupport()); secondfbpLbl.setVisible(!selectedCommandStation.isFeedbackSupport() && selectedFeedbackProvider.isFeedbackSupport() && selectedFeedbackProvider.getId() != null); + + fbpSerialCB.setVisible(!selectedCommandStation.isFeedbackSupport()); + fbpSerialCB.setEnabled(!selectedCommandStation.isFeedbackSupport()); + fbpSerialLbl.setVisible(!selectedCommandStation.isFeedbackSupport()); + + if (controller != null && controller.isConnected()) { + InfoBean ib = controller.getCommandStationInfo(); + connectedToLbl.setText("Connected to : " + ib.getProductName()); + connectedToLbl.setVisible(true); + + serialLbl.setText("Serial: " + ib.getSerialNumber()); + serialLbl.setVisible(true); + + if (ib.getSoftwareVersion() != null) { + swVersionLbl.setText("Software version: " + ib.getSoftwareVersion()); + swVersionLbl.setVisible(true); + } else { + swVersionLbl.setVisible(false); + } + + if (ib.getHardwareVersion() != null) { + hwVersionLbl.setText(("Hardware version: " + ib.getHardwareVersion())); + hwVersionLbl.setVisible(true); + } else { + hwVersionLbl.setVisible(false); + } + + connectBtn.setText("Disconnect"); + } else { + connectedToLbl.setVisible(false); + serialLbl.setVisible(false); + swVersionLbl.setVisible(false); + hwVersionLbl.setVisible(false); + connectBtn.setText("Connect"); + } } private void changeDefaultCommandStation(final CommandStationBean newDefault) { @@ -531,7 +609,13 @@ private void ipTFMouseExited(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_i }//GEN-LAST:event_ipTFMouseExited private void connectBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_connectBtnActionPerformed - // TODO add your handling code here: + Logger.trace("Try to connect to " + selectedCommandStation.getDescription()); + + if ("Connect".equals(connectBtn.getText())) { + executor.execute(() -> connect(selectedCommandStation)); + } else { + executor.execute(() -> disconnect()); + } }//GEN-LAST:event_connectBtnActionPerformed private void checkBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_checkBtnActionPerformed @@ -541,7 +625,7 @@ private void checkBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRS private InetAddress discover(final CommandStationBean commandStation) { final JOptionPane optionPane = new JOptionPane("Try to discovering a " + commandStation.getDescription(), JOptionPane.INFORMATION_MESSAGE, - JOptionPane.OK_OPTION); + JOptionPane.DEFAULT_OPTION); final JDialog discoverDialog = new JDialog(this, "Discovering..."); discoverDialog.setContentPane(optionPane); @@ -560,10 +644,10 @@ private InetAddress discover(final CommandStationBean commandStation) { if (inetAddress != null) { Logger.trace("Discovered host " + inetAddress.getHostAddress() + " for " + commandStation.getDescription()); commandStation.setIpAddress(inetAddress.getHostAddress()); + persistCommandStation(commandStation); } java.awt.EventQueue.invokeLater(() -> { - setComponents(); discoverDialog.setVisible(false); discoverDialog.dispose(); }); @@ -578,14 +662,89 @@ private void checkConnection(final CommandStationBean commandStation) { java.awt.EventQueue.invokeLater(() -> { if (canConnect) { ipTF.setBackground(new java.awt.Color(204, 255, 204)); + connectBtn.setEnabled(true); } else { ipTF.setBackground(new java.awt.Color(255, 255, 255)); - + connectBtn.setEnabled(false); JOptionPane.showMessageDialog(this, "Can't connect with host " + ip, "Can't Connect", JOptionPane.WARNING_MESSAGE); } }); } + private void disconnect() { + if (controller != null) { + controller.disconnect(); + controller = null; + + java.awt.EventQueue.invokeLater(() -> { + setComponents(); + }); + + } + } + + private void connect(final CommandStationBean commandStation) { + final JOptionPane optionPane = new JOptionPane("Try to connect to " + commandStation.getDescription(), + JOptionPane.INFORMATION_MESSAGE, + JOptionPane.DEFAULT_OPTION); + + final JDialog connectingDialog = new JDialog(this, "Connecting..."); + connectingDialog.setContentPane(optionPane); + connectingDialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); + connectingDialog.pack(); + connectingDialog.setLocationRelativeTo(null); + connectingDialog.setVisible(true); + + if (MARKLIN_CS.equals(commandStation.getId())) { + controller = new MarklinCentralStationImpl(commandStation); + } else if (ESU_ECOS.equals(commandStation.getId())) { + controller = new EsuEcosCommandStationImpl(commandStation); + } else if (DCC_EX.equals(commandStation.getId())) { + Logger.info("TODO: DCC-EX!"); + } else if (HSI_S88.equals(commandStation.getId())) { + Logger.info("TODO: HSI-S88!"); + } else { + Logger.trace("Unknown Controller!"); + } + + if (controller == null) { + return; + } + + controller.connect(); + if (controller.isConnected()) { + //Obtain some info from the controller + Logger.trace("Connected to " + controller.getCommandStationInfo()); + + java.awt.EventQueue.invokeLater(() -> { + setComponents(); + }); + } + + java.awt.EventQueue.invokeLater(() -> { + connectingDialog.setVisible(false); + connectingDialog.dispose(); + }); + + //} catch (UnknownHostException ex) { + // Logger.error("Unknown host " + commandStation.getIpAddress()); + // return false; + //} + } + + @Override + public void setVisible(boolean b) { + super.setVisible(b); + + if (!b && this.controller != null) { + if (controller.isConnected()) { + controller.disconnect(); + } + controller = null; + Logger.trace("Disconnected from " + selectedCommandStation.getId()); + } + } + /** * @param args the command line arguments */ @@ -605,6 +764,7 @@ public static void main(String args[]) { dialog.addWindowListener(new java.awt.event.WindowAdapter() { @Override public void windowClosing(java.awt.event.WindowEvent e) { + dialog.setVisible(false); System.exit(0); } }); @@ -623,8 +783,10 @@ public void windowClosing(java.awt.event.WindowEvent e) { private javax.swing.JComboBox commandStationCB; private javax.swing.JLabel commandStationLbl; private javax.swing.JButton connectBtn; + private javax.swing.JLabel connectedToLbl; private javax.swing.ButtonGroup connectionTypeBG; private javax.swing.JLabel controllerLbl; + private javax.swing.JPanel controllerPanel; private javax.swing.JButton discoverBtn; private javax.swing.JComboBox fbpSerialCB; private javax.swing.JLabel fbpSerialLbl; @@ -633,8 +795,10 @@ public void windowClosing(java.awt.event.WindowEvent e) { private javax.swing.JLabel feedbackLbl; private javax.swing.JLabel feedbackProviderLbl; private javax.swing.Box.Filler filler1; + private javax.swing.JLabel hwVersionLbl; private javax.swing.JLabel ipOrPortLbl; private javax.swing.JTextField ipTF; + private javax.swing.JPanel jPanel1; private javax.swing.JPanel jPanel2; private javax.swing.JPanel jPanel3; private javax.swing.JPanel jPanel4; @@ -645,7 +809,9 @@ public void windowClosing(java.awt.event.WindowEvent e) { private javax.swing.JRadioButton networkRB; private javax.swing.JLabel secondfbpLbl; private javax.swing.JComboBox serialCB; + private javax.swing.JLabel serialLbl; private javax.swing.JRadioButton serialRB; + private javax.swing.JLabel swVersionLbl; private javax.swing.JPanel topPanel; // End of variables declaration//GEN-END:variables diff --git a/src/test/java/jcs/commandStation/marklin/cs/net/CSConnectionFactoryTest.java b/src/test/java/jcs/commandStation/marklin/cs/net/CSConnectionFactoryTest.java deleted file mode 100644 index 93191c41..00000000 --- a/src/test/java/jcs/commandStation/marklin/cs/net/CSConnectionFactoryTest.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (C) 2022 fransjacobs. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA - */ -package jcs.commandStation.marklin.cs.net; - -import org.junit.After; -import static org.junit.Assert.*; -import org.junit.Before; - -/** - * - * @author fransjacobs - */ -public class CSConnectionFactoryTest { - - public CSConnectionFactoryTest() { - } - - @Before - public void setUp() { - } - - @After - public void tearDown() { - } - - /** - * Test of getInstance method, of class CSConnectionFactory. - */ - //@Test - public void testGetInstance() { - System.out.println("getInstance"); - CSConnectionFactory expResult = null; - CSConnectionFactory result = CSConnectionFactory.getInstance(); - assertEquals(expResult, result); - // TODO review the generated test code and remove the default call to fail. - fail("The test case is a prototype."); - } - - /** - * Test of getConnectionImpl method, of class CSConnectionFactory. - */ - //@Test - public void testGetConnectionImpl() { - System.out.println("getConnectionImpl"); - CSConnectionFactory instance = null; - CSConnection expResult = null; - CSConnection result = instance.getConnectionImpl(true); - assertEquals(expResult, result); - // TODO review the generated test code and remove the default call to fail. - fail("The test case is a prototype."); - } - - /** - * Test of getConnection method, of class CSConnectionFactory. - */ - //@Test - public void testGetConnection() { - System.out.println("getConnection"); - CSConnection expResult = null; - CSConnection result = CSConnectionFactory.getConnection(true); - assertEquals(expResult, result); - // TODO review the generated test code and remove the default call to fail. - fail("The test case is a prototype."); - } - - /** - * Test of disconnectAll method, of class CSConnectionFactory. - */ - //@Test - public void testDisconnectAll() { - System.out.println("disconnectAll"); - CSConnectionFactory.disconnectAll(); - // TODO review the generated test code and remove the default call to fail. - fail("The test case is a prototype."); - } - - /** - * Test of getHTTPConnectionImpl method, of class CSConnectionFactory. - */ - //@Test - public void testGetHTTPConnectionImpl() { - System.out.println("getHTTPConnectionImpl"); - CSConnectionFactory instance = null; - CSHTTPConnection expResult = null; - CSHTTPConnection result = instance.getHTTPConnectionImpl(true); - assertEquals(expResult, result); - // TODO review the generated test code and remove the default call to fail. - fail("The test case is a prototype."); - } - - /** - * Test of getHTTPConnection method, of class CSConnectionFactory. - */ - //@Test - public void testGetHTTPConnection() { - System.out.println("getHTTPConnection"); - CSHTTPConnection expResult = null; - CSHTTPConnection result = CSConnectionFactory.getHTTPConnection(true); - assertEquals(expResult, result); - // TODO review the generated test code and remove the default call to fail. - fail("The test case is a prototype."); - } - - /** - * Test of sendMobileAppPing method, of class CSConnectionFactory. - */ - //@Test - public void testSendMobileAppPing() { - System.out.println("sendMobileAppPing"); - CSConnectionFactory instance = null; - instance.sendMobileAppPing(); - // TODO review the generated test code and remove the default call to fail. - fail("The test case is a prototype."); - } - - /** - * Test of getControllerIpImpl method, of class CSConnectionFactory. - */ - //@Test - public void testGetControllerIpImpl() { - System.out.println("getControllerIpImpl"); - CSConnectionFactory instance = null; - String expResult = ""; - String result = instance.getControllerIpImpl(); - assertEquals(expResult, result); - // TODO review the generated test code and remove the default call to fail. - fail("The test case is a prototype."); - } - - /** - * Test of getControllerIp method, of class CSConnectionFactory. - */ - //@Test - public void testGetControllerIp() { - System.out.println("getControllerIp"); - String expResult = ""; - String result = CSConnectionFactory.getControllerIp(); - assertEquals(expResult, result); - // TODO review the generated test code and remove the default call to fail. - fail("The test case is a prototype."); - } - -} From 81cb023b7758395119ab18c23a1a7660d66d2f80 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Fri, 23 May 2025 14:21:56 +0200 Subject: [PATCH 66/70] Fix test --- src/main/java/jcs/ui/settings/CommandStationDialog1.java | 4 ++++ .../esu/ecos/EsuEcosCommandStationImplTest.java | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/src/main/java/jcs/ui/settings/CommandStationDialog1.java b/src/main/java/jcs/ui/settings/CommandStationDialog1.java index e9f52771..123a087d 100644 --- a/src/main/java/jcs/ui/settings/CommandStationDialog1.java +++ b/src/main/java/jcs/ui/settings/CommandStationDialog1.java @@ -718,6 +718,10 @@ private void connect(final CommandStationBean commandStation) { java.awt.EventQueue.invokeLater(() -> { setComponents(); + + //Query the controller for devices in general and for feedback devices + //how to populate the tree..... + }); } diff --git a/src/test/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImplTest.java b/src/test/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImplTest.java index af38ce34..b2d278a3 100644 --- a/src/test/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImplTest.java +++ b/src/test/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImplTest.java @@ -136,9 +136,15 @@ public void testGetCommandStationInfo() { expResult.setSerialNumber("0x00000000"); expResult.setHardwareVersion("1.3"); expResult.setSoftwareVersion("4.2.13"); + expResult.setProductName("ECoS-Virtual"); expResult.setHostname(NetworkUtil.getIPv4HostAddress().getHostAddress()); InfoBean result = instance.getCommandStationInfo(); + +//expected: +// but was: + + assertEquals(expResult, result); } } From 4f5cf25e0adb1ed66435fb634217f670da84c17a Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Sun, 25 May 2025 18:52:59 +0200 Subject: [PATCH 67/70] More work on the new CommandStationDialog Sensor are updated --- .../jcs/commandStation/GenericController.java | 4 + .../dccex/DccExCommandStationImpl.java | 15 +- .../jcs/commandStation/entities/Device.java | 153 ++++++ .../esu/ecos/EsuEcosCommandStationImpl.java | 39 +- .../esu/ecos/net/EcosVirtualConnection.java | 4 +- .../jcs/commandStation/hsis88/HSIImpl.java | 22 +- .../marklin/cs/MarklinCentralStationImpl.java | 18 + .../virtual/VirtualCommandStationImpl.java | 9 + .../java/jcs/entities/FeedbackModuleBean.java | 27 +- .../ui/settings/CommandStationDialog1.form | 465 +++++++++++++----- .../ui/settings/CommandStationDialog1.java | 364 ++++++++++++-- 11 files changed, 921 insertions(+), 199 deletions(-) create mode 100644 src/main/java/jcs/commandStation/entities/Device.java diff --git a/src/main/java/jcs/commandStation/GenericController.java b/src/main/java/jcs/commandStation/GenericController.java index 66a1485f..374510ba 100755 --- a/src/main/java/jcs/commandStation/GenericController.java +++ b/src/main/java/jcs/commandStation/GenericController.java @@ -15,6 +15,8 @@ */ package jcs.commandStation; +import java.util.List; +import jcs.commandStation.entities.Device; import jcs.entities.CommandStationBean; import jcs.commandStation.entities.InfoBean; import jcs.commandStation.events.ConnectionEventListener; @@ -39,6 +41,8 @@ public interface GenericController { InfoBean getCommandStationInfo(); + List getDevices(); + String getIp(); } diff --git a/src/main/java/jcs/commandStation/dccex/DccExCommandStationImpl.java b/src/main/java/jcs/commandStation/dccex/DccExCommandStationImpl.java index e66ccf45..7f292924 100644 --- a/src/main/java/jcs/commandStation/dccex/DccExCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/dccex/DccExCommandStationImpl.java @@ -16,6 +16,7 @@ package jcs.commandStation.dccex; import java.awt.Image; +import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executors; import jcs.JCS; @@ -26,6 +27,7 @@ import jcs.commandStation.dccex.connection.DccExMessageListener; import jcs.commandStation.dccex.events.CabEvent; import jcs.commandStation.dccex.events.DccExMeasurementEvent; +import jcs.commandStation.entities.Device; import jcs.commandStation.events.AccessoryEvent; import jcs.commandStation.events.AccessoryEventListener; import jcs.commandStation.events.ConnectionEvent; @@ -57,7 +59,6 @@ public class DccExCommandStationImpl extends AbstractController implements Decod private boolean powerStatusSet = false; //Map measurementChannels; - public DccExCommandStationImpl(CommandStationBean commandStationBean) { this(commandStationBean, false); } @@ -96,7 +97,6 @@ public DccExCommandStationImpl(CommandStationBean commandStationBean, boolean au // handleMeasurement(csrq); // } // } - @Override public final boolean connect() { if (!connected) { @@ -379,6 +379,12 @@ public InfoBean getCommandStationInfo() { return this.infoBean; } + @Override + public List getDevices() { + List devices = new ArrayList<>(); + return devices; + } + @Override public boolean isSupportTrackMeasurements() { return false; // true; @@ -393,7 +399,6 @@ public boolean isSupportTrackMeasurements() { // } // return this.measurementChannels; // } - private void fireAllDisconnectionEventListeners(final ConnectionEvent disconnectionEvent) { for (ConnectionEventListener listener : this.connectionEventListeners) { listener.onConnectionChange(disconnectionEvent); @@ -534,7 +539,6 @@ private void fireAllAccessoryEventListeners(final AccessoryEvent accessoryEvent) // } // } // } - private void handleInfoMessage(String message) { //executor.execute(() -> fireAllPowerEventListeners(powerEvent)); Logger.trace("Info: " + message); @@ -704,6 +708,9 @@ public static void main(String[] a) { // ((DccExCommandStationImpl) cs).pause(500L); // cs.power(true); // Logger.trace("Power is: " + (cs.isPower() ? "On" : "Off")); + + + ///// //((DccExCommandStationImpl) cs).pause(500L); // cs.changeFunctionValue(8, 0, true); diff --git a/src/main/java/jcs/commandStation/entities/Device.java b/src/main/java/jcs/commandStation/entities/Device.java new file mode 100644 index 00000000..a0cc2302 --- /dev/null +++ b/src/main/java/jcs/commandStation/entities/Device.java @@ -0,0 +1,153 @@ +/* + * Copyright 2025 fransjacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.commandStation.entities; + +import java.util.Objects; + +/** + * Command Station Device is an Object to be able to show the Devices that "live"
+ * inside a Command Station. Examples
+ * Marklin CS:
+ * - GFP internal booster device - Link S88 external feedback device ESU-ECoS:
+ * - Ecos device self / booster - Locomotive Manager - Accessories Manager - Feedback Manager + */ +public class Device { + + private String id; + private String name; + private String hardwareVersion; + private String softwareVersion; + private String serialNumber; + + private Integer size; + private Integer channels; + private boolean feedback; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getHardwareVersion() { + return hardwareVersion; + } + + public void setHardwareVersion(String hardwareVersion) { + this.hardwareVersion = hardwareVersion; + } + + public String getSoftwareVersion() { + return softwareVersion; + } + + public void setSoftwareVersion(String softwareVersion) { + this.softwareVersion = softwareVersion; + } + + public String getSerialNumber() { + return serialNumber; + } + + public void setSerialNumber(String serialNumber) { + this.serialNumber = serialNumber; + } + + public Integer getSize() { + return size; + } + + public void setSize(Integer size) { + this.size = size; + } + + public Integer getChannels() { + return channels; + } + + public void setChannels(Integer channels) { + this.channels = channels; + } + + public boolean isFeedback() { + return feedback; + } + + public void setFeedback(boolean feedback) { + this.feedback = feedback; + } + + @Override + public int hashCode() { + int hash = 3; + hash = 67 * hash + Objects.hashCode(this.id); + hash = 67 * hash + Objects.hashCode(this.name); + hash = 67 * hash + Objects.hashCode(this.hardwareVersion); + hash = 67 * hash + Objects.hashCode(this.softwareVersion); + hash = 67 * hash + Objects.hashCode(this.serialNumber); + hash = 67 * hash + Objects.hashCode(this.size); + hash = 67 * hash + Objects.hashCode(this.channels); + hash = 67 * hash + Objects.hashCode(this.feedback); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final Device other = (Device) obj; + if (!Objects.equals(this.id, other.id)) { + return false; + } + if (!Objects.equals(this.name, other.name)) { + return false; + } + if (!Objects.equals(this.hardwareVersion, other.hardwareVersion)) { + return false; + } + if (!Objects.equals(this.softwareVersion, other.softwareVersion)) { + return false; + } + if (!Objects.equals(this.serialNumber, other.serialNumber)) { + return false; + } + if (!Objects.equals(this.size, other.size)) { + return false; + } + if (!Objects.equals(this.feedback, other.feedback)) { + return false; + } + return Objects.equals(this.channels, other.channels); + } + +} diff --git a/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java b/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java index baf44829..1f649d59 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java @@ -51,6 +51,7 @@ import jcs.commandStation.events.SensorEventListener; import jcs.commandStation.autopilot.DriveSimulator; import jcs.commandStation.VirtualConnection; +import jcs.commandStation.entities.Device; import static jcs.entities.AccessoryBean.AccessoryValue.GREEN; import static jcs.entities.AccessoryBean.AccessoryValue.RED; import jcs.entities.LocomotiveBean; @@ -272,14 +273,14 @@ public void disconnect() { Logger.trace("Stopping event handling..."); eventMessageHandler.quit(); eventMessageHandler.join(); - + eventMessageHandler = null; } if (connected) { connection.close(); connected = false; } - + EcosConnectionFactory.disconnectAll(); } catch (Exception ex) { Logger.error(ex); @@ -308,6 +309,40 @@ public InfoBean getCommandStationInfo() { return ib; } + @Override + public List getDevices() { + List devices = new ArrayList<>(); + Device ecos = new Device(); + ecos.setId(EcosManager.ID + ""); + ecos.setName(ecosManager.getName()); + ecos.setSerialNumber(ecosManager.getSerialNumber()); + ecos.setHardwareVersion(ecosManager.getHardwareVersion()); + ecos.setSoftwareVersion(ecosManager.getApplicationVersion()); + devices.add(ecos); + + Device locs = new Device(); + locs.setId(LocomotiveManager.ID + ""); + locs.setName("LocomotiveManager"); + locs.setSize(locomotiveManager.getSize()); + devices.add(locs); + + Device acm = new Device(); + acm.setId(AccessoryManager.ID + ""); + acm.setName("AccessoryManager"); + acm.setSize(accessoryManager.getSize()); + devices.add(acm); + + Device fbm = new Device(); + fbm.setId(FeedbackManager.ID + ""); + fbm.setName("FeedbackManager"); + fbm.setSize(feedbackManager.getSize()); + fbm.setChannels(feedbackManager.getModules().size()); + fbm.setFeedback(true); + devices.add(fbm); + + return devices; + } + @Override public String getIp() { if (this.connection != null && this.connection.isConnected()) { diff --git a/src/main/java/jcs/commandStation/esu/ecos/net/EcosVirtualConnection.java b/src/main/java/jcs/commandStation/esu/ecos/net/EcosVirtualConnection.java index 39ca5dd5..4430705a 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/net/EcosVirtualConnection.java +++ b/src/main/java/jcs/commandStation/esu/ecos/net/EcosVirtualConnection.java @@ -47,6 +47,8 @@ class EcosVirtualConnection implements EcosConnection, VirtualConnection { private EcosMessageListener messageListener; private boolean debug = false; + + private static String ESU_ECOS_ID = "esu-ecos"; EcosVirtualConnection(InetAddress address) { debug = System.getProperty("message.debug", "false").equalsIgnoreCase("true"); @@ -111,7 +113,7 @@ public synchronized EcosMessage sendMessage(EcosMessage message) { } case EcosMessageFactory.QUERY_LOCOMOTIVES -> { //Query the locomotives from the database - List locos = PersistenceFactory.getService().getLocomotives(); + List locos = PersistenceFactory.getService().getLocomotivesByCommandStationId(ESU_ECOS_ID); for (LocomotiveBean loco : locos) { //name,addr,protocol diff --git a/src/main/java/jcs/commandStation/hsis88/HSIImpl.java b/src/main/java/jcs/commandStation/hsis88/HSIImpl.java index ffe412ab..5e10c74d 100644 --- a/src/main/java/jcs/commandStation/hsis88/HSIImpl.java +++ b/src/main/java/jcs/commandStation/hsis88/HSIImpl.java @@ -15,6 +15,7 @@ */ package jcs.commandStation.hsis88; +import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -32,6 +33,7 @@ import jcs.entities.FeedbackModuleBean; import jcs.commandStation.entities.InfoBean; import jcs.commandStation.VirtualConnection; +import jcs.commandStation.entities.Device; import jcs.entities.SensorBean; import jcs.util.RunUtil; import org.tinylog.Logger; @@ -124,7 +126,7 @@ public final synchronized boolean connect() { //DeviceBean d = new DeviceBean(); String[] hsiinfo = info.split("/"); - //d.setName(info); + //d.setName(info); //d.setUid("0"); // for (int i = 0; i < hsiinfo.length; i++) { // switch (i) { @@ -155,25 +157,15 @@ public final synchronized boolean connect() { return connected; } -// @Override -// public DeviceBean getDevice() { -// return this.mainDevice; -// } - -// @Override -// public List getDevices() { -// return null;//this.devices.values().stream().collect(Collectors.toList()); -// } - @Override public InfoBean getCommandStationInfo() { return infoBean; } -// @Override -// public DeviceBean getFeedbackDevice() { -// return this.feedbackDevice; -// } + public List getDevices() { + List devices = new ArrayList<>(); + return devices; + } @Override public List getFeedbackModules() { diff --git a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java index 4282d261..ac637dc6 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java +++ b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java @@ -72,6 +72,7 @@ import jcs.commandStation.VirtualConnection; import jcs.commandStation.autopilot.AutoPilot; import jcs.commandStation.autopilot.DriveSimulator; +import jcs.commandStation.entities.Device; import jcs.commandStation.entities.MeasuredChannels; import jcs.commandStation.entities.MeasurementBean; import jcs.commandStation.events.ConnectionEvent; @@ -479,6 +480,23 @@ public InfoBean getCommandStationInfo() { return infoBean; } + @Override + public List getDevices() { + List devices = new ArrayList<>(); + for (CanDevice cd : canDevices.values()) { + Device d = new Device(); + d.setId(cd.getUid()); + d.setName(cd.getName()); + d.setSerialNumber(cd.getSerial()); + d.setSoftwareVersion(cd.getVersion()); + d.setHardwareVersion(cd.getHwVersion()); + d.setChannels(cd.getConfigChannelCount()); + devices.add(d); + } + + return devices; + } + @Override public List getFeedbackModules() { //Feedbackmodules can be queried from the Link S88 if available. diff --git a/src/main/java/jcs/commandStation/virtual/VirtualCommandStationImpl.java b/src/main/java/jcs/commandStation/virtual/VirtualCommandStationImpl.java index f83e1ece..af1fce0e 100644 --- a/src/main/java/jcs/commandStation/virtual/VirtualCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/virtual/VirtualCommandStationImpl.java @@ -17,6 +17,7 @@ import jcs.commandStation.autopilot.DriveSimulator; import java.awt.Image; +import java.util.ArrayList; import java.util.List; import jcs.JCS; import jcs.commandStation.AbstractController; @@ -24,6 +25,7 @@ import jcs.commandStation.DecoderController; import jcs.commandStation.FeedbackController; import jcs.commandStation.autopilot.AutoPilot; +import jcs.commandStation.entities.Device; import jcs.commandStation.events.AccessoryEvent; import jcs.commandStation.events.AccessoryEventListener; import jcs.commandStation.events.LocomotiveDirectionEvent; @@ -112,6 +114,13 @@ public InfoBean getCommandStationInfo() { return this.infoBean; } + @Override + public List getDevices() { + List devices = new ArrayList<>(); + + return devices; + } + @Override public String getIp() { return NetworkUtil.getIPv4HostAddress().getHostAddress(); diff --git a/src/main/java/jcs/entities/FeedbackModuleBean.java b/src/main/java/jcs/entities/FeedbackModuleBean.java index 9cdfdaa5..d007b495 100644 --- a/src/main/java/jcs/entities/FeedbackModuleBean.java +++ b/src/main/java/jcs/entities/FeedbackModuleBean.java @@ -23,7 +23,7 @@ /** * Represents 1 Feedback Module (S88) with a number of ports (usually 16) */ -public class FeedbackModuleBean { +public class FeedbackModuleBean implements Comparable { private Integer id; private Integer moduleNumber; @@ -60,6 +60,31 @@ public FeedbackModuleBean(Integer id, Integer moduleNumber, Integer portCount, I prevPorts = new int[portCount]; } + @Override + public int compareTo(FeedbackModuleBean o) { + int bn = 0; + if (busNumber != null) { + bn = busNumber; + } + int obn = 0; + if (o.busNumber != null) { + obn = o.busNumber; + } + int mn = 0; + if (moduleNumber != null) { + mn = moduleNumber; + } + int omn = 0; + if (o.moduleNumber != null) { + omn = o.moduleNumber; + } + + if (Integer.compare(bn, obn) != 0) { + return Integer.compare(bn, obn); + } + return Integer.compare(mn, omn); + } + public Integer getId() { return id; } diff --git a/src/main/java/jcs/ui/settings/CommandStationDialog1.form b/src/main/java/jcs/ui/settings/CommandStationDialog1.form index b4832b62..50f8feaf 100644 --- a/src/main/java/jcs/ui/settings/CommandStationDialog1.form +++ b/src/main/java/jcs/ui/settings/CommandStationDialog1.form @@ -22,7 +22,7 @@ - + @@ -64,6 +64,15 @@
+ + + + + + + + + @@ -475,7 +484,7 @@ - + @@ -507,7 +516,7 @@ - + @@ -517,21 +526,6 @@ - - - - - - - - - - - - - - - @@ -542,109 +536,302 @@ - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - + - - - - - - - - + - - - - + - + - + - + - - + + - + @@ -652,68 +839,29 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - - - - - - - - + - + - - + + - + @@ -721,6 +869,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/jcs/ui/settings/CommandStationDialog1.java b/src/main/java/jcs/ui/settings/CommandStationDialog1.java index 123a087d..097c2f47 100644 --- a/src/main/java/jcs/ui/settings/CommandStationDialog1.java +++ b/src/main/java/jcs/ui/settings/CommandStationDialog1.java @@ -32,18 +32,29 @@ import jcs.persistence.PersistenceFactory; import org.tinylog.Logger; import java.net.InetAddress; +import java.net.URL; +import java.util.Collections; import javax.swing.JDialog; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeSelectionModel; import jcs.commandStation.DecoderController; +import jcs.commandStation.FeedbackController; +import jcs.commandStation.entities.Device; import jcs.commandStation.entities.InfoBean; import jcs.commandStation.esu.ecos.EsuEcosCommandStationImpl; import jcs.commandStation.marklin.cs.MarklinCentralStationImpl; +import jcs.entities.FeedbackModuleBean; +import jcs.entities.SensorBean; import jcs.util.Ping; /** * * @author fransjacobs */ -public class CommandStationDialog1 extends javax.swing.JDialog { +public class CommandStationDialog1 extends JDialog implements TreeSelectionListener { private ComboBoxModel commandStationCBM; private ComboBoxModel feedbackCBM; @@ -70,7 +81,7 @@ public class CommandStationDialog1 extends javax.swing.JDialog { public CommandStationDialog1(java.awt.Frame parent, boolean modal) { super(parent, modal); initComponents(); - this.executor = Executors.newSingleThreadExecutor(); + executor = Executors.newSingleThreadExecutor(); if (PersistenceFactory.getService() != null) { initModels(null); } @@ -84,7 +95,7 @@ private void initModels(CommandStationBean selected) { selectedCommandStation = selected; } - if (!selectedCommandStation.isFeedbackSupport()) { + if (selectedCommandStation != null && !selectedCommandStation.isFeedbackSupport()) { selectedFeedbackProvider = PersistenceFactory.getService().getEnabledFeedbackProvider(); } @@ -155,12 +166,10 @@ private void initModels(CommandStationBean selected) { } setComponents(); - if (CommandStationBean.ConnectionType.NETWORK == selectedCommandStation.getConnectionType() && selectedCommandStation.getIpAddress() != null && selectedCommandStation.getIpAddress().length() > 8) { + + if (!selectedCommandStation.isVirtual() && CommandStationBean.ConnectionType.NETWORK == selectedCommandStation.getConnectionType() && selectedCommandStation.getIpAddress() != null && selectedCommandStation.getIpAddress().length() > 8) { executor.execute(() -> checkConnection(selectedCommandStation)); } - - //enableFields(false); - //this.progressBar.setVisible(false); } /** @@ -175,6 +184,7 @@ private void initComponents() { mainCSPanel = new javax.swing.JPanel(); commandStationLbl = new javax.swing.JLabel(); commandStationCB = new javax.swing.JComboBox<>(); + virtualCB = new javax.swing.JCheckBox(); ipOrPortLbl = new javax.swing.JLabel(); ipTF = new javax.swing.JTextField(); serialCB = new javax.swing.JComboBox<>(); @@ -196,15 +206,28 @@ private void initComponents() { jPanel4 = new javax.swing.JPanel(); connectBtn = new javax.swing.JButton(); jPanel5 = new javax.swing.JPanel(); - jScrollPane1 = new javax.swing.JScrollPane(); - jTree1 = new javax.swing.JTree(); jPanel2 = new javax.swing.JPanel(); - jPanel1 = new javax.swing.JPanel(); + propertiesPanel = new javax.swing.JPanel(); controllerPanel = new javax.swing.JPanel(); connectedToLbl = new javax.swing.JLabel(); serialLbl = new javax.swing.JLabel(); swVersionLbl = new javax.swing.JLabel(); hwVersionLbl = new javax.swing.JLabel(); + feedbackSettingsPanel = new javax.swing.JPanel(); + jLabel1 = new javax.swing.JLabel(); + mainSpinner = new javax.swing.JSpinner(); + jLabel2 = new javax.swing.JLabel(); + bus1Spinner = new javax.swing.JSpinner(); + jLabel3 = new javax.swing.JLabel(); + bus2Spinner = new javax.swing.JSpinner(); + jLabel4 = new javax.swing.JLabel(); + bus3Spinner = new javax.swing.JSpinner(); + filler2 = new javax.swing.Box.Filler(new java.awt.Dimension(100, 0), new java.awt.Dimension(100, 0), new java.awt.Dimension(100, 32767)); + updateBtn = new javax.swing.JButton(); + jPanel6 = new javax.swing.JPanel(); + jPanel1 = new javax.swing.JPanel(); + jScrollPane1 = new javax.swing.JScrollPane(); + jTree1 = new javax.swing.JTree(); setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); @@ -227,6 +250,15 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { }); mainCSPanel.add(commandStationCB); + virtualCB.setText("Virtual"); + virtualCB.setToolTipText("Use Virtual Connection"); + virtualCB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + virtualCBActionPerformed(evt); + } + }); + mainCSPanel.add(virtualCB); + ipOrPortLbl.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); ipOrPortLbl.setLabelFor(ipTF); ipOrPortLbl.setText("ip Address:"); @@ -353,7 +385,7 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { jPanel3.setLayout(jPanel3Layout); jPanel3Layout.setHorizontalGroup( jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 1113, Short.MAX_VALUE) + .addGap(0, 1202, Short.MAX_VALUE) ); jPanel3Layout.setVerticalGroup( jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -372,33 +404,19 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { getContentPane().add(jPanel4, java.awt.BorderLayout.LINE_END); - jPanel5.setPreferredSize(new java.awt.Dimension(200, 400)); + jPanel5.setPreferredSize(new java.awt.Dimension(100, 400)); jPanel5.setLayout(new java.awt.BorderLayout()); - - jScrollPane1.setViewportView(jTree1); - - jPanel5.add(jScrollPane1, java.awt.BorderLayout.CENTER); - getContentPane().add(jPanel5, java.awt.BorderLayout.LINE_START); jPanel2.setLayout(new java.awt.BorderLayout()); - javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); - jPanel1.setLayout(jPanel1Layout); - jPanel1Layout.setHorizontalGroup( - jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 825, Short.MAX_VALUE) - ); - jPanel1Layout.setVerticalGroup( - jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 390, Short.MAX_VALUE) - ); + jcs.ui.swing.layout.VerticalFlowLayout verticalFlowLayout2 = new jcs.ui.swing.layout.VerticalFlowLayout(); + verticalFlowLayout2.sethAlignment(0); + propertiesPanel.setLayout(verticalFlowLayout2); - jPanel2.add(jPanel1, java.awt.BorderLayout.CENTER); - - java.awt.FlowLayout flowLayout2 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); - flowLayout2.setAlignOnBaseline(true); - controllerPanel.setLayout(flowLayout2); + java.awt.FlowLayout flowLayout3 = new java.awt.FlowLayout(java.awt.FlowLayout.RIGHT); + flowLayout3.setAlignOnBaseline(true); + controllerPanel.setLayout(flowLayout3); connectedToLbl.setText("Connected to: command station"); connectedToLbl.setPreferredSize(new java.awt.Dimension(200, 17)); @@ -416,7 +434,77 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { hwVersionLbl.setPreferredSize(new java.awt.Dimension(160, 17)); controllerPanel.add(hwVersionLbl); - jPanel2.add(controllerPanel, java.awt.BorderLayout.PAGE_START); + propertiesPanel.add(controllerPanel); + + feedbackSettingsPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Feedback Modules")); + + jLabel1.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel1.setText("Main"); + jLabel1.setPreferredSize(new java.awt.Dimension(40, 17)); + feedbackSettingsPanel.add(jLabel1); + + mainSpinner.setModel(new javax.swing.SpinnerNumberModel(0, null, 31, 1)); + feedbackSettingsPanel.add(mainSpinner); + + jLabel2.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel2.setText("Bus 1"); + jLabel2.setPreferredSize(new java.awt.Dimension(40, 17)); + feedbackSettingsPanel.add(jLabel2); + + bus1Spinner.setModel(new javax.swing.SpinnerNumberModel(0, null, 31, 1)); + feedbackSettingsPanel.add(bus1Spinner); + + jLabel3.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel3.setText("Bus 2"); + jLabel3.setPreferredSize(new java.awt.Dimension(40, 17)); + feedbackSettingsPanel.add(jLabel3); + + bus2Spinner.setModel(new javax.swing.SpinnerNumberModel(0, null, 31, 1)); + feedbackSettingsPanel.add(bus2Spinner); + + jLabel4.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel4.setText("Bus 3"); + jLabel4.setPreferredSize(new java.awt.Dimension(40, 17)); + feedbackSettingsPanel.add(jLabel4); + + bus3Spinner.setModel(new javax.swing.SpinnerNumberModel(0, null, 31, 1)); + feedbackSettingsPanel.add(bus3Spinner); + feedbackSettingsPanel.add(filler2); + + updateBtn.setText("Update"); + updateBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + updateBtnActionPerformed(evt); + } + }); + feedbackSettingsPanel.add(updateBtn); + + propertiesPanel.add(feedbackSettingsPanel); + + jPanel2.add(propertiesPanel, java.awt.BorderLayout.PAGE_START); + + jPanel6.setPreferredSize(new java.awt.Dimension(750, 318)); + + javax.swing.GroupLayout jPanel6Layout = new javax.swing.GroupLayout(jPanel6); + jPanel6.setLayout(jPanel6Layout); + jPanel6Layout.setHorizontalGroup( + jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 750, Short.MAX_VALUE) + ); + jPanel6Layout.setVerticalGroup( + jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 318, Short.MAX_VALUE) + ); + + jPanel2.add(jPanel6, java.awt.BorderLayout.EAST); + + jPanel1.setLayout(new java.awt.GridLayout(1, 1)); + + jScrollPane1.setViewportView(jTree1); + + jPanel1.add(jScrollPane1); + + jPanel2.add(jPanel1, java.awt.BorderLayout.CENTER); getContentPane().add(jPanel2, java.awt.BorderLayout.CENTER); @@ -426,9 +514,9 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { private void commandStationCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_commandStationCBActionPerformed CommandStationBean newSelectedCommandStation = (CommandStationBean) commandStationCBM.getSelectedItem(); - if (!selectedCommandStation.getId().equals(newSelectedCommandStation.getId())) { + if (selectedCommandStation != null && selectedCommandStation.getId() != null && !selectedCommandStation.getId().equals(newSelectedCommandStation.getId())) { try { - if (JCS.getJcsCommandStation() != null) { + if (JCS.getJcsCommandStation() != null && JCS.getJcsCommandStation().isConnected()) { JCS.getJcsCommandStation().switchPower(false); } if (JCS.getParentFrame() != null) { @@ -437,15 +525,15 @@ private void commandStationCBActionPerformed(java.awt.event.ActionEvent evt) {// } catch (Exception e) { Logger.error(e.getMessage()); } + } else { + selectedCommandStation = newSelectedCommandStation; } selectedCommandStation = (CommandStationBean) commandStationCBM.getSelectedItem(); - executor.execute(() -> changeDefaultCommandStation(selectedCommandStation)); selectedCommandStation.setEnabled(true); + executor.execute(() -> changeDefaultCommandStation(selectedCommandStation)); - setComponents(); - //this.enableFields(this.enableEditCB.isSelected()); - Logger.trace("Selected CS: " + this.selectedCommandStation.getDescription()); + Logger.trace("Selected CS: " + selectedCommandStation.getDescription()); }//GEN-LAST:event_commandStationCBActionPerformed private void setComponents() { @@ -453,6 +541,8 @@ private void setComponents() { accessoryControllerLbl.setVisible(selectedCommandStation.isAccessoryControlSupport()); feedbackProviderLbl.setVisible(selectedCommandStation.isFeedbackSupport()); + virtualCB.setSelected(selectedCommandStation.isVirtual()); + discoverBtn.setVisible(selectedCommandStation.isIpAutoConfiguration()); ipTF.setText(selectedCommandStation.getIpAddress()); @@ -521,6 +611,159 @@ private void setComponents() { } } + private void initTree() { + Logger.trace("build tree"); + DefaultMutableTreeNode root = new DefaultMutableTreeNode(selectedCommandStation.getDescription()); + createNodes(root); + + DefaultTreeModel model = new DefaultTreeModel(root); + + jTree1.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); + jTree1.addTreeSelectionListener(this); + + jTree1.setModel(model); + } + + private void createNodes(DefaultMutableTreeNode root) { + Logger.trace("Create feedback nodes"); + if (controller == null) { + return; + } + + List devices = controller.getDevices(); + + for (Device d : devices) { + DefaultMutableTreeNode deviceNode = new DefaultMutableTreeNode(d.getId() + " " + d.getName()); + + if (d.isFeedback()) { + List modules = ((FeedbackController) controller).getFeedbackModules(); + Collections.sort(modules); + + for (FeedbackModuleBean fm : modules) { + DefaultMutableTreeNode moduleNode = new DefaultMutableTreeNode("M " + fm.toString()); + Logger.trace("M " + fm.toString()); + + deviceNode.add(moduleNode); + } + + } + + root.add(deviceNode); + } + +// if (controller != null && controller instanceof FeedbackController) { +// //DefaultMutableTreeNode feedbackmodules = null; +// +// DefaultMutableTreeNode category = null; +// DefaultMutableTreeNode book = null; +// +// List modules = ((FeedbackController) controller).getFeedbackModules(); +// Collections.sort(modules); +// +// for (FeedbackModuleBean fm : modules) { +// DefaultMutableTreeNode moduleNode = new DefaultMutableTreeNode("M " + fm.toString()); +// Logger.trace("M " + fm.toString()); +// +// if () { +// root.add(moduleNode); +// } +// } +// category = new DefaultMutableTreeNode("Books for Java Programmers"); +// top.add(category); +// +// //original Tutorial +// book = new DefaultMutableTreeNode(new BookInfo("The Java Tutorial: A Short Course on the Basics", +// "tutorial.html")); +// category.add(book); +// +// //Tutorial Continued +// book = new DefaultMutableTreeNode(new BookInfo("The Java Tutorial Continued: The Rest of the JDK", +// "tutorialcont.html")); +// category.add(book); +// +// //Swing Tutorial +// book = new DefaultMutableTreeNode(new BookInfo("The Swing Tutorial: A Guide to Constructing GUIs", +// "swingtutorial.html")); +// category.add(book); +// +// //...add more books for programmers... +// category = new DefaultMutableTreeNode("Books for Java Implementers"); +// top.add(category); +// +// //VM +// book = new DefaultMutableTreeNode(new BookInfo("The Java Virtual Machine Specification", +// "vm.html")); +// category.add(book); +// +// //Language Spec +// book = new DefaultMutableTreeNode(new BookInfo("The Java Language Specification", +// "jls.html")); +// category.add(book); +// } + } + + private class BookInfo { + + public String bookName; + public URL bookURL; + + public BookInfo(String book, String filename) { + bookName = book; + bookURL = getClass().getResource("/sandbox/" + filename); + + if (bookURL == null) { + Logger.warn("Couldn't find file: " + filename); + } + } + + @Override + public String toString() { + return bookName; + } + } + + public void valueChanged(TreeSelectionEvent e) { + DefaultMutableTreeNode node = (DefaultMutableTreeNode) jTree1.getLastSelectedPathComponent(); + + if (node == null) { + return; + } + + Object nodeInfo = node.getUserObject(); + + if (node.isLeaf()) { + CommandStationDialog1.BookInfo book = (CommandStationDialog1.BookInfo) nodeInfo; + + displayURL(book.bookURL); +// if (DEBUG) { +// System.out.print(book.bookURL + ": \n "); +// } + } else { + //displayURL(helpURL); + } +// if (DEBUG) { +// System.out.println(nodeInfo.toString()); +// } + } + + private void displayURL(URL url) { + //try { + if (url != null) { + //htmlPane.setPage(url); + Logger.trace("Suppose to set URL: " + url); + } else { + // htmlPane.setText("File Not Found"); + Logger.trace("File Not Found " + url); +// if (DEBUG) { +// System.out.println("Attempted to display a null URL."); +// } + } + //} catch (IOException e) { + //System.err.println("Attempted to read a bad URL: " + url); + // Logger.trace("Attempted to read a bad URL: " + url); + //} + } + private void changeDefaultCommandStation(final CommandStationBean newDefault) { PersistenceFactory.getService().changeDefaultCommandStation(newDefault); java.awt.EventQueue.invokeLater(() -> { @@ -622,6 +865,31 @@ private void checkBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRS executor.execute(() -> checkConnection(selectedCommandStation)); }//GEN-LAST:event_checkBtnActionPerformed + private void virtualCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_virtualCBActionPerformed + selectedCommandStation.setVirtual(virtualCB.isSelected()); + persistCommandStation(selectedCommandStation); + }//GEN-LAST:event_virtualCBActionPerformed + + private void updateBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_updateBtnActionPerformed + //TODO in workerthread with some feedback in the UI + + updateSensors(); + }//GEN-LAST:event_updateBtnActionPerformed + + private void updateSensors() { + + List modules = ((FeedbackController) controller).getFeedbackModules(); + + Logger.trace("There are " + modules.size() + " feedback modules"); + for (FeedbackModuleBean fbm : modules) { + List sensors = fbm.getSensors(); + for (SensorBean sb : sensors) { + PersistenceFactory.getService().persist(sb); + } + } + + } + private InetAddress discover(final CommandStationBean commandStation) { final JOptionPane optionPane = new JOptionPane("Try to discovering a " + commandStation.getDescription(), JOptionPane.INFORMATION_MESSAGE, @@ -717,11 +985,11 @@ private void connect(final CommandStationBean commandStation) { Logger.trace("Connected to " + controller.getCommandStationInfo()); java.awt.EventQueue.invokeLater(() -> { + initTree(); setComponents(); - + //Query the controller for devices in general and for feedback devices //how to populate the tree..... - }); } @@ -783,6 +1051,9 @@ public void windowClosing(java.awt.event.WindowEvent e) { // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JLabel accessoryControllerLbl; + private javax.swing.JSpinner bus1Spinner; + private javax.swing.JSpinner bus2Spinner; + private javax.swing.JSpinner bus3Spinner; private javax.swing.JButton checkBtn; private javax.swing.JComboBox commandStationCB; private javax.swing.JLabel commandStationLbl; @@ -798,25 +1069,36 @@ public void windowClosing(java.awt.event.WindowEvent e) { private javax.swing.JPanel feedbackCSPanel; private javax.swing.JLabel feedbackLbl; private javax.swing.JLabel feedbackProviderLbl; + private javax.swing.JPanel feedbackSettingsPanel; private javax.swing.Box.Filler filler1; + private javax.swing.Box.Filler filler2; private javax.swing.JLabel hwVersionLbl; private javax.swing.JLabel ipOrPortLbl; private javax.swing.JTextField ipTF; + private javax.swing.JLabel jLabel1; + private javax.swing.JLabel jLabel2; + private javax.swing.JLabel jLabel3; + private javax.swing.JLabel jLabel4; private javax.swing.JPanel jPanel1; private javax.swing.JPanel jPanel2; private javax.swing.JPanel jPanel3; private javax.swing.JPanel jPanel4; private javax.swing.JPanel jPanel5; + private javax.swing.JPanel jPanel6; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JTree jTree1; private javax.swing.JPanel mainCSPanel; + private javax.swing.JSpinner mainSpinner; private javax.swing.JRadioButton networkRB; + private javax.swing.JPanel propertiesPanel; private javax.swing.JLabel secondfbpLbl; private javax.swing.JComboBox serialCB; private javax.swing.JLabel serialLbl; private javax.swing.JRadioButton serialRB; private javax.swing.JLabel swVersionLbl; private javax.swing.JPanel topPanel; + private javax.swing.JButton updateBtn; + private javax.swing.JCheckBox virtualCB; // End of variables declaration//GEN-END:variables } From 0bb731e51d5f45e9382b31fccd6252683154b403 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Sun, 25 May 2025 18:53:26 +0200 Subject: [PATCH 68/70] Update CommandStationDialog1.java --- .../ui/settings/CommandStationDialog1.java | 96 ------------------- 1 file changed, 96 deletions(-) diff --git a/src/main/java/jcs/ui/settings/CommandStationDialog1.java b/src/main/java/jcs/ui/settings/CommandStationDialog1.java index 097c2f47..a709b37b 100644 --- a/src/main/java/jcs/ui/settings/CommandStationDialog1.java +++ b/src/main/java/jcs/ui/settings/CommandStationDialog1.java @@ -651,75 +651,6 @@ private void createNodes(DefaultMutableTreeNode root) { root.add(deviceNode); } -// if (controller != null && controller instanceof FeedbackController) { -// //DefaultMutableTreeNode feedbackmodules = null; -// -// DefaultMutableTreeNode category = null; -// DefaultMutableTreeNode book = null; -// -// List modules = ((FeedbackController) controller).getFeedbackModules(); -// Collections.sort(modules); -// -// for (FeedbackModuleBean fm : modules) { -// DefaultMutableTreeNode moduleNode = new DefaultMutableTreeNode("M " + fm.toString()); -// Logger.trace("M " + fm.toString()); -// -// if () { -// root.add(moduleNode); -// } -// } -// category = new DefaultMutableTreeNode("Books for Java Programmers"); -// top.add(category); -// -// //original Tutorial -// book = new DefaultMutableTreeNode(new BookInfo("The Java Tutorial: A Short Course on the Basics", -// "tutorial.html")); -// category.add(book); -// -// //Tutorial Continued -// book = new DefaultMutableTreeNode(new BookInfo("The Java Tutorial Continued: The Rest of the JDK", -// "tutorialcont.html")); -// category.add(book); -// -// //Swing Tutorial -// book = new DefaultMutableTreeNode(new BookInfo("The Swing Tutorial: A Guide to Constructing GUIs", -// "swingtutorial.html")); -// category.add(book); -// -// //...add more books for programmers... -// category = new DefaultMutableTreeNode("Books for Java Implementers"); -// top.add(category); -// -// //VM -// book = new DefaultMutableTreeNode(new BookInfo("The Java Virtual Machine Specification", -// "vm.html")); -// category.add(book); -// -// //Language Spec -// book = new DefaultMutableTreeNode(new BookInfo("The Java Language Specification", -// "jls.html")); -// category.add(book); -// } - } - - private class BookInfo { - - public String bookName; - public URL bookURL; - - public BookInfo(String book, String filename) { - bookName = book; - bookURL = getClass().getResource("/sandbox/" + filename); - - if (bookURL == null) { - Logger.warn("Couldn't find file: " + filename); - } - } - - @Override - public String toString() { - return bookName; - } } public void valueChanged(TreeSelectionEvent e) { @@ -732,36 +663,9 @@ public void valueChanged(TreeSelectionEvent e) { Object nodeInfo = node.getUserObject(); if (node.isLeaf()) { - CommandStationDialog1.BookInfo book = (CommandStationDialog1.BookInfo) nodeInfo; - displayURL(book.bookURL); -// if (DEBUG) { -// System.out.print(book.bookURL + ": \n "); -// } } else { - //displayURL(helpURL); } -// if (DEBUG) { -// System.out.println(nodeInfo.toString()); -// } - } - - private void displayURL(URL url) { - //try { - if (url != null) { - //htmlPane.setPage(url); - Logger.trace("Suppose to set URL: " + url); - } else { - // htmlPane.setText("File Not Found"); - Logger.trace("File Not Found " + url); -// if (DEBUG) { -// System.out.println("Attempted to display a null URL."); -// } - } - //} catch (IOException e) { - //System.err.println("Attempted to read a bad URL: " + url); - // Logger.trace("Attempted to read a bad URL: " + url); - //} } private void changeDefaultCommandStation(final CommandStationBean newDefault) { From fd013a9475bf00ec3d18a0cf8e0b6869c2905987 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Wed, 28 May 2025 19:23:54 +0200 Subject: [PATCH 69/70] New CommandStation Dialog is now the default in the settings --- .../commandStation/FeedbackController.java | 4 +- .../entities/FeedbackModule.java} | 43 +- .../esu/ecos/EsuEcosCommandStationImpl.java | 12 +- .../esu/ecos/FeedbackManager.java | 25 +- .../esu/ecos/net/EcosVirtualConnection.java | 11 +- .../jcs/commandStation/hsis88/HSIImpl.java | 4 +- .../marklin/cs/MarklinCentralStationImpl.java | 33 +- .../marklin/cs/can/device/CanDevice.java | 11 + .../cs/can/parser/FeedbackEventMessage.java | 14 +- .../marklin/parser/GeraetParser.java | 26 +- .../virtual/VirtualCommandStationImpl.java | 4 +- src/main/java/jcs/entities/SensorBean.java | 41 +- .../jcs/persistence/H2PersistenceService.java | 18 +- .../jcs/persistence/PersistenceService.java | 18 +- .../jcs/ui/panel/SmallDriverCabPanel.java | 2 +- .../jcs/ui/settings/CommandStationDialog.form | 1145 ++++++++++++++++- .../jcs/ui/settings/CommandStationDialog.java | 1137 +++++++++++++++- .../ui/settings/CommandStationDialog1.form | 922 ------------- .../ui/settings/CommandStationDialog1.java | 1008 --------------- .../jcs/ui/settings/CommandStationPanel.java | 8 +- src/main/resources/update-jcs-db-002.sql | 7 + .../entities/FeedbackModuleTest.java} | 96 +- .../ecos/EsuEcosCommandStationImplTest.java | 4 +- .../esu/ecos/FeedbackManagerTest.java | 4 +- .../persistence/PersistenceServiceTest.java | 8 +- src/test/resources/jcs-test-data-h2.sql | 6 +- 26 files changed, 2434 insertions(+), 2177 deletions(-) rename src/main/java/jcs/{entities/FeedbackModuleBean.java => commandStation/entities/FeedbackModule.java} (85%) delete mode 100644 src/main/java/jcs/ui/settings/CommandStationDialog1.form delete mode 100644 src/main/java/jcs/ui/settings/CommandStationDialog1.java rename src/test/java/jcs/{entities/FeedbackModuleBeanTest.java => commandStation/entities/FeedbackModuleTest.java} (72%) diff --git a/src/main/java/jcs/commandStation/FeedbackController.java b/src/main/java/jcs/commandStation/FeedbackController.java index f96ee9d5..ea15cffd 100644 --- a/src/main/java/jcs/commandStation/FeedbackController.java +++ b/src/main/java/jcs/commandStation/FeedbackController.java @@ -18,7 +18,7 @@ import java.util.List; import jcs.commandStation.events.SensorEvent; import jcs.commandStation.events.SensorEventListener; -import jcs.entities.FeedbackModuleBean; +import jcs.commandStation.entities.FeedbackModule; public interface FeedbackController extends GenericController { @@ -28,7 +28,7 @@ public interface FeedbackController extends GenericController { //DeviceBean getFeedbackDevice(); - List getFeedbackModules(); + List getFeedbackModules(); void fireSensorEventListeners(SensorEvent sensorEvent); diff --git a/src/main/java/jcs/entities/FeedbackModuleBean.java b/src/main/java/jcs/commandStation/entities/FeedbackModule.java similarity index 85% rename from src/main/java/jcs/entities/FeedbackModuleBean.java rename to src/main/java/jcs/commandStation/entities/FeedbackModule.java index d007b495..9c4ca6cc 100644 --- a/src/main/java/jcs/entities/FeedbackModuleBean.java +++ b/src/main/java/jcs/commandStation/entities/FeedbackModule.java @@ -13,17 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package jcs.entities; +package jcs.commandStation.entities; import java.util.ArrayList; import java.util.List; import jcs.commandStation.events.SensorEvent; +import jcs.entities.SensorBean; import org.tinylog.Logger; /** * Represents 1 Feedback Module (S88) with a number of ports (usually 16) */ -public class FeedbackModuleBean implements Comparable { +public class FeedbackModule implements Comparable { private Integer id; private Integer moduleNumber; @@ -32,6 +33,7 @@ public class FeedbackModuleBean implements Comparable { private Integer identifier; private Integer busNumber; private String commandStationId; + private Integer busSize; private int[] ports; private int[] prevPorts; @@ -40,15 +42,15 @@ public class FeedbackModuleBean implements Comparable { public static int DEFAULT_ADDRESS_OFFSET = 0; public static int DEFAULT_IDENTIFIER = 0; - public FeedbackModuleBean() { + public FeedbackModule() { this(null, null, null); } - public FeedbackModuleBean(Integer id, Integer moduleNumber, String commandStationId) { + public FeedbackModule(Integer id, Integer moduleNumber, String commandStationId) { this(id, moduleNumber, DEFAULT_PORT_COUNT, DEFAULT_ADDRESS_OFFSET, DEFAULT_IDENTIFIER, commandStationId); } - public FeedbackModuleBean(Integer id, Integer moduleNumber, Integer portCount, Integer addressOffset, Integer identifier, String commandStationId) { + public FeedbackModule(Integer id, Integer moduleNumber, Integer portCount, Integer addressOffset, Integer identifier, String commandStationId) { this.id = id; this.moduleNumber = moduleNumber; this.portCount = portCount; @@ -61,7 +63,7 @@ public FeedbackModuleBean(Integer id, Integer moduleNumber, Integer portCount, I } @Override - public int compareTo(FeedbackModuleBean o) { + public int compareTo(FeedbackModule o) { int bn = 0; if (busNumber != null) { bn = busNumber; @@ -147,13 +149,13 @@ public void setPorts(int[] ports) { public void setPortValue(int port, boolean active) { //save current values - System.arraycopy(this.ports, 0, this.prevPorts, 0, this.ports.length); - this.ports[port] = active ? 1 : 0; + System.arraycopy(ports, 0, prevPorts, 0, ports.length); + ports[port] = active ? 1 : 0; } public boolean isPort(int port) { if (ports != null && port < ports.length) { - return this.ports[port] == 1; + return ports[port] == 1; } else { return false; } @@ -187,6 +189,14 @@ public void setCommandStationId(String commandStationId) { this.commandStationId = commandStationId; } + public Integer getBusSize() { + return busSize; + } + + public void setBusSize(Integer busSize) { + this.busSize = busSize; + } + public SensorBean getSensor(int port) { int sid; int offset = 0; @@ -196,8 +206,8 @@ public SensorBean getSensor(int port) { if (addressOffset != null) { offset = addressOffset; } - sid = offset + moduleNumber * portCount + port; - name = "M" + String.format("%02d", moduleNumber) + "-C" + String.format("%02d", port); + sid = offset + (moduleNumber - 1) * portCount + port; + name = "M" + String.format("%02d", moduleNumber) + "-C" + String.format("%02d", port + 1); } else { //Part of a bus, there should be an offset... if (addressOffset != null) { @@ -205,14 +215,19 @@ public SensorBean getSensor(int port) { } else { Logger.warn("Module connected to bus " + busNumber + " but bus address offset is not specified!"); } - sid = offset + moduleNumber * portCount + port; - name = "B" + busNumber.toString() + "-M" + String.format("%02d", moduleNumber) + "-C" + String.format("%02d", port); + sid = offset + (moduleNumber - 1) * portCount + port; + name = "B" + busNumber.toString() + "-M" + String.format("%02d", moduleNumber) + "-C" + String.format("%02d", port + 1); } int status = ports[port]; int prevStatus = prevPorts[port]; - SensorBean sb = new SensorBean(sid, moduleNumber, port, identifier, status, prevStatus, commandStationId); + int busNr = 0; + if (busNumber != null) { + busNr = busNumber; + } + + SensorBean sb = new SensorBean(sid, moduleNumber, port + 1, identifier, status, prevStatus, commandStationId, busNr); sb.setName(name); return sb; } diff --git a/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java b/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java index 1f649d59..4d609dc2 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java @@ -37,7 +37,7 @@ import jcs.commandStation.events.SensorEvent; import jcs.entities.AccessoryBean; import jcs.entities.CommandStationBean; -import jcs.entities.FeedbackModuleBean; +import jcs.commandStation.entities.FeedbackModule; import jcs.commandStation.entities.InfoBean; import jcs.commandStation.esu.ecos.net.EcosHTTPConnection; import jcs.commandStation.events.AccessoryEvent; @@ -252,7 +252,7 @@ public void disconnect() { try { if (connected) { Logger.trace("Unsubsribe from " + feedbackManager.getSize() + " feedback modules..."); - for (FeedbackModuleBean fm : feedbackManager.getModules().values()) { + for (FeedbackModule fm : feedbackManager.getModules().values()) { connection.sendMessage(EcosMessageFactory.unSubscribeFeedbackModule(fm.getId())); } Logger.trace("Unsubscribe from " + accessoryManager.getSize() + " accessories..."); @@ -571,8 +571,8 @@ EcosConnection getConnection() { } @Override - public List getFeedbackModules() { - List feedbackModules = new ArrayList<>(this.feedbackManager.getModules().values()); + public List getFeedbackModules() { + List feedbackModules = new ArrayList<>(this.feedbackManager.getModules().values()); return feedbackModules; } @@ -762,9 +762,9 @@ public static void main(String[] a) { // // cs.pause(1000); // - List feedbackModules = cs.getFeedbackModules(); + List feedbackModules = cs.getFeedbackModules(); Logger.trace("There are " + feedbackModules + " Feedback Modules"); - for (FeedbackModuleBean fm : feedbackModules) { + for (FeedbackModule fm : feedbackModules) { Logger.trace("Module id: " + fm.getId() + " Module nr: " + fm.getModuleNumber() + " ports: " + fm.getPortCount() + " NodeId: " + fm.getIdentifier() + " BusNr: " + fm.getBusNumber()); Logger.trace("FBModule id: " + fm.getId() + " S 1 id:" + fm.getSensor(0).getId() + " contactId: " + fm.getSensor(0).getContactId() + " ModuleNr: " + fm.getSensor(0).getDeviceId() + " Name " + fm.getSensor(0).getName()); Logger.trace("FBModule id: " + fm.getId() + " S 15 id:" + fm.getSensor(15).getId() + " contactId: " + fm.getSensor(15).getContactId() + " ModuleNr: " + fm.getSensor(15).getDeviceId() + " Name " + fm.getSensor(15).getName()); diff --git a/src/main/java/jcs/commandStation/esu/ecos/FeedbackManager.java b/src/main/java/jcs/commandStation/esu/ecos/FeedbackManager.java index 85f87512..74c5dde7 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/FeedbackManager.java +++ b/src/main/java/jcs/commandStation/esu/ecos/FeedbackManager.java @@ -20,7 +20,7 @@ import java.util.List; import java.util.Map; import jcs.commandStation.events.SensorEvent; -import jcs.entities.FeedbackModuleBean; +import jcs.commandStation.entities.FeedbackModule; import org.tinylog.Logger; /** @@ -36,7 +36,7 @@ class FeedbackManager { private static final String ESU_ECOS_CS = "esu-ecos"; private final EsuEcosCommandStationImpl ecosCommandStation; - private final Map modules; + private final Map modules; FeedbackManager(EsuEcosCommandStationImpl ecosCommandStation, EcosMessage message) { this.ecosCommandStation = ecosCommandStation; @@ -53,14 +53,14 @@ private List parse(EcosMessage message) { int objectId = message.getObjectId(); if (ID != objectId) { - FeedbackModuleBean feedbackModule; + FeedbackModule feedbackModule; if (modules.containsKey(objectId)) { feedbackModule = modules.get(objectId); } else { - feedbackModule = new FeedbackModuleBean(); + feedbackModule = new FeedbackModule(); feedbackModule.setId(objectId); feedbackModule.setAddressOffset(0); - feedbackModule.setModuleNumber(objectId - S88_OFFSET); + feedbackModule.setModuleNumber(objectId - S88_OFFSET + 1); //ESU ECoS has 1 bus feedbackModule.setIdentifier(0); //In Unit Testcase the command station is null @@ -100,12 +100,13 @@ private List parse(EcosMessage message) { if (values.containsKey(Ecos.SIZE)) { int size = Integer.parseInt(values.get(Ecos.SIZE).toString()); for (int i = 0; i < size; i++) { - FeedbackModuleBean fbmb = new FeedbackModuleBean(); + FeedbackModule fbmb = new FeedbackModule(); fbmb.setAddressOffset(0); - fbmb.setModuleNumber(i); + fbmb.setModuleNumber(i + 1); fbmb.setId(S88_OFFSET + i); fbmb.setPortCount(S88_DEFAULT_PORT_COUNT); fbmb.setIdentifier(0); + fbmb.setBusSize(size); //In Unit Testcase the command station is null if (ecosCommandStation != null) { @@ -132,7 +133,7 @@ public int getSize() { return this.modules.size(); } - void updatePorts(String state, FeedbackModuleBean s88) { + void updatePorts(String state, FeedbackModule s88) { String val = state.replace("0x", ""); int l = 4 - val.length(); for (int i = 0; i < l; i++) { @@ -143,8 +144,8 @@ void updatePorts(String state, FeedbackModuleBean s88) { int[] prevPorts = s88.getPrevPorts(); if (ports == null) { - ports = new int[FeedbackModuleBean.DEFAULT_PORT_COUNT]; - prevPorts = new int[FeedbackModuleBean.DEFAULT_PORT_COUNT]; + ports = new int[FeedbackModule.DEFAULT_PORT_COUNT]; + prevPorts = new int[FeedbackModule.DEFAULT_PORT_COUNT]; } //Set the previous ports State System.arraycopy(ports, 0, prevPorts, 0, ports.length); @@ -160,11 +161,11 @@ void updatePorts(String state, FeedbackModuleBean s88) { s88.setPorts(ports); } - public Map getModules() { + public Map getModules() { return modules; } - public FeedbackModuleBean getFeedbackModule(int id) { + public FeedbackModule getFeedbackModule(int id) { return modules.get(id); } } diff --git a/src/main/java/jcs/commandStation/esu/ecos/net/EcosVirtualConnection.java b/src/main/java/jcs/commandStation/esu/ecos/net/EcosVirtualConnection.java index 4430705a..931b1c3b 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/net/EcosVirtualConnection.java +++ b/src/main/java/jcs/commandStation/esu/ecos/net/EcosVirtualConnection.java @@ -26,7 +26,7 @@ import jcs.commandStation.events.SensorEvent; import jcs.commandStation.VirtualConnection; import jcs.entities.AccessoryBean; -import jcs.entities.FeedbackModuleBean; +import jcs.commandStation.entities.FeedbackModule; import jcs.entities.FunctionBean; import jcs.entities.LocomotiveBean; import jcs.entities.SensorBean; @@ -197,7 +197,7 @@ public synchronized EcosMessage sendMessage(EcosMessage message) { } } else if (objId >= 100 && objId < 999) { if (Ecos.CMD_GET.equals(cmd)) { - FeedbackModuleBean module = getFeedbackModule(objId); + FeedbackModule module = getFeedbackModule(objId); replyBuilder.append(module.getAddressOffset() + module.getModuleNumber()); replyBuilder.append(" state[0x"); replyBuilder.append(module.getAccumulatedPortsValue()); @@ -334,6 +334,7 @@ public synchronized EcosMessage sendMessage(EcosMessage message) { replyBuilder.append("]"); } } + } replyBuilder.append(""); @@ -402,11 +403,11 @@ static String getSymbol(String type) { }; } - FeedbackModuleBean getFeedbackModule(int moduleId) { + FeedbackModule getFeedbackModule(int moduleId) { List sensors = PersistenceFactory.getService().getSensors(); int id = moduleId; int moduleNr = id - 100; - FeedbackModuleBean module = new FeedbackModuleBean(); + FeedbackModule module = new FeedbackModule(); module.setId(id); module.setModuleNumber(moduleNr); module.setPortCount(16); @@ -426,7 +427,7 @@ FeedbackModuleBean getFeedbackModule(int moduleId) { @Override public void sendEvent(SensorEvent sensorEvent) { Logger.trace("Device: " + sensorEvent.getDeviceId() + " contact: " + sensorEvent.getContactId() + " -> " + sensorEvent.isActive()); - FeedbackModuleBean fbm = getFeedbackModule(100 + sensorEvent.getDeviceId()); + FeedbackModule fbm = getFeedbackModule(100 + sensorEvent.getDeviceId()); //Logger.trace(fbm.getIdString()+" nr: "+fbm.getModuleNumber() + " Current ports: " + fbm.portToString()); int port = sensorEvent.getContactId() - 1; fbm.setPortValue(port, sensorEvent.isActive()); diff --git a/src/main/java/jcs/commandStation/hsis88/HSIImpl.java b/src/main/java/jcs/commandStation/hsis88/HSIImpl.java index 5e10c74d..8dd0d3c0 100644 --- a/src/main/java/jcs/commandStation/hsis88/HSIImpl.java +++ b/src/main/java/jcs/commandStation/hsis88/HSIImpl.java @@ -30,7 +30,7 @@ import static jcs.commandStation.hsis88.HSIConnection.COMMAND_VERSION; import jcs.entities.CommandStationBean; import jcs.entities.CommandStationBean.ConnectionType; -import jcs.entities.FeedbackModuleBean; +import jcs.commandStation.entities.FeedbackModule; import jcs.commandStation.entities.InfoBean; import jcs.commandStation.VirtualConnection; import jcs.commandStation.entities.Device; @@ -168,7 +168,7 @@ public List getDevices() { } @Override - public List getFeedbackModules() { + public List getFeedbackModules() { return null; } diff --git a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java index ac637dc6..4184a799 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java +++ b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java @@ -64,7 +64,7 @@ import jcs.entities.CommandStationBean; import jcs.commandStation.entities.InfoBean; import jcs.commandStation.marklin.cs.can.parser.AccessoryMessage; -import jcs.entities.FeedbackModuleBean; +import jcs.commandStation.entities.FeedbackModule; import jcs.commandStation.marklin.cs2.LocomotiveDirectionEventParser; import jcs.commandStation.marklin.cs2.LocomotiveFunctionEventParser; import jcs.commandStation.marklin.cs.can.parser.LocomotiveVelocityMessage; @@ -491,6 +491,7 @@ public List getDevices() { d.setSoftwareVersion(cd.getVersion()); d.setHardwareVersion(cd.getHwVersion()); d.setChannels(cd.getConfigChannelCount()); + d.setFeedback(CanDevice.FEEDBACK_DEVICE_NAME.equals(cd.getName())); devices.add(d); } @@ -498,13 +499,13 @@ public List getDevices() { } @Override - public List getFeedbackModules() { + public List getFeedbackModules() { //Feedbackmodules can be queried from the Link S88 if available. //In case of a CS 3 Plus or CS 2 there should be a node "0" which could have max 32 S88 modules. //TODO: Test with CS-3Plus and CS2. //Link S88 - List feedbackModules = new ArrayList<>(); - CanDevice links88 = getCanDevice("Link S88"); + List feedbackModules = new ArrayList<>(); + CanDevice links88 = getCanDevice(CanDevice.FEEDBACK_DEVICE_NAME); int bus1Len = 0, bus2Len = 0, bus3Len = 0, nodeId = 0; if (links88 != null) { nodeId = links88.getIdentifierInt() + 1; @@ -523,50 +524,54 @@ public List getFeedbackModules() { //Link S88 has 16 sensors starting from 0 //Bus 1 offset 1000, Bus 2 offset 2000 and Bus 3 offset 3000 - FeedbackModuleBean l = new FeedbackModuleBean(); + FeedbackModule l = new FeedbackModule(); l.setId(0); l.setAddressOffset(0); - l.setModuleNumber(0); + l.setModuleNumber(1); l.setPortCount(16); l.setIdentifier(nodeId); l.setBusNumber(0); l.setCommandStationId(commandStationBean.getId()); + l.setBusSize(1); feedbackModules.add(l); for (int i = 0; i < bus1Len; i++) { - FeedbackModuleBean b1 = new FeedbackModuleBean(); + FeedbackModule b1 = new FeedbackModule(); //Use the offset plus module nr as the id b1.setId(1000 + i); b1.setAddressOffset(1000); - b1.setModuleNumber(i); + b1.setModuleNumber(i + 1); b1.setPortCount(16); b1.setIdentifier(nodeId); b1.setBusNumber(1); b1.setCommandStationId(commandStationBean.getId()); + b1.setBusSize(bus1Len); feedbackModules.add(b1); } for (int i = 0; i < bus2Len; i++) { - FeedbackModuleBean b2 = new FeedbackModuleBean(); + FeedbackModule b2 = new FeedbackModule(); b2.setId(2000 + i); b2.setAddressOffset(2000); - b2.setModuleNumber(i); + b2.setModuleNumber(i + 1); b2.setPortCount(16); b2.setIdentifier(nodeId); b2.setBusNumber(2); b2.setCommandStationId(commandStationBean.getId()); + b2.setBusSize(bus2Len); feedbackModules.add(b2); } for (int i = 0; i < bus3Len; i++) { - FeedbackModuleBean b3 = new FeedbackModuleBean(); + FeedbackModule b3 = new FeedbackModule(); b3.setId(3000 + i); b3.setAddressOffset(3000); - b3.setModuleNumber(i); + b3.setModuleNumber(i + 1); b3.setPortCount(16); b3.setIdentifier(nodeId); b3.setBusNumber(3); b3.setCommandStationId(commandStationBean.getId()); + b3.setBusSize(bus3Len); feedbackModules.add(b3); } @@ -1258,9 +1263,9 @@ public static void main(String[] a) { // // Logger.debug("Switch Accessory 2 to Green"); //cs.switchAccessory(2, AccessoryValue.GREEN, 250); - List feedbackModules = cs.getFeedbackModules(); + List feedbackModules = cs.getFeedbackModules(); Logger.trace("There are " + feedbackModules + " Feedback Modules"); - for (FeedbackModuleBean fm : feedbackModules) { + for (FeedbackModule fm : feedbackModules) { Logger.trace("Module id: " + fm.getId() + " Module nr: " + fm.getModuleNumber() + " ports: " + fm.getPortCount() + " NodeId: " + fm.getIdentifier() + " BusNr: " + fm.getBusNumber()); Logger.trace("FBModule id: " + fm.getId() + " S 1 id:" + fm.getSensor(0).getId() + " contactId: " + fm.getSensor(0).getContactId() + " ModuleNr: " + fm.getSensor(0).getDeviceId() + " Name " + fm.getSensor(0).getName()); Logger.trace("FBModule id: " + fm.getId() + " S 15 id:" + fm.getSensor(15).getId() + " contactId: " + fm.getSensor(15).getContactId() + " ModuleNr: " + fm.getSensor(15).getDeviceId() + " Name " + fm.getSensor(15).getName()); diff --git a/src/main/java/jcs/commandStation/marklin/cs/can/device/CanDevice.java b/src/main/java/jcs/commandStation/marklin/cs/can/device/CanDevice.java index 587074f7..5b358d8c 100644 --- a/src/main/java/jcs/commandStation/marklin/cs/can/device/CanDevice.java +++ b/src/main/java/jcs/commandStation/marklin/cs/can/device/CanDevice.java @@ -41,10 +41,13 @@ public class CanDevice { private String serial; private String articleNumber; private String name; + private String shortName; private final Map measuringChannels; private final Map configChannels; + public static final String FEEDBACK_DEVICE_NAME = "Link S88"; + public CanDevice() { measuringChannels = new HashMap<>(); configChannels = new HashMap<>(); @@ -91,6 +94,14 @@ public void setName(String name) { this.name = name; } + public String getShortName() { + return shortName; + } + + public void setShortName(String shortName) { + this.shortName = shortName; + } + public String getIdentifier() { return identifier; } diff --git a/src/main/java/jcs/commandStation/marklin/cs/can/parser/FeedbackEventMessage.java b/src/main/java/jcs/commandStation/marklin/cs/can/parser/FeedbackEventMessage.java index 5d400446..f8938fe6 100644 --- a/src/main/java/jcs/commandStation/marklin/cs/can/parser/FeedbackEventMessage.java +++ b/src/main/java/jcs/commandStation/marklin/cs/can/parser/FeedbackEventMessage.java @@ -48,7 +48,19 @@ public static SensorBean parse(CanMessage message, Date eventDate) { Integer millis = ByteUtil.toInt(new byte[]{data[6], data[7]}) * 10; - SensorBean sensorBean = new SensorBean(contactId, null, null, null, identifier, status, previousStatus, millis, System.currentTimeMillis(), MARKLIN_CS); + //Derive the busNumber + int busNumber; + if (contactId < 1000) { + busNumber = 0; + } else if (contactId >= 1000 && contactId < 2000) { + busNumber = 1; + } else if (contactId >= 2000 && contactId < 3000) { + busNumber = 2; + } else { + busNumber = 3; + } + + SensorBean sensorBean = new SensorBean(contactId, null, null, null, identifier, status, previousStatus, millis, System.currentTimeMillis(), MARKLIN_CS, busNumber); return sensorBean; } else { Logger.warn("Can't parse message, not a Sensor Response! " + resp); diff --git a/src/main/java/jcs/commandStation/marklin/parser/GeraetParser.java b/src/main/java/jcs/commandStation/marklin/parser/GeraetParser.java index eeed9175..1af28f9f 100644 --- a/src/main/java/jcs/commandStation/marklin/parser/GeraetParser.java +++ b/src/main/java/jcs/commandStation/marklin/parser/GeraetParser.java @@ -35,7 +35,7 @@ public static CanDevice parseFile(String geraetFile) { if (geraetFile == null) { return null; } - + CanDevice gfp = new CanDevice(); //InfoBean ib = new InfoBean(); //ib.copyInto(commandStationBean); @@ -50,10 +50,10 @@ public static CanDevice parseFile(String geraetFile) { } String key = line.substring(0, eqidx).trim(); String value = line.substring(eqidx).replace("=", "").trim(); - + switch (key) { case "[geraet]" -> { - + } case ".major" -> { major = value; @@ -86,22 +86,24 @@ public static CanDevice parseFile(String geraetFile) { } } } - + String softwareVersion = (major != null ? major : "") + (major != null ? "." : "") + (minor != null ? minor : ""); //ib.setSoftwareVersion(softwareVersion); gfp.setVersion(softwareVersion); - - if (gfp.getSerial().length() < 5) { + + if (gfp.getSerial() != null & gfp.getSerial().length() < 5) { gfp.setSerial("0" + gfp.getSerial()); } - + String shortName; if (gfp.getName() != null && gfp.getName().contains("Central Station 3")) { shortName = "CS3"; } else { shortName = "CS2"; } - + + gfp.setShortName(shortName); + gfp.setIdentifier("0x00"); return gfp; } @@ -116,9 +118,9 @@ public static InfoBean parseJson(String json) { if (json == null) { return null; } - + InfoBean ib = new InfoBean(); - + JSONObject infoObject = new JSONObject(json); ib.setSoftwareVersion(infoObject.optString("softwareVersion")); ib.setHardwareVersion(infoObject.optString("hardwareVersion")); @@ -128,8 +130,8 @@ public static InfoBean parseJson(String json) { ib.setHostname(infoObject.optString("hostname")); ib.setGfpUid(infoObject.optString("gfpUid")); ib.setGuiUid(infoObject.optString("guiUid")); - + return ib; } - + } diff --git a/src/main/java/jcs/commandStation/virtual/VirtualCommandStationImpl.java b/src/main/java/jcs/commandStation/virtual/VirtualCommandStationImpl.java index af1fce0e..56adfb87 100644 --- a/src/main/java/jcs/commandStation/virtual/VirtualCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/virtual/VirtualCommandStationImpl.java @@ -40,7 +40,7 @@ import jcs.commandStation.events.SensorEventListener; import jcs.entities.AccessoryBean; import jcs.entities.CommandStationBean; -import jcs.entities.FeedbackModuleBean; +import jcs.commandStation.entities.FeedbackModule; import jcs.commandStation.entities.InfoBean; import jcs.entities.LocomotiveBean; import jcs.util.NetworkUtil; @@ -290,7 +290,7 @@ public List getAccessories() { } @Override - public List getFeedbackModules() { + public List getFeedbackModules() { throw new UnsupportedOperationException("Not supported yet."); } diff --git a/src/main/java/jcs/entities/SensorBean.java b/src/main/java/jcs/entities/SensorBean.java index b9b53162..a9d69ca8 100755 --- a/src/main/java/jcs/entities/SensorBean.java +++ b/src/main/java/jcs/entities/SensorBean.java @@ -38,24 +38,25 @@ public class SensorBean { private Long lastUpdated; private Integer nodeId; private String commandStationId; + private Integer busNr; public SensorBean() { - this(null, null, null, null, null, null, null); + this(null, null, null, null, null, null, null, 0); } - public SensorBean(Integer id, Integer deviceId, Integer contactId, Integer nodeId, Integer status, Integer previousStatus, String commandStationId) { - this(id, null, deviceId, contactId, nodeId, status, previousStatus, (Integer) null, (Long) null, commandStationId); + public SensorBean(Integer id, Integer deviceId, Integer contactId, Integer nodeId, Integer status, Integer previousStatus, String commandStationId, Integer busNr) { + this(id, null, deviceId, contactId, nodeId, status, previousStatus, (Integer) null, (Long) null, commandStationId, busNr); } - public SensorBean(Integer id, String name, Integer deviceId, Integer contactId, Integer nodeId, Integer status, Integer previousStatus, Integer millis, String commandStationId) { - this(id, name, deviceId, contactId, nodeId, status, previousStatus, millis, (Long) null, commandStationId); + public SensorBean(Integer id, String name, Integer deviceId, Integer contactId, Integer nodeId, Integer status, Integer previousStatus, Integer millis, String commandStationId, Integer busNr) { + this(id, name, deviceId, contactId, nodeId, status, previousStatus, millis, (Long) null, commandStationId, busNr); } - public SensorBean(Integer id, String name, Integer deviceId, Integer contactId, Integer nodeId, Integer status, Integer previousStatus, Integer millis, Date lastUpdated, String commandStationId) { - this(id, name, deviceId, contactId, nodeId, status, previousStatus, millis, (lastUpdated != null ? lastUpdated.getTime() : null), commandStationId); + public SensorBean(Integer id, String name, Integer deviceId, Integer contactId, Integer nodeId, Integer status, Integer previousStatus, Integer millis, Date lastUpdated, String commandStationId, Integer busNr) { + this(id, name, deviceId, contactId, nodeId, status, previousStatus, millis, (lastUpdated != null ? lastUpdated.getTime() : null), commandStationId, busNr); } - public SensorBean(Integer id, String name, Integer deviceId, Integer contactId, Integer nodeId, Integer status, Integer previousStatus, Integer millis, Long lastUpdated, String commandStationId) { + public SensorBean(Integer id, String name, Integer deviceId, Integer contactId, Integer nodeId, Integer status, Integer previousStatus, Integer millis, Long lastUpdated, String commandStationId, Integer busNr) { this.id = id; this.name = name; this.status = status; @@ -66,13 +67,15 @@ public SensorBean(Integer id, String name, Integer deviceId, Integer contactId, this.millis = millis; this.lastUpdated = lastUpdated; this.commandStationId = commandStationId; + this.busNr = busNr; + //TODO! if (name == null) { - this.name = generateName(); + //this.name = generateName(); } } - private String generateName() { + private String generateNameOld() { if (deviceId != null && contactId != null && nodeId != null) { String dn = deviceId.toString(); @@ -106,7 +109,7 @@ public void setId(Integer id) { @Column(name = "name", length = 255, nullable = false) public String getName() { if (name == null) { - name = generateName(); + //name = generateName(); } return name; } @@ -169,6 +172,15 @@ public void setCommandStationId(String commandStationId) { this.commandStationId = commandStationId; } + @Column(name = "bus_nr", nullable = false) + public Integer getBusNr() { + return busNr; + } + + public void setBusNr(Integer busNr) { + this.busNr = busNr; + } + @Transient public void toggle() { if (status == null) { @@ -273,6 +285,7 @@ public int hashCode() { hash = 41 * hash + Objects.hashCode(this.millis); hash = 41 * hash + Objects.hashCode(this.lastUpdated); hash = 41 * hash + Objects.hashCode(this.commandStationId); + hash = 41 * hash + Objects.hashCode(this.busNr); return hash; } @@ -315,9 +328,13 @@ public boolean equals(Object obj) { if (!Objects.equals(this.commandStationId, other.commandStationId)) { return false; } + if (!Objects.equals(this.busNr, other.busNr)) { + return false; + } return Objects.equals(this.lastUpdated, other.lastUpdated); } + @Deprecated public boolean equalsDeviceIdAndContactId(Object obj) { if (this == obj) { return true; @@ -387,6 +404,8 @@ public String toLogString() { + lastUpdated + ", commandStationId=" + commandStationId + + ", busNr=" + + busNr + "}"; } } diff --git a/src/main/java/jcs/persistence/H2PersistenceService.java b/src/main/java/jcs/persistence/H2PersistenceService.java index 7a2aba4b..647e5dac 100755 --- a/src/main/java/jcs/persistence/H2PersistenceService.java +++ b/src/main/java/jcs/persistence/H2PersistenceService.java @@ -117,11 +117,23 @@ public void remove(JCSPropertyBean property) { } @Override - public List getSensors() { + public List getAllSensors() { List sensors = database.results(SensorBean.class); return sensors; } + @Override + public List getSensors() { + String commandStationId = getDefaultCommandStation().getId(); + return getSensorsByCommandStationId(commandStationId); + } + + @Override + public List getSensorsByCommandStationId(String commandStationId) { + List sensors = database.where("command_station_id=?", commandStationId).orderBy("id").results(SensorBean.class); + return sensors; + } + @Override public List getAssignedSensors() { List sensorTiles = getTileBeansByTileType(TileBean.TileType.SENSOR); @@ -943,11 +955,11 @@ public CommandStationBean getDefaultCommandStation() { return database.where("default_cs=true").first(CommandStationBean.class); } - @Override + @Override public CommandStationBean getEnabledFeedbackProvider() { return database.where("default_cs=false and supports_feedback=true and supports_decoder_control=false and enabled=true").first(CommandStationBean.class); } - + @Override public synchronized CommandStationBean persist(CommandStationBean commandStationBean) { CommandStationBean prev = database.where("id=?", commandStationBean.getId()).first(CommandStationBean.class); diff --git a/src/main/java/jcs/persistence/PersistenceService.java b/src/main/java/jcs/persistence/PersistenceService.java index 73bf2e5f..50d64291 100755 --- a/src/main/java/jcs/persistence/PersistenceService.java +++ b/src/main/java/jcs/persistence/PersistenceService.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Frans Jacobs. + * Copyright 2025 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -81,12 +81,26 @@ public interface PersistenceService { // Sensors /** - * Retrieves all SensorBeans. + * Retrieves All SensorBeans + * + * @return A List of SensorBeans. + */ + List getAllSensors(); + + /** + * Retrieves SensorBeans for the default command station * * @return A List of SensorBeans. */ List getSensors(); + /** + * + * @param commandStationId the command station id for which the sensors are retrieved + * @return A List of SensorBeans + */ + List getSensorsByCommandStationId(String commandStationId); + /** * Retrieves all assigned SensorBeans. * diff --git a/src/main/java/jcs/ui/panel/SmallDriverCabPanel.java b/src/main/java/jcs/ui/panel/SmallDriverCabPanel.java index 3f1ad795..9e8ee77b 100644 --- a/src/main/java/jcs/ui/panel/SmallDriverCabPanel.java +++ b/src/main/java/jcs/ui/panel/SmallDriverCabPanel.java @@ -119,7 +119,7 @@ public void setEnabled(boolean enabled) { buttonsTP.setEnabled(enabled); } - //@Override + @Override public void onFunctionChange(LocomotiveFunctionEvent event) { if (locomotiveBean != null && locomotiveBean.getId().equals(event.getFunctionBean().getLocomotiveId())) { FunctionBean fb = event.getFunctionBean(); diff --git a/src/main/java/jcs/ui/settings/CommandStationDialog.form b/src/main/java/jcs/ui/settings/CommandStationDialog.form index 374c9a31..17426a57 100644 --- a/src/main/java/jcs/ui/settings/CommandStationDialog.form +++ b/src/main/java/jcs/ui/settings/CommandStationDialog.form @@ -1,11 +1,12 @@
+ + + + - - - @@ -21,88 +22,421 @@ - + - - - - - - - - - - - - - + - + - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - + - - - - - - - - + - - - - + - + - + - + - - + + - + @@ -110,26 +444,721 @@ - + - + - - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/jcs/ui/settings/CommandStationDialog.java b/src/main/java/jcs/ui/settings/CommandStationDialog.java index 5bdae197..205d3e1b 100644 --- a/src/main/java/jcs/ui/settings/CommandStationDialog.java +++ b/src/main/java/jcs/ui/settings/CommandStationDialog.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Frans Jacobs. + * Copyright 2025 fransjacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,75 +15,1065 @@ */ package jcs.ui.settings; +import com.fazecast.jSerialComm.SerialPort; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import javax.swing.ComboBoxModel; +import javax.swing.DefaultComboBoxModel; +import javax.swing.JOptionPane; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; +import jcs.JCS; +import jcs.commandStation.esu.ecos.net.EcosConnectionFactory; +import jcs.commandStation.marklin.cs.net.CSConnectionFactory; +import jcs.entities.CommandStationBean; +import jcs.persistence.PersistenceFactory; import org.tinylog.Logger; +import java.net.InetAddress; +import java.util.Collections; +import javax.swing.JDialog; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeSelectionModel; +import jcs.commandStation.DecoderController; +import jcs.commandStation.FeedbackController; +import jcs.commandStation.entities.Device; +import jcs.commandStation.entities.InfoBean; +import jcs.commandStation.esu.ecos.EsuEcosCommandStationImpl; +import jcs.commandStation.marklin.cs.MarklinCentralStationImpl; +import jcs.commandStation.entities.FeedbackModule; +import jcs.entities.SensorBean; +import jcs.util.Ping; /** * - * @author frans + * @author fransjacobs */ -public class CommandStationDialog extends javax.swing.JDialog { +public class CommandStationDialog extends JDialog implements TreeSelectionListener { + + private ComboBoxModel commandStationCBM; + private ComboBoxModel feedbackCBM; + private ComboBoxModel serialPortCBM; + private ComboBoxModel fbpSerialPortCBM; + private CommandStationBean selectedCommandStation; + private CommandStationBean selectedFeedbackProvider; + + private final ExecutorService executor; + + private CommandStationBean emptyCS; + private CommandStationBean emptyFB; + + private static final String MARKLIN_CS = "marklin.cs"; + private static final String ESU_ECOS = "esu-ecos"; + private static final String DCC_EX = "dcc-ex"; + private static final String HSI_S88 = "hsi-s88"; + + private DecoderController controller; /** - * Creates new form CommandStationDialog - * @param parent - * @param modal + * Creates new form CommandStationDialog1 */ public CommandStationDialog(java.awt.Frame parent, boolean modal) { super(parent, modal); initComponents(); + executor = Executors.newSingleThreadExecutor(); + if (PersistenceFactory.getService() != null) { + initModels(null); + } + + } + + private void initModels(CommandStationBean selected) { + if (selected == null) { + selectedCommandStation = PersistenceFactory.getService().getDefaultCommandStation(); + } else { + selectedCommandStation = selected; + } + + if (selectedCommandStation != null && !selectedCommandStation.isFeedbackSupport()) { + selectedFeedbackProvider = PersistenceFactory.getService().getEnabledFeedbackProvider(); + } + + List allCommandStations = PersistenceFactory.getService().getCommandStations(); + + List commandStations = new ArrayList<>(); + List feedbackProviders = new ArrayList<>(); + + for (CommandStationBean csb : allCommandStations) { + if (csb.isDecoderControlSupport()) { + commandStations.add(csb); + } else { + feedbackProviders.add(csb); + } + } + + emptyCS = new CommandStationBean(); + emptyCS.setDecoderControlSupport(true); + emptyFB = new CommandStationBean(); + emptyFB.setFeedbackSupport(true); + + commandStations.add(emptyCS); + feedbackProviders.add(emptyFB); + + if (selectedCommandStation == null) { + selectedCommandStation = emptyCS; + } + + if (selectedFeedbackProvider == null) { + selectedFeedbackProvider = emptyFB; + } + + CommandStationBean[] csba = new CommandStationBean[commandStations.size()]; + CommandStationBean[] fbpa = new CommandStationBean[feedbackProviders.size()]; + commandStations.toArray(csba); + feedbackProviders.toArray(fbpa); + + commandStationCBM = new DefaultComboBoxModel<>(csba); + commandStationCBM.setSelectedItem(selectedCommandStation); + commandStationCB.setModel(commandStationCBM); + + feedbackCBM = new DefaultComboBoxModel<>(fbpa); + feedbackCBM.setSelectedItem(selectedFeedbackProvider); + feedbackCB.setModel(feedbackCBM); + + SerialPort comPorts[] = SerialPort.getCommPorts(); + String[] ports = new String[comPorts.length]; + for (int i = 0; i < comPorts.length; i++) { + ports[i] = comPorts[i].getSystemPortName(); + } + + serialPortCBM = new DefaultComboBoxModel<>(ports); + fbpSerialPortCBM = new DefaultComboBoxModel<>(ports); + serialCB.setModel(serialPortCBM); + fbpSerialCB.setModel(fbpSerialPortCBM); + + if (CommandStationBean.ConnectionType.SERIAL == selectedCommandStation.getConnectionType()) { + String port = selectedCommandStation.getSerialPort(); + serialCB.setSelectedItem(port); + serialRB.setSelected(true); + } else { + networkRB.setSelected(true); + } + + if (selectedFeedbackProvider.getConnectionType() != null && CommandStationBean.ConnectionType.SERIAL == selectedFeedbackProvider.getConnectionType()) { + String port = selectedFeedbackProvider.getSerialPort(); + fbpSerialCB.setSelectedItem(port); + } + + setComponents(); + if (!selectedCommandStation.isVirtual() && CommandStationBean.ConnectionType.NETWORK == selectedCommandStation.getConnectionType() && selectedCommandStation.getIpAddress() != null && selectedCommandStation.getIpAddress().length() > 8) { + executor.execute(() -> checkConnection(selectedCommandStation)); + } } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") - // //GEN-BEGIN:initComponents - private void initComponents() { - - commandStationPanel1 = new jcs.ui.settings.CommandStationPanel(); - southPanel = new javax.swing.JPanel(); - exitBtn = new javax.swing.JButton(); - - setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); - setPreferredSize(new java.awt.Dimension(1080, 750)); - getContentPane().add(commandStationPanel1, java.awt.BorderLayout.CENTER); - - southPanel.setPreferredSize(new java.awt.Dimension(1024, 50)); - java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.RIGHT); - flowLayout1.setAlignOnBaseline(true); - southPanel.setLayout(flowLayout1); - - exitBtn.setIcon(new javax.swing.ImageIcon(getClass().getResource("/media/exit-24.png"))); // NOI18N - exitBtn.setText("Close"); - exitBtn.setPreferredSize(new java.awt.Dimension(100, 36)); - exitBtn.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - exitBtnActionPerformed(evt); - } - }); - southPanel.add(exitBtn); - - getContentPane().add(southPanel, java.awt.BorderLayout.SOUTH); - - pack(); - }// //GEN-END:initComponents - - private void exitBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exitBtnActionPerformed - this.setVisible(false); - this.dispose(); - }//GEN-LAST:event_exitBtnActionPerformed + // //GEN-BEGIN:initComponents + private void initComponents() { + + connectionTypeBG = new javax.swing.ButtonGroup(); + topPanel = new javax.swing.JPanel(); + mainCSPanel = new javax.swing.JPanel(); + commandStationLbl = new javax.swing.JLabel(); + commandStationCB = new javax.swing.JComboBox<>(); + virtualCB = new javax.swing.JCheckBox(); + ipOrPortLbl = new javax.swing.JLabel(); + ipTF = new javax.swing.JTextField(); + serialCB = new javax.swing.JComboBox<>(); + controllerLbl = new javax.swing.JLabel(); + accessoryControllerLbl = new javax.swing.JLabel(); + feedbackProviderLbl = new javax.swing.JLabel(); + discoverBtn = new javax.swing.JButton(); + checkBtn = new javax.swing.JButton(); + networkRB = new javax.swing.JRadioButton(); + serialRB = new javax.swing.JRadioButton(); + feedbackCSPanel = new javax.swing.JPanel(); + feedbackLbl = new javax.swing.JLabel(); + feedbackCB = new javax.swing.JComboBox<>(); + secondfbpLbl = new javax.swing.JLabel(); + fbpSerialLbl = new javax.swing.JLabel(); + fbpSerialCB = new javax.swing.JComboBox<>(); + filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 23), new java.awt.Dimension(0, 23), new java.awt.Dimension(32767, 23)); + jPanel3 = new javax.swing.JPanel(); + jPanel4 = new javax.swing.JPanel(); + connectBtn = new javax.swing.JButton(); + jPanel5 = new javax.swing.JPanel(); + jPanel2 = new javax.swing.JPanel(); + propertiesPanel = new javax.swing.JPanel(); + controllerPanel = new javax.swing.JPanel(); + connectedToLbl = new javax.swing.JLabel(); + serialLbl = new javax.swing.JLabel(); + swVersionLbl = new javax.swing.JLabel(); + hwVersionLbl = new javax.swing.JLabel(); + feedbackPanel = new javax.swing.JPanel(); + feedbackModulesPanel = new javax.swing.JPanel(); + mainLbl = new javax.swing.JLabel(); + mainSpinner = new javax.swing.JSpinner(); + bus1Lbl = new javax.swing.JLabel(); + bus1Spinner = new javax.swing.JSpinner(); + bus2Lbl = new javax.swing.JLabel(); + bus2Spinner = new javax.swing.JSpinner(); + bus3Lbl = new javax.swing.JLabel(); + bus3Spinner = new javax.swing.JSpinner(); + filler2 = new javax.swing.Box.Filler(new java.awt.Dimension(100, 0), new java.awt.Dimension(100, 0), new java.awt.Dimension(100, 32767)); + updatePanel = new javax.swing.JPanel(); + updateBtn = new javax.swing.JButton(); + jPanel6 = new javax.swing.JPanel(); + devicesPanel = new javax.swing.JPanel(); + devicesSP = new javax.swing.JScrollPane(); + devicesTree = new javax.swing.JTree(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + + jcs.ui.swing.layout.VerticalFlowLayout verticalFlowLayout1 = new jcs.ui.swing.layout.VerticalFlowLayout(); + verticalFlowLayout1.sethAlignment(0); + topPanel.setLayout(verticalFlowLayout1); + + mainCSPanel.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT)); + + commandStationLbl.setLabelFor(commandStationCB); + commandStationLbl.setText("Command Station"); + commandStationLbl.setPreferredSize(new java.awt.Dimension(110, 17)); + mainCSPanel.add(commandStationLbl); + + commandStationCB.setPreferredSize(new java.awt.Dimension(200, 23)); + commandStationCB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + commandStationCBActionPerformed(evt); + } + }); + mainCSPanel.add(commandStationCB); + + virtualCB.setText("Virtual"); + virtualCB.setToolTipText("Use Virtual Connection"); + virtualCB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + virtualCBActionPerformed(evt); + } + }); + mainCSPanel.add(virtualCB); + + ipOrPortLbl.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); + ipOrPortLbl.setLabelFor(ipTF); + ipOrPortLbl.setText("ip Address:"); + ipOrPortLbl.setPreferredSize(new java.awt.Dimension(105, 17)); + mainCSPanel.add(ipOrPortLbl); + + ipTF.setPreferredSize(new java.awt.Dimension(120, 23)); + ipTF.addFocusListener(new java.awt.event.FocusAdapter() { + public void focusLost(java.awt.event.FocusEvent evt) { + ipTFFocusLost(evt); + } + }); + ipTF.addMouseListener(new java.awt.event.MouseAdapter() { + public void mouseExited(java.awt.event.MouseEvent evt) { + ipTFMouseExited(evt); + } + }); + ipTF.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + ipTFActionPerformed(evt); + } + }); + mainCSPanel.add(ipTF); + + serialCB.setPreferredSize(new java.awt.Dimension(120, 23)); + serialCB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + serialCBActionPerformed(evt); + } + }); + mainCSPanel.add(serialCB); + + controllerLbl.setIcon(new javax.swing.ImageIcon(getClass().getResource("/media/controller-console-24.png"))); // NOI18N + controllerLbl.setToolTipText("Decoder Controller"); + mainCSPanel.add(controllerLbl); + + accessoryControllerLbl.setIcon(new javax.swing.ImageIcon(getClass().getResource("/media/branch-24.png"))); // NOI18N + accessoryControllerLbl.setToolTipText("Accessory Controller"); + mainCSPanel.add(accessoryControllerLbl); + + feedbackProviderLbl.setIcon(new javax.swing.ImageIcon(getClass().getResource("/media/chat-24.png"))); // NOI18N + feedbackProviderLbl.setToolTipText("Feedback Provider"); + mainCSPanel.add(feedbackProviderLbl); + + discoverBtn.setText("Discover"); + discoverBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + discoverBtnActionPerformed(evt); + } + }); + mainCSPanel.add(discoverBtn); + + checkBtn.setText("Check"); + checkBtn.setToolTipText("Check Connection"); + checkBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + checkBtnActionPerformed(evt); + } + }); + mainCSPanel.add(checkBtn); + + connectionTypeBG.add(networkRB); + networkRB.setText("Network"); + networkRB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + networkRBActionPerformed(evt); + } + }); + mainCSPanel.add(networkRB); + + connectionTypeBG.add(serialRB); + serialRB.setText("Serialport"); + serialRB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + serialRBActionPerformed(evt); + } + }); + mainCSPanel.add(serialRB); + + topPanel.add(mainCSPanel); + + java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); + flowLayout1.setAlignOnBaseline(true); + feedbackCSPanel.setLayout(flowLayout1); + + feedbackLbl.setLabelFor(feedbackCB); + feedbackLbl.setText("Feedback Device"); + feedbackLbl.setPreferredSize(new java.awt.Dimension(110, 17)); + feedbackCSPanel.add(feedbackLbl); + + feedbackCB.setPreferredSize(new java.awt.Dimension(200, 23)); + feedbackCB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + feedbackCBActionPerformed(evt); + } + }); + feedbackCSPanel.add(feedbackCB); + + secondfbpLbl.setIcon(new javax.swing.ImageIcon(getClass().getResource("/media/chat-24.png"))); // NOI18N + secondfbpLbl.setToolTipText("Feedback Provicer"); + secondfbpLbl.setPreferredSize(new java.awt.Dimension(25, 24)); + feedbackCSPanel.add(secondfbpLbl); + + fbpSerialLbl.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); + fbpSerialLbl.setText("Serial Port:"); + fbpSerialLbl.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING); + fbpSerialLbl.setPreferredSize(new java.awt.Dimension(75, 17)); + feedbackCSPanel.add(fbpSerialLbl); + + fbpSerialCB.setPreferredSize(new java.awt.Dimension(120, 23)); + fbpSerialCB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + fbpSerialCBActionPerformed(evt); + } + }); + feedbackCSPanel.add(fbpSerialCB); + feedbackCSPanel.add(filler1); + + topPanel.add(feedbackCSPanel); + + getContentPane().add(topPanel, java.awt.BorderLayout.PAGE_START); + + javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3); + jPanel3.setLayout(jPanel3Layout); + jPanel3Layout.setHorizontalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 1406, Short.MAX_VALUE) + ); + jPanel3Layout.setVerticalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 100, Short.MAX_VALUE) + ); + + getContentPane().add(jPanel3, java.awt.BorderLayout.PAGE_END); + + connectBtn.setText("Connect"); + connectBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + connectBtnActionPerformed(evt); + } + }); + jPanel4.add(connectBtn); + + getContentPane().add(jPanel4, java.awt.BorderLayout.LINE_END); + + jPanel5.setPreferredSize(new java.awt.Dimension(100, 400)); + jPanel5.setLayout(new java.awt.BorderLayout()); + getContentPane().add(jPanel5, java.awt.BorderLayout.LINE_START); + + jPanel2.setLayout(new java.awt.BorderLayout()); + + propertiesPanel.setLayout(new java.awt.BorderLayout()); + + controllerPanel.setPreferredSize(new java.awt.Dimension(695, 40)); + java.awt.FlowLayout flowLayout3 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); + flowLayout3.setAlignOnBaseline(true); + controllerPanel.setLayout(flowLayout3); + + connectedToLbl.setText("Connected to: command station"); + connectedToLbl.setPreferredSize(new java.awt.Dimension(200, 17)); + controllerPanel.add(connectedToLbl); + + serialLbl.setText("Serial: xxxxxx"); + serialLbl.setPreferredSize(new java.awt.Dimension(150, 17)); + controllerPanel.add(serialLbl); + + swVersionLbl.setText("Software version: xxxxxxx"); + swVersionLbl.setPreferredSize(new java.awt.Dimension(160, 17)); + controllerPanel.add(swVersionLbl); + + hwVersionLbl.setText("Hardware version: xxxxxx"); + hwVersionLbl.setPreferredSize(new java.awt.Dimension(160, 17)); + controllerPanel.add(hwVersionLbl); + + propertiesPanel.add(controllerPanel, java.awt.BorderLayout.NORTH); + + feedbackPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Feedback Modules")); + feedbackPanel.setPreferredSize(new java.awt.Dimension(654, 60)); + feedbackPanel.setLayout(new java.awt.GridLayout(1, 2)); + + java.awt.FlowLayout flowLayout4 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); + flowLayout4.setAlignOnBaseline(true); + feedbackModulesPanel.setLayout(flowLayout4); + + mainLbl.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + mainLbl.setText("Main"); + mainLbl.setPreferredSize(new java.awt.Dimension(40, 17)); + feedbackModulesPanel.add(mainLbl); + + mainSpinner.setModel(new javax.swing.SpinnerNumberModel(0, null, 31, 1)); + feedbackModulesPanel.add(mainSpinner); + + bus1Lbl.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + bus1Lbl.setText("Bus 1"); + bus1Lbl.setPreferredSize(new java.awt.Dimension(40, 17)); + feedbackModulesPanel.add(bus1Lbl); + + bus1Spinner.setModel(new javax.swing.SpinnerNumberModel(0, null, 31, 1)); + feedbackModulesPanel.add(bus1Spinner); + + bus2Lbl.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + bus2Lbl.setText("Bus 2"); + bus2Lbl.setPreferredSize(new java.awt.Dimension(40, 17)); + feedbackModulesPanel.add(bus2Lbl); + + bus2Spinner.setModel(new javax.swing.SpinnerNumberModel(0, null, 31, 1)); + feedbackModulesPanel.add(bus2Spinner); + + bus3Lbl.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + bus3Lbl.setText("Bus 3"); + bus3Lbl.setPreferredSize(new java.awt.Dimension(40, 17)); + feedbackModulesPanel.add(bus3Lbl); + + bus3Spinner.setModel(new javax.swing.SpinnerNumberModel(0, null, 31, 1)); + feedbackModulesPanel.add(bus3Spinner); + feedbackModulesPanel.add(filler2); + + feedbackPanel.add(feedbackModulesPanel); + + updatePanel.setPreferredSize(new java.awt.Dimension(350, 57)); + java.awt.FlowLayout flowLayout2 = new java.awt.FlowLayout(java.awt.FlowLayout.RIGHT); + flowLayout2.setAlignOnBaseline(true); + updatePanel.setLayout(flowLayout2); + + updateBtn.setText("Update"); + updateBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + updateBtnActionPerformed(evt); + } + }); + updatePanel.add(updateBtn); + + feedbackPanel.add(updatePanel); + + propertiesPanel.add(feedbackPanel, java.awt.BorderLayout.SOUTH); + + jPanel2.add(propertiesPanel, java.awt.BorderLayout.PAGE_START); + + jPanel6.setPreferredSize(new java.awt.Dimension(750, 318)); + + javax.swing.GroupLayout jPanel6Layout = new javax.swing.GroupLayout(jPanel6); + jPanel6.setLayout(jPanel6Layout); + jPanel6Layout.setHorizontalGroup( + jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 750, Short.MAX_VALUE) + ); + jPanel6Layout.setVerticalGroup( + jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 317, Short.MAX_VALUE) + ); + + jPanel2.add(jPanel6, java.awt.BorderLayout.EAST); + + devicesPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Devices")); + devicesPanel.setLayout(new java.awt.GridLayout(1, 1)); + + devicesSP.setViewportView(devicesTree); + + devicesPanel.add(devicesSP); + + jPanel2.add(devicesPanel, java.awt.BorderLayout.CENTER); + + getContentPane().add(jPanel2, java.awt.BorderLayout.CENTER); + + pack(); + }// //GEN-END:initComponents + + private void commandStationCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_commandStationCBActionPerformed + CommandStationBean newSelectedCommandStation = (CommandStationBean) commandStationCBM.getSelectedItem(); + if (selectedCommandStation != null && selectedCommandStation.getId() != null && !selectedCommandStation.getId().equals(newSelectedCommandStation.getId())) { + selectedCommandStation.setDefault(false); + selectedCommandStation.setEnabled(false); + try { + if (JCS.getJcsCommandStation() != null && JCS.getJcsCommandStation().isConnected()) { + JCS.getJcsCommandStation().switchPower(false); + } + if (JCS.getParentFrame() != null) { + JCS.getParentFrame().connect(false); + } + } catch (Exception e) { + Logger.error(e.getMessage()); + } + } else { + selectedCommandStation = newSelectedCommandStation; + } + + selectedCommandStation = (CommandStationBean) commandStationCBM.getSelectedItem(); + selectedCommandStation.setEnabled(true); + selectedCommandStation.setDefault(true); + executor.execute(() -> changeDefaultCommandStation(selectedCommandStation)); + + Logger.trace("Selected CS: " + selectedCommandStation.getDescription()); + }//GEN-LAST:event_commandStationCBActionPerformed + + private void setComponents() { + controllerLbl.setVisible(selectedCommandStation.isDecoderControlSupport()); + accessoryControllerLbl.setVisible(selectedCommandStation.isAccessoryControlSupport()); + feedbackProviderLbl.setVisible(selectedCommandStation.isFeedbackSupport()); + + virtualCB.setSelected(selectedCommandStation.isVirtual()); + + discoverBtn.setVisible(selectedCommandStation.isIpAutoConfiguration()); + ipTF.setText(selectedCommandStation.getIpAddress()); + + serialCB.setVisible(CommandStationBean.ConnectionType.SERIAL == selectedCommandStation.getConnectionType()); + ipTF.setVisible(CommandStationBean.ConnectionType.NETWORK == selectedCommandStation.getConnectionType()); + + networkRB.setVisible(selectedCommandStation.getSupportedConnectionTypes().size() > 1); + serialRB.setVisible(selectedCommandStation.getSupportedConnectionTypes().size() > 1); + networkRB.setSelected(CommandStationBean.ConnectionType.NETWORK == selectedCommandStation.getConnectionType()); + + if (serialCB.isVisible()) { + ipOrPortLbl.setText("Serial Port:"); + } else { + ipOrPortLbl.setText("ip Address:"); + } + + checkBtn.setVisible(CommandStationBean.ConnectionType.NETWORK == selectedCommandStation.getConnectionType() && selectedCommandStation.getIpAddress() != null && selectedCommandStation.getIpAddress().length() > 8); + + if (selectedCommandStation.getIpAddress() == null || selectedCommandStation.getIpAddress().length() > 8) { + ipTF.setBackground(new java.awt.Color(255, 255, 255)); + connectBtn.setEnabled(true); + } else { + connectBtn.setEnabled(false); + } + + //no main controller feedback support, enable the secondary + feedbackCB.setVisible(!selectedCommandStation.isFeedbackSupport()); + feedbackCB.setEnabled(!selectedCommandStation.isFeedbackSupport()); + feedbackLbl.setVisible(!selectedCommandStation.isFeedbackSupport()); + + secondfbpLbl.setVisible(!selectedCommandStation.isFeedbackSupport() && selectedFeedbackProvider.isFeedbackSupport() && selectedFeedbackProvider.getId() != null); + + fbpSerialCB.setVisible(!selectedCommandStation.isFeedbackSupport()); + fbpSerialCB.setEnabled(!selectedCommandStation.isFeedbackSupport()); + fbpSerialLbl.setVisible(!selectedCommandStation.isFeedbackSupport()); + + if (controller != null && controller.isConnected()) { + InfoBean ib = controller.getCommandStationInfo(); + connectedToLbl.setText("Connected to : " + ib.getProductName()); + connectedToLbl.setVisible(true); + + serialLbl.setText("Serial: " + ib.getSerialNumber()); + serialLbl.setVisible(true); + + if (ib.getSoftwareVersion() != null) { + swVersionLbl.setText("Software version: " + ib.getSoftwareVersion()); + swVersionLbl.setVisible(true); + } else { + swVersionLbl.setVisible(false); + } + + if (ib.getHardwareVersion() != null) { + hwVersionLbl.setText(("Hardware version: " + ib.getHardwareVersion())); + hwVersionLbl.setVisible(true); + } else { + hwVersionLbl.setVisible(false); + } + + connectBtn.setText("Disconnect"); + + //feedback settings + List modules = ((FeedbackController) controller).getFeedbackModules(); + + mainLbl.setVisible(true); + mainSpinner.setVisible(true); + + updateBtn.setVisible(true); + + for (FeedbackModule fbm : modules) { + Integer busNr = fbm.getBusNumber(); + if (busNr == null) { + //Assume null is the main + busNr = 0; + } + switch (busNr) { + case 1 -> { + bus1Spinner.setValue(fbm.getBusSize()); + } + case 2 -> { + bus2Spinner.setValue(fbm.getBusSize()); + } + case 3 -> { + bus3Spinner.setValue(fbm.getBusSize()); + } + default -> { + mainSpinner.setValue(fbm.getBusSize()); + } + } + } + + if (selectedCommandStation.getId().equals(MARKLIN_CS)) { + bus1Lbl.setVisible(true); + bus1Spinner.setVisible(true); + bus2Lbl.setVisible(true); + bus2Spinner.setVisible(true); + bus3Lbl.setVisible(true); + bus3Spinner.setVisible(true); + } else { + bus1Lbl.setVisible(false); + bus1Spinner.setVisible(false); + bus2Lbl.setVisible(false); + bus2Spinner.setVisible(false); + bus3Lbl.setVisible(false); + bus3Spinner.setVisible(false); + } + + //Command Stations Marklin CS and ESU-ECoS require that the setting + //for the number of modules is done on the commandstation it self, hence disable the spinners + if (selectedCommandStation.getId().equals(MARKLIN_CS) || selectedCommandStation.getId().equals(ESU_ECOS)) { + mainSpinner.setEnabled(false); + bus1Spinner.setEnabled(false); + bus2Spinner.setEnabled(false); + bus3Spinner.setEnabled(false); + } else { + mainSpinner.setEnabled(true); + bus1Spinner.setEnabled(true); + bus2Spinner.setEnabled(true); + bus3Spinner.setEnabled(true); + } + } else { + connectedToLbl.setVisible(false); + serialLbl.setVisible(false); + swVersionLbl.setVisible(false); + hwVersionLbl.setVisible(false); + connectBtn.setText("Connect"); + + //Feedback modules + mainLbl.setVisible(false); + mainSpinner.setVisible(false); + + bus1Lbl.setVisible(false); + bus1Spinner.setVisible(false); + bus2Lbl.setVisible(false); + bus2Spinner.setVisible(false); + bus3Lbl.setVisible(false); + bus3Spinner.setVisible(false); + updateBtn.setVisible(false); + } + + buildTree(); + } + + private void buildTree() { + Logger.trace("build tree"); + String rootDesc; + if (selectedCommandStation != null) { + rootDesc = selectedCommandStation.getDescription(); + } else { + rootDesc = ""; + } + + DefaultMutableTreeNode root = new DefaultMutableTreeNode(rootDesc); + createNodes(root); + + DefaultTreeModel model = new DefaultTreeModel(root); + + devicesTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); + devicesTree.addTreeSelectionListener(this); + + devicesTree.setModel(model); + } + + private void createNodes(DefaultMutableTreeNode root) { + Logger.trace("Create feedback nodes"); + if (controller == null) { + return; + } + + List devices = controller.getDevices(); + + for (Device d : devices) { + DefaultMutableTreeNode deviceNode = new DefaultMutableTreeNode(d.getId() + " " + d.getName()); + + if (d.isFeedback()) { + List modules = ((FeedbackController) controller).getFeedbackModules(); + Collections.sort(modules); + + //Marklin show per bus + + + for (FeedbackModule fm : modules) { + StringBuilder sb = new StringBuilder(); + sb.append("id: "); + sb.append(fm.getId()); + if (fm.getIdentifier() != null) { + sb.append(" node: "); + sb.append(fm.getIdentifier()); + } + if (fm.getBusNumber() != null) { + sb.append(" bus: "); + sb.append(fm.getBusNumber()); + } + sb.append(" module: "); + sb.append(fm.getModuleNumber()); + + DefaultMutableTreeNode moduleNode = new DefaultMutableTreeNode(sb); + Logger.trace("M " + sb.toString()); + + deviceNode.add(moduleNode); + } + + } + + root.add(deviceNode); + } + + } + + public void valueChanged(TreeSelectionEvent e) { + DefaultMutableTreeNode node = (DefaultMutableTreeNode) devicesTree.getLastSelectedPathComponent(); + + if (node == null) { + return; + } + + Object nodeInfo = node.getUserObject(); + + if (node.isLeaf()) { + + } else { + } + } + + private void changeDefaultCommandStation(final CommandStationBean newDefault) { + PersistenceFactory.getService().changeDefaultCommandStation(newDefault); + java.awt.EventQueue.invokeLater(() -> { + setComponents(); + }); + } + + private void persistCommandStation(final CommandStationBean commandStation) { + PersistenceFactory.getService().persist(commandStation); + java.awt.EventQueue.invokeLater(() -> { + setComponents(); + }); + } + + private void discoverBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_discoverBtnActionPerformed + Logger.trace("Try to discover " + selectedCommandStation.getDescription()); + executor.execute(() -> discover(selectedCommandStation)); + }//GEN-LAST:event_discoverBtnActionPerformed + + private void feedbackCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_feedbackCBActionPerformed + CommandStationBean newSelectedFeedbackProvider = (CommandStationBean) feedbackCBM.getSelectedItem(); + //Check if it is not the empty one + if (feedbackCB.isEnabled()) { + if (selectedFeedbackProvider != null && selectedFeedbackProvider.getId() != null && newSelectedFeedbackProvider.getId() == null) { + //Disable the curren selected provider + selectedFeedbackProvider.setEnabled(false); + PersistenceFactory.getService().persist(selectedFeedbackProvider); + selectedFeedbackProvider = newSelectedFeedbackProvider; + } else { + selectedFeedbackProvider = newSelectedFeedbackProvider; + selectedFeedbackProvider.setEnabled(newSelectedFeedbackProvider.getId() != null); + //Persist the change + PersistenceFactory.getService().persist(selectedFeedbackProvider); + } + secondfbpLbl.setVisible(selectedFeedbackProvider.isFeedbackSupport() && selectedFeedbackProvider.getId() != null); + } + }//GEN-LAST:event_feedbackCBActionPerformed + + private void serialCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_serialCBActionPerformed + String selectedPort = (String) serialCB.getSelectedItem(); + selectedCommandStation.setSerialPort(selectedPort); + persistCommandStation(selectedCommandStation); + }//GEN-LAST:event_serialCBActionPerformed + + private void fbpSerialCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fbpSerialCBActionPerformed + String selectedPort = (String) fbpSerialCB.getSelectedItem(); + selectedFeedbackProvider.setSerialPort(selectedPort); + persistCommandStation(selectedFeedbackProvider); + }//GEN-LAST:event_fbpSerialCBActionPerformed + + private void networkRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_networkRBActionPerformed + if (networkRB.isSelected()) { + selectedCommandStation.setConnectionType(CommandStationBean.ConnectionType.NETWORK); + selectedCommandStation.setSerialPort(null); + } else { + selectedCommandStation.setConnectionType(CommandStationBean.ConnectionType.SERIAL); + } + persistCommandStation(selectedCommandStation); + }//GEN-LAST:event_networkRBActionPerformed + + private void serialRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_serialRBActionPerformed + if (networkRB.isSelected()) { + selectedCommandStation.setConnectionType(CommandStationBean.ConnectionType.NETWORK); + } else { + selectedCommandStation.setConnectionType(CommandStationBean.ConnectionType.SERIAL); + } + persistCommandStation(selectedCommandStation); + }//GEN-LAST:event_serialRBActionPerformed + + private void ipTFActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ipTFActionPerformed + Logger.trace("ip Address: " + this.ipTF.getText()); + selectedCommandStation.setIpAddress(ipTF.getText()); + persistCommandStation(selectedCommandStation); + }//GEN-LAST:event_ipTFActionPerformed + + private void ipTFFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_ipTFFocusLost + Logger.trace("ip Address: " + this.ipTF.getText()); + selectedCommandStation.setIpAddress(ipTF.getText()); + persistCommandStation(selectedCommandStation); + }//GEN-LAST:event_ipTFFocusLost + + private void ipTFMouseExited(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_ipTFMouseExited + Logger.trace("ip Address: " + this.ipTF.getText()); + selectedCommandStation.setIpAddress(ipTF.getText()); + persistCommandStation(selectedCommandStation); + }//GEN-LAST:event_ipTFMouseExited + + private void connectBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_connectBtnActionPerformed + Logger.trace("Try to connect to " + selectedCommandStation.getDescription()); + + if ("Connect".equals(connectBtn.getText())) { + executor.execute(() -> connect(selectedCommandStation)); + } else { + executor.execute(() -> disconnect()); + } + }//GEN-LAST:event_connectBtnActionPerformed + + private void checkBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_checkBtnActionPerformed + executor.execute(() -> checkConnection(selectedCommandStation)); + }//GEN-LAST:event_checkBtnActionPerformed + + private void virtualCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_virtualCBActionPerformed + selectedCommandStation.setVirtual(virtualCB.isSelected()); + persistCommandStation(selectedCommandStation); + }//GEN-LAST:event_virtualCBActionPerformed + + private void updateBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_updateBtnActionPerformed + executor.execute(() -> { + updateBtn.setEnabled(false); + updateSensors(); + }); + }//GEN-LAST:event_updateBtnActionPerformed + + private void updateSensors() { + List modules = ((FeedbackController) controller).getFeedbackModules(); + + Logger.trace("There are " + modules.size() + " feedback modules"); + //Catch errors if any... + try { + for (FeedbackModule fbm : modules) { + List sensors = fbm.getSensors(); + for (SensorBean sb : sensors) { + Logger.trace("Storing : " + sb); + PersistenceFactory.getService().persist(sb); + } + } + } catch (Exception e) { + Logger.error("Error updating sensors! " + e); + } + + java.awt.EventQueue.invokeLater(() -> { + setComponents(); + updateBtn.setEnabled(true); + }); + } + + private List getFeedbackModules(String commandStationId) { + List sensors = PersistenceFactory.getService().getSensorsByCommandStationId(commandStationId); + + List modules = new ArrayList<>(); + if (!sensors.isEmpty()) { + Integer id = -1; + for (SensorBean sb : sensors) { + if (!id.equals(sb.getDeviceId())) { + FeedbackModule fbm = new FeedbackModule(); + fbm.setId(sb.getDeviceId()); + fbm.setIdentifier(sb.getNodeId()); + //The busnumber and address offset depend on the commandstation id + fbm.setBusNumber(sb.getBusNr()); + } + } + } + + return modules; + } + + private InetAddress discover(final CommandStationBean commandStation) { + final JOptionPane optionPane = new JOptionPane("Try to discovering a " + commandStation.getDescription(), + JOptionPane.INFORMATION_MESSAGE, + JOptionPane.DEFAULT_OPTION); + + final JDialog discoverDialog = new JDialog(this, "Discovering..."); + discoverDialog.setContentPane(optionPane); + discoverDialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); + discoverDialog.pack(); + discoverDialog.setLocationRelativeTo(null); + discoverDialog.setVisible(true); + + InetAddress inetAddress = null; + if (MARKLIN_CS.equals(commandStation.getId())) { + inetAddress = CSConnectionFactory.discoverCs(); + } else if (ESU_ECOS.equals(commandStation.getId())) { + inetAddress = EcosConnectionFactory.discoverEcos(); + } + + if (inetAddress != null) { + Logger.trace("Discovered host " + inetAddress.getHostAddress() + " for " + commandStation.getDescription()); + commandStation.setIpAddress(inetAddress.getHostAddress()); + persistCommandStation(commandStation); + } + + java.awt.EventQueue.invokeLater(() -> { + discoverDialog.setVisible(false); + discoverDialog.dispose(); + }); + + return inetAddress; + } + + private void checkConnection(final CommandStationBean commandStation) { + String ip = commandStation.getIpAddress(); + boolean canConnect = Ping.IsReachable(ip); + + java.awt.EventQueue.invokeLater(() -> { + if (canConnect) { + ipTF.setBackground(new java.awt.Color(204, 255, 204)); + connectBtn.setEnabled(true); + } else { + ipTF.setBackground(new java.awt.Color(255, 255, 255)); + connectBtn.setEnabled(false); + JOptionPane.showMessageDialog(this, "Can't connect with host " + ip, "Can't Connect", JOptionPane.WARNING_MESSAGE); + } + }); + } + + private void disconnect() { + if (controller != null) { + controller.disconnect(); + controller = null; + + java.awt.EventQueue.invokeLater(() -> { + setComponents(); + }); + + } + } + + private void connect(final CommandStationBean commandStation) { + final JOptionPane optionPane = new JOptionPane("Try to connect to " + commandStation.getDescription(), + JOptionPane.INFORMATION_MESSAGE, + JOptionPane.DEFAULT_OPTION); + + final JDialog connectingDialog = new JDialog(this, "Connecting..."); + connectingDialog.setContentPane(optionPane); + connectingDialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); + connectingDialog.pack(); + connectingDialog.setLocationRelativeTo(null); + connectingDialog.setVisible(true); + + if (MARKLIN_CS.equals(commandStation.getId())) { + controller = new MarklinCentralStationImpl(commandStation); + } else if (ESU_ECOS.equals(commandStation.getId())) { + controller = new EsuEcosCommandStationImpl(commandStation); + } else if (DCC_EX.equals(commandStation.getId())) { + Logger.info("TODO: DCC-EX!"); + } else if (HSI_S88.equals(commandStation.getId())) { + Logger.info("TODO: HSI-S88!"); + } else { + Logger.trace("Unknown Controller!"); + } + + if (controller == null) { + return; + } + + controller.connect(); + if (controller.isConnected()) { + //Obtain some info from the controller + Logger.trace("Connected to " + controller.getCommandStationInfo()); + + java.awt.EventQueue.invokeLater(() -> { + setComponents(); + }); + } + + java.awt.EventQueue.invokeLater(() -> { + connectingDialog.setVisible(false); + connectingDialog.dispose(); + }); + + //} catch (UnknownHostException ex) { + // Logger.error("Unknown host " + commandStation.getIpAddress()); + // return false; + //} + } + + @Override + public void setVisible(boolean b) { + super.setVisible(b); + + if (!b && this.controller != null) { + if (controller.isConnected()) { + controller.disconnect(); + } + controller = null; + Logger.trace("Disconnected from " + selectedCommandStation.getId()); + } + } /** * @param args the command line arguments */ public static void main(String args[]) { + /* Set the FlatLightLaf look and feel */ + // try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { Logger.warn("Can't set the LookAndFeel: " + ex); } + // /* Create and display the dialog */ java.awt.EventQueue.invokeLater(() -> { @@ -91,18 +1081,71 @@ public static void main(String args[]) { dialog.addWindowListener(new java.awt.event.WindowAdapter() { @Override public void windowClosing(java.awt.event.WindowEvent e) { + dialog.setVisible(false); System.exit(0); } }); - dialog.setLocationRelativeTo(null); + dialog.pack(); + dialog.setLocationRelativeTo(null); dialog.setVisible(true); + }); } - // Variables declaration - do not modify//GEN-BEGIN:variables - private jcs.ui.settings.CommandStationPanel commandStationPanel1; - private javax.swing.JButton exitBtn; - private javax.swing.JPanel southPanel; - // End of variables declaration//GEN-END:variables + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel accessoryControllerLbl; + private javax.swing.JLabel bus1Lbl; + private javax.swing.JSpinner bus1Spinner; + private javax.swing.JLabel bus2Lbl; + private javax.swing.JSpinner bus2Spinner; + private javax.swing.JLabel bus3Lbl; + private javax.swing.JSpinner bus3Spinner; + private javax.swing.JButton checkBtn; + private javax.swing.JComboBox commandStationCB; + private javax.swing.JLabel commandStationLbl; + private javax.swing.JButton connectBtn; + private javax.swing.JLabel connectedToLbl; + private javax.swing.ButtonGroup connectionTypeBG; + private javax.swing.JLabel controllerLbl; + private javax.swing.JPanel controllerPanel; + private javax.swing.JPanel devicesPanel; + private javax.swing.JScrollPane devicesSP; + private javax.swing.JTree devicesTree; + private javax.swing.JButton discoverBtn; + private javax.swing.JComboBox fbpSerialCB; + private javax.swing.JLabel fbpSerialLbl; + private javax.swing.JComboBox feedbackCB; + private javax.swing.JPanel feedbackCSPanel; + private javax.swing.JLabel feedbackLbl; + private javax.swing.JPanel feedbackModulesPanel; + private javax.swing.JPanel feedbackPanel; + private javax.swing.JLabel feedbackProviderLbl; + private javax.swing.Box.Filler filler1; + private javax.swing.Box.Filler filler2; + private javax.swing.JLabel hwVersionLbl; + private javax.swing.JLabel ipOrPortLbl; + private javax.swing.JTextField ipTF; + private javax.swing.JPanel jPanel2; + private javax.swing.JPanel jPanel3; + private javax.swing.JPanel jPanel4; + private javax.swing.JPanel jPanel5; + private javax.swing.JPanel jPanel6; + private javax.swing.JPanel mainCSPanel; + private javax.swing.JLabel mainLbl; + private javax.swing.JSpinner mainSpinner; + private javax.swing.JRadioButton networkRB; + private javax.swing.JPanel propertiesPanel; + private javax.swing.JLabel secondfbpLbl; + private javax.swing.JComboBox serialCB; + private javax.swing.JLabel serialLbl; + private javax.swing.JRadioButton serialRB; + private javax.swing.JLabel swVersionLbl; + private javax.swing.JPanel topPanel; + private javax.swing.JButton updateBtn; + private javax.swing.JPanel updatePanel; + private javax.swing.JCheckBox virtualCB; + // End of variables declaration//GEN-END:variables + } diff --git a/src/main/java/jcs/ui/settings/CommandStationDialog1.form b/src/main/java/jcs/ui/settings/CommandStationDialog1.form deleted file mode 100644 index 50f8feaf..00000000 --- a/src/main/java/jcs/ui/settings/CommandStationDialog1.form +++ /dev/null @@ -1,922 +0,0 @@ - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/main/java/jcs/ui/settings/CommandStationDialog1.java b/src/main/java/jcs/ui/settings/CommandStationDialog1.java deleted file mode 100644 index a709b37b..00000000 --- a/src/main/java/jcs/ui/settings/CommandStationDialog1.java +++ /dev/null @@ -1,1008 +0,0 @@ -/* - * Copyright 2025 fransjacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.settings; - -import com.fazecast.jSerialComm.SerialPort; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import javax.swing.ComboBoxModel; -import javax.swing.DefaultComboBoxModel; -import javax.swing.JOptionPane; -import javax.swing.UIManager; -import javax.swing.UnsupportedLookAndFeelException; -import jcs.JCS; -import jcs.commandStation.esu.ecos.net.EcosConnectionFactory; -import jcs.commandStation.marklin.cs.net.CSConnectionFactory; -import jcs.entities.CommandStationBean; -import jcs.persistence.PersistenceFactory; -import org.tinylog.Logger; -import java.net.InetAddress; -import java.net.URL; -import java.util.Collections; -import javax.swing.JDialog; -import javax.swing.event.TreeSelectionEvent; -import javax.swing.event.TreeSelectionListener; -import javax.swing.tree.DefaultMutableTreeNode; -import javax.swing.tree.DefaultTreeModel; -import javax.swing.tree.TreeSelectionModel; -import jcs.commandStation.DecoderController; -import jcs.commandStation.FeedbackController; -import jcs.commandStation.entities.Device; -import jcs.commandStation.entities.InfoBean; -import jcs.commandStation.esu.ecos.EsuEcosCommandStationImpl; -import jcs.commandStation.marklin.cs.MarklinCentralStationImpl; -import jcs.entities.FeedbackModuleBean; -import jcs.entities.SensorBean; -import jcs.util.Ping; - -/** - * - * @author fransjacobs - */ -public class CommandStationDialog1 extends JDialog implements TreeSelectionListener { - - private ComboBoxModel commandStationCBM; - private ComboBoxModel feedbackCBM; - private ComboBoxModel serialPortCBM; - private ComboBoxModel fbpSerialPortCBM; - private CommandStationBean selectedCommandStation; - private CommandStationBean selectedFeedbackProvider; - - private final ExecutorService executor; - - private CommandStationBean emptyCS; - private CommandStationBean emptyFB; - - private static final String MARKLIN_CS = "marklin.cs"; - private static final String ESU_ECOS = "esu-ecos"; - private static final String DCC_EX = "dcc-ex"; - private static final String HSI_S88 = "hsi-s88"; - - private DecoderController controller; - - /** - * Creates new form CommandStationDialog1 - */ - public CommandStationDialog1(java.awt.Frame parent, boolean modal) { - super(parent, modal); - initComponents(); - executor = Executors.newSingleThreadExecutor(); - if (PersistenceFactory.getService() != null) { - initModels(null); - } - - } - - private void initModels(CommandStationBean selected) { - if (selected == null) { - selectedCommandStation = PersistenceFactory.getService().getDefaultCommandStation(); - } else { - selectedCommandStation = selected; - } - - if (selectedCommandStation != null && !selectedCommandStation.isFeedbackSupport()) { - selectedFeedbackProvider = PersistenceFactory.getService().getEnabledFeedbackProvider(); - } - - List allCommandStations = PersistenceFactory.getService().getCommandStations(); - - List commandStations = new ArrayList<>(); - List feedbackProviders = new ArrayList<>(); - - for (CommandStationBean csb : allCommandStations) { - if (csb.isDecoderControlSupport()) { - commandStations.add(csb); - } else { - feedbackProviders.add(csb); - } - } - - emptyCS = new CommandStationBean(); - emptyCS.setDecoderControlSupport(true); - emptyFB = new CommandStationBean(); - emptyFB.setFeedbackSupport(true); - - commandStations.add(emptyCS); - feedbackProviders.add(emptyFB); - - if (selectedCommandStation == null) { - selectedCommandStation = emptyCS; - } - - if (selectedFeedbackProvider == null) { - selectedFeedbackProvider = emptyFB; - } - - CommandStationBean[] csba = new CommandStationBean[commandStations.size()]; - CommandStationBean[] fbpa = new CommandStationBean[feedbackProviders.size()]; - commandStations.toArray(csba); - feedbackProviders.toArray(fbpa); - - commandStationCBM = new DefaultComboBoxModel<>(csba); - commandStationCBM.setSelectedItem(selectedCommandStation); - commandStationCB.setModel(commandStationCBM); - - feedbackCBM = new DefaultComboBoxModel<>(fbpa); - feedbackCBM.setSelectedItem(selectedFeedbackProvider); - feedbackCB.setModel(feedbackCBM); - - SerialPort comPorts[] = SerialPort.getCommPorts(); - String[] ports = new String[comPorts.length]; - for (int i = 0; i < comPorts.length; i++) { - ports[i] = comPorts[i].getSystemPortName(); - } - - serialPortCBM = new DefaultComboBoxModel<>(ports); - fbpSerialPortCBM = new DefaultComboBoxModel<>(ports); - serialCB.setModel(serialPortCBM); - fbpSerialCB.setModel(fbpSerialPortCBM); - - if (CommandStationBean.ConnectionType.SERIAL == selectedCommandStation.getConnectionType()) { - String port = selectedCommandStation.getSerialPort(); - serialCB.setSelectedItem(port); - serialRB.setSelected(true); - } else { - networkRB.setSelected(true); - } - - if (selectedFeedbackProvider.getConnectionType() != null && CommandStationBean.ConnectionType.SERIAL == selectedFeedbackProvider.getConnectionType()) { - String port = selectedFeedbackProvider.getSerialPort(); - fbpSerialCB.setSelectedItem(port); - } - - setComponents(); - - if (!selectedCommandStation.isVirtual() && CommandStationBean.ConnectionType.NETWORK == selectedCommandStation.getConnectionType() && selectedCommandStation.getIpAddress() != null && selectedCommandStation.getIpAddress().length() > 8) { - executor.execute(() -> checkConnection(selectedCommandStation)); - } - } - - /** - * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. - */ - @SuppressWarnings("unchecked") - // //GEN-BEGIN:initComponents - private void initComponents() { - - connectionTypeBG = new javax.swing.ButtonGroup(); - topPanel = new javax.swing.JPanel(); - mainCSPanel = new javax.swing.JPanel(); - commandStationLbl = new javax.swing.JLabel(); - commandStationCB = new javax.swing.JComboBox<>(); - virtualCB = new javax.swing.JCheckBox(); - ipOrPortLbl = new javax.swing.JLabel(); - ipTF = new javax.swing.JTextField(); - serialCB = new javax.swing.JComboBox<>(); - controllerLbl = new javax.swing.JLabel(); - accessoryControllerLbl = new javax.swing.JLabel(); - feedbackProviderLbl = new javax.swing.JLabel(); - discoverBtn = new javax.swing.JButton(); - checkBtn = new javax.swing.JButton(); - networkRB = new javax.swing.JRadioButton(); - serialRB = new javax.swing.JRadioButton(); - feedbackCSPanel = new javax.swing.JPanel(); - feedbackLbl = new javax.swing.JLabel(); - feedbackCB = new javax.swing.JComboBox<>(); - secondfbpLbl = new javax.swing.JLabel(); - fbpSerialLbl = new javax.swing.JLabel(); - fbpSerialCB = new javax.swing.JComboBox<>(); - filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 23), new java.awt.Dimension(0, 23), new java.awt.Dimension(32767, 23)); - jPanel3 = new javax.swing.JPanel(); - jPanel4 = new javax.swing.JPanel(); - connectBtn = new javax.swing.JButton(); - jPanel5 = new javax.swing.JPanel(); - jPanel2 = new javax.swing.JPanel(); - propertiesPanel = new javax.swing.JPanel(); - controllerPanel = new javax.swing.JPanel(); - connectedToLbl = new javax.swing.JLabel(); - serialLbl = new javax.swing.JLabel(); - swVersionLbl = new javax.swing.JLabel(); - hwVersionLbl = new javax.swing.JLabel(); - feedbackSettingsPanel = new javax.swing.JPanel(); - jLabel1 = new javax.swing.JLabel(); - mainSpinner = new javax.swing.JSpinner(); - jLabel2 = new javax.swing.JLabel(); - bus1Spinner = new javax.swing.JSpinner(); - jLabel3 = new javax.swing.JLabel(); - bus2Spinner = new javax.swing.JSpinner(); - jLabel4 = new javax.swing.JLabel(); - bus3Spinner = new javax.swing.JSpinner(); - filler2 = new javax.swing.Box.Filler(new java.awt.Dimension(100, 0), new java.awt.Dimension(100, 0), new java.awt.Dimension(100, 32767)); - updateBtn = new javax.swing.JButton(); - jPanel6 = new javax.swing.JPanel(); - jPanel1 = new javax.swing.JPanel(); - jScrollPane1 = new javax.swing.JScrollPane(); - jTree1 = new javax.swing.JTree(); - - setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); - - jcs.ui.swing.layout.VerticalFlowLayout verticalFlowLayout1 = new jcs.ui.swing.layout.VerticalFlowLayout(); - verticalFlowLayout1.sethAlignment(0); - topPanel.setLayout(verticalFlowLayout1); - - mainCSPanel.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT)); - - commandStationLbl.setLabelFor(commandStationCB); - commandStationLbl.setText("Command Station"); - commandStationLbl.setPreferredSize(new java.awt.Dimension(110, 17)); - mainCSPanel.add(commandStationLbl); - - commandStationCB.setPreferredSize(new java.awt.Dimension(200, 23)); - commandStationCB.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - commandStationCBActionPerformed(evt); - } - }); - mainCSPanel.add(commandStationCB); - - virtualCB.setText("Virtual"); - virtualCB.setToolTipText("Use Virtual Connection"); - virtualCB.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - virtualCBActionPerformed(evt); - } - }); - mainCSPanel.add(virtualCB); - - ipOrPortLbl.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); - ipOrPortLbl.setLabelFor(ipTF); - ipOrPortLbl.setText("ip Address:"); - ipOrPortLbl.setPreferredSize(new java.awt.Dimension(105, 17)); - mainCSPanel.add(ipOrPortLbl); - - ipTF.setPreferredSize(new java.awt.Dimension(120, 23)); - ipTF.addFocusListener(new java.awt.event.FocusAdapter() { - public void focusLost(java.awt.event.FocusEvent evt) { - ipTFFocusLost(evt); - } - }); - ipTF.addMouseListener(new java.awt.event.MouseAdapter() { - public void mouseExited(java.awt.event.MouseEvent evt) { - ipTFMouseExited(evt); - } - }); - ipTF.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - ipTFActionPerformed(evt); - } - }); - mainCSPanel.add(ipTF); - - serialCB.setPreferredSize(new java.awt.Dimension(120, 23)); - serialCB.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - serialCBActionPerformed(evt); - } - }); - mainCSPanel.add(serialCB); - - controllerLbl.setIcon(new javax.swing.ImageIcon(getClass().getResource("/media/controller-console-24.png"))); // NOI18N - controllerLbl.setToolTipText("Decoder Controller"); - mainCSPanel.add(controllerLbl); - - accessoryControllerLbl.setIcon(new javax.swing.ImageIcon(getClass().getResource("/media/branch-24.png"))); // NOI18N - accessoryControllerLbl.setToolTipText("Accessory Controller"); - mainCSPanel.add(accessoryControllerLbl); - - feedbackProviderLbl.setIcon(new javax.swing.ImageIcon(getClass().getResource("/media/chat-24.png"))); // NOI18N - feedbackProviderLbl.setToolTipText("Feedback Provider"); - mainCSPanel.add(feedbackProviderLbl); - - discoverBtn.setText("Discover"); - discoverBtn.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - discoverBtnActionPerformed(evt); - } - }); - mainCSPanel.add(discoverBtn); - - checkBtn.setText("Check"); - checkBtn.setToolTipText("Check Connection"); - checkBtn.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - checkBtnActionPerformed(evt); - } - }); - mainCSPanel.add(checkBtn); - - connectionTypeBG.add(networkRB); - networkRB.setText("Network"); - networkRB.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - networkRBActionPerformed(evt); - } - }); - mainCSPanel.add(networkRB); - - connectionTypeBG.add(serialRB); - serialRB.setText("Serialport"); - serialRB.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - serialRBActionPerformed(evt); - } - }); - mainCSPanel.add(serialRB); - - topPanel.add(mainCSPanel); - - java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); - flowLayout1.setAlignOnBaseline(true); - feedbackCSPanel.setLayout(flowLayout1); - - feedbackLbl.setLabelFor(feedbackCB); - feedbackLbl.setText("Feedback Device"); - feedbackLbl.setPreferredSize(new java.awt.Dimension(110, 17)); - feedbackCSPanel.add(feedbackLbl); - - feedbackCB.setPreferredSize(new java.awt.Dimension(200, 23)); - feedbackCB.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - feedbackCBActionPerformed(evt); - } - }); - feedbackCSPanel.add(feedbackCB); - - secondfbpLbl.setIcon(new javax.swing.ImageIcon(getClass().getResource("/media/chat-24.png"))); // NOI18N - secondfbpLbl.setToolTipText("Feedback Provicer"); - secondfbpLbl.setPreferredSize(new java.awt.Dimension(25, 24)); - feedbackCSPanel.add(secondfbpLbl); - - fbpSerialLbl.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); - fbpSerialLbl.setText("Serial Port:"); - fbpSerialLbl.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING); - fbpSerialLbl.setPreferredSize(new java.awt.Dimension(75, 17)); - feedbackCSPanel.add(fbpSerialLbl); - - fbpSerialCB.setPreferredSize(new java.awt.Dimension(120, 23)); - fbpSerialCB.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - fbpSerialCBActionPerformed(evt); - } - }); - feedbackCSPanel.add(fbpSerialCB); - feedbackCSPanel.add(filler1); - - topPanel.add(feedbackCSPanel); - - getContentPane().add(topPanel, java.awt.BorderLayout.PAGE_START); - - javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3); - jPanel3.setLayout(jPanel3Layout); - jPanel3Layout.setHorizontalGroup( - jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 1202, Short.MAX_VALUE) - ); - jPanel3Layout.setVerticalGroup( - jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 100, Short.MAX_VALUE) - ); - - getContentPane().add(jPanel3, java.awt.BorderLayout.PAGE_END); - - connectBtn.setText("Connect"); - connectBtn.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - connectBtnActionPerformed(evt); - } - }); - jPanel4.add(connectBtn); - - getContentPane().add(jPanel4, java.awt.BorderLayout.LINE_END); - - jPanel5.setPreferredSize(new java.awt.Dimension(100, 400)); - jPanel5.setLayout(new java.awt.BorderLayout()); - getContentPane().add(jPanel5, java.awt.BorderLayout.LINE_START); - - jPanel2.setLayout(new java.awt.BorderLayout()); - - jcs.ui.swing.layout.VerticalFlowLayout verticalFlowLayout2 = new jcs.ui.swing.layout.VerticalFlowLayout(); - verticalFlowLayout2.sethAlignment(0); - propertiesPanel.setLayout(verticalFlowLayout2); - - java.awt.FlowLayout flowLayout3 = new java.awt.FlowLayout(java.awt.FlowLayout.RIGHT); - flowLayout3.setAlignOnBaseline(true); - controllerPanel.setLayout(flowLayout3); - - connectedToLbl.setText("Connected to: command station"); - connectedToLbl.setPreferredSize(new java.awt.Dimension(200, 17)); - controllerPanel.add(connectedToLbl); - - serialLbl.setText("Serial: xxxxxx"); - serialLbl.setPreferredSize(new java.awt.Dimension(150, 17)); - controllerPanel.add(serialLbl); - - swVersionLbl.setText("Software version: xxxxxxx"); - swVersionLbl.setPreferredSize(new java.awt.Dimension(160, 17)); - controllerPanel.add(swVersionLbl); - - hwVersionLbl.setText("Hardware version: xxxxxx"); - hwVersionLbl.setPreferredSize(new java.awt.Dimension(160, 17)); - controllerPanel.add(hwVersionLbl); - - propertiesPanel.add(controllerPanel); - - feedbackSettingsPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Feedback Modules")); - - jLabel1.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); - jLabel1.setText("Main"); - jLabel1.setPreferredSize(new java.awt.Dimension(40, 17)); - feedbackSettingsPanel.add(jLabel1); - - mainSpinner.setModel(new javax.swing.SpinnerNumberModel(0, null, 31, 1)); - feedbackSettingsPanel.add(mainSpinner); - - jLabel2.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); - jLabel2.setText("Bus 1"); - jLabel2.setPreferredSize(new java.awt.Dimension(40, 17)); - feedbackSettingsPanel.add(jLabel2); - - bus1Spinner.setModel(new javax.swing.SpinnerNumberModel(0, null, 31, 1)); - feedbackSettingsPanel.add(bus1Spinner); - - jLabel3.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); - jLabel3.setText("Bus 2"); - jLabel3.setPreferredSize(new java.awt.Dimension(40, 17)); - feedbackSettingsPanel.add(jLabel3); - - bus2Spinner.setModel(new javax.swing.SpinnerNumberModel(0, null, 31, 1)); - feedbackSettingsPanel.add(bus2Spinner); - - jLabel4.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); - jLabel4.setText("Bus 3"); - jLabel4.setPreferredSize(new java.awt.Dimension(40, 17)); - feedbackSettingsPanel.add(jLabel4); - - bus3Spinner.setModel(new javax.swing.SpinnerNumberModel(0, null, 31, 1)); - feedbackSettingsPanel.add(bus3Spinner); - feedbackSettingsPanel.add(filler2); - - updateBtn.setText("Update"); - updateBtn.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - updateBtnActionPerformed(evt); - } - }); - feedbackSettingsPanel.add(updateBtn); - - propertiesPanel.add(feedbackSettingsPanel); - - jPanel2.add(propertiesPanel, java.awt.BorderLayout.PAGE_START); - - jPanel6.setPreferredSize(new java.awt.Dimension(750, 318)); - - javax.swing.GroupLayout jPanel6Layout = new javax.swing.GroupLayout(jPanel6); - jPanel6.setLayout(jPanel6Layout); - jPanel6Layout.setHorizontalGroup( - jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 750, Short.MAX_VALUE) - ); - jPanel6Layout.setVerticalGroup( - jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 318, Short.MAX_VALUE) - ); - - jPanel2.add(jPanel6, java.awt.BorderLayout.EAST); - - jPanel1.setLayout(new java.awt.GridLayout(1, 1)); - - jScrollPane1.setViewportView(jTree1); - - jPanel1.add(jScrollPane1); - - jPanel2.add(jPanel1, java.awt.BorderLayout.CENTER); - - getContentPane().add(jPanel2, java.awt.BorderLayout.CENTER); - - pack(); - }// //GEN-END:initComponents - - private void commandStationCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_commandStationCBActionPerformed - CommandStationBean newSelectedCommandStation = (CommandStationBean) commandStationCBM.getSelectedItem(); - - if (selectedCommandStation != null && selectedCommandStation.getId() != null && !selectedCommandStation.getId().equals(newSelectedCommandStation.getId())) { - try { - if (JCS.getJcsCommandStation() != null && JCS.getJcsCommandStation().isConnected()) { - JCS.getJcsCommandStation().switchPower(false); - } - if (JCS.getParentFrame() != null) { - JCS.getParentFrame().connect(false); - } - } catch (Exception e) { - Logger.error(e.getMessage()); - } - } else { - selectedCommandStation = newSelectedCommandStation; - } - - selectedCommandStation = (CommandStationBean) commandStationCBM.getSelectedItem(); - selectedCommandStation.setEnabled(true); - executor.execute(() -> changeDefaultCommandStation(selectedCommandStation)); - - Logger.trace("Selected CS: " + selectedCommandStation.getDescription()); - }//GEN-LAST:event_commandStationCBActionPerformed - - private void setComponents() { - controllerLbl.setVisible(selectedCommandStation.isDecoderControlSupport()); - accessoryControllerLbl.setVisible(selectedCommandStation.isAccessoryControlSupport()); - feedbackProviderLbl.setVisible(selectedCommandStation.isFeedbackSupport()); - - virtualCB.setSelected(selectedCommandStation.isVirtual()); - - discoverBtn.setVisible(selectedCommandStation.isIpAutoConfiguration()); - ipTF.setText(selectedCommandStation.getIpAddress()); - - serialCB.setVisible(CommandStationBean.ConnectionType.SERIAL == selectedCommandStation.getConnectionType()); - ipTF.setVisible(CommandStationBean.ConnectionType.NETWORK == selectedCommandStation.getConnectionType()); - - networkRB.setVisible(selectedCommandStation.getSupportedConnectionTypes().size() > 1); - serialRB.setVisible(selectedCommandStation.getSupportedConnectionTypes().size() > 1); - networkRB.setSelected(CommandStationBean.ConnectionType.NETWORK == selectedCommandStation.getConnectionType()); - - if (serialCB.isVisible()) { - ipOrPortLbl.setText("Serial Port:"); - } else { - ipOrPortLbl.setText("ip Address:"); - } - - checkBtn.setVisible(CommandStationBean.ConnectionType.NETWORK == selectedCommandStation.getConnectionType() && selectedCommandStation.getIpAddress() != null && selectedCommandStation.getIpAddress().length() > 8); - - if (selectedCommandStation.getIpAddress() == null || selectedCommandStation.getIpAddress().length() > 8) { - ipTF.setBackground(new java.awt.Color(255, 255, 255)); - connectBtn.setEnabled(true); - } else { - connectBtn.setEnabled(false); - } - - //no main controller feedback support, enable the secondary - feedbackCB.setVisible(!selectedCommandStation.isFeedbackSupport()); - feedbackCB.setEnabled(!selectedCommandStation.isFeedbackSupport()); - feedbackLbl.setVisible(!selectedCommandStation.isFeedbackSupport()); - - secondfbpLbl.setVisible(!selectedCommandStation.isFeedbackSupport() && selectedFeedbackProvider.isFeedbackSupport() && selectedFeedbackProvider.getId() != null); - - fbpSerialCB.setVisible(!selectedCommandStation.isFeedbackSupport()); - fbpSerialCB.setEnabled(!selectedCommandStation.isFeedbackSupport()); - fbpSerialLbl.setVisible(!selectedCommandStation.isFeedbackSupport()); - - if (controller != null && controller.isConnected()) { - InfoBean ib = controller.getCommandStationInfo(); - connectedToLbl.setText("Connected to : " + ib.getProductName()); - connectedToLbl.setVisible(true); - - serialLbl.setText("Serial: " + ib.getSerialNumber()); - serialLbl.setVisible(true); - - if (ib.getSoftwareVersion() != null) { - swVersionLbl.setText("Software version: " + ib.getSoftwareVersion()); - swVersionLbl.setVisible(true); - } else { - swVersionLbl.setVisible(false); - } - - if (ib.getHardwareVersion() != null) { - hwVersionLbl.setText(("Hardware version: " + ib.getHardwareVersion())); - hwVersionLbl.setVisible(true); - } else { - hwVersionLbl.setVisible(false); - } - - connectBtn.setText("Disconnect"); - } else { - connectedToLbl.setVisible(false); - serialLbl.setVisible(false); - swVersionLbl.setVisible(false); - hwVersionLbl.setVisible(false); - connectBtn.setText("Connect"); - } - } - - private void initTree() { - Logger.trace("build tree"); - DefaultMutableTreeNode root = new DefaultMutableTreeNode(selectedCommandStation.getDescription()); - createNodes(root); - - DefaultTreeModel model = new DefaultTreeModel(root); - - jTree1.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); - jTree1.addTreeSelectionListener(this); - - jTree1.setModel(model); - } - - private void createNodes(DefaultMutableTreeNode root) { - Logger.trace("Create feedback nodes"); - if (controller == null) { - return; - } - - List devices = controller.getDevices(); - - for (Device d : devices) { - DefaultMutableTreeNode deviceNode = new DefaultMutableTreeNode(d.getId() + " " + d.getName()); - - if (d.isFeedback()) { - List modules = ((FeedbackController) controller).getFeedbackModules(); - Collections.sort(modules); - - for (FeedbackModuleBean fm : modules) { - DefaultMutableTreeNode moduleNode = new DefaultMutableTreeNode("M " + fm.toString()); - Logger.trace("M " + fm.toString()); - - deviceNode.add(moduleNode); - } - - } - - root.add(deviceNode); - } - - } - - public void valueChanged(TreeSelectionEvent e) { - DefaultMutableTreeNode node = (DefaultMutableTreeNode) jTree1.getLastSelectedPathComponent(); - - if (node == null) { - return; - } - - Object nodeInfo = node.getUserObject(); - - if (node.isLeaf()) { - - } else { - } - } - - private void changeDefaultCommandStation(final CommandStationBean newDefault) { - PersistenceFactory.getService().changeDefaultCommandStation(newDefault); - java.awt.EventQueue.invokeLater(() -> { - setComponents(); - }); - } - - private void persistCommandStation(final CommandStationBean commandStation) { - PersistenceFactory.getService().persist(commandStation); - java.awt.EventQueue.invokeLater(() -> { - setComponents(); - }); - } - - private void discoverBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_discoverBtnActionPerformed - Logger.trace("Try to discover " + selectedCommandStation.getDescription()); - executor.execute(() -> discover(selectedCommandStation)); - }//GEN-LAST:event_discoverBtnActionPerformed - - private void feedbackCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_feedbackCBActionPerformed - CommandStationBean newSelectedFeedbackProvider = (CommandStationBean) feedbackCBM.getSelectedItem(); - //Check if it is not the empty one - if (feedbackCB.isEnabled()) { - if (selectedFeedbackProvider != null && selectedFeedbackProvider.getId() != null && newSelectedFeedbackProvider.getId() == null) { - //Disable the curren selected provider - selectedFeedbackProvider.setEnabled(false); - PersistenceFactory.getService().persist(selectedFeedbackProvider); - selectedFeedbackProvider = newSelectedFeedbackProvider; - } else { - selectedFeedbackProvider = newSelectedFeedbackProvider; - selectedFeedbackProvider.setEnabled(newSelectedFeedbackProvider.getId() != null); - //Persist the change - PersistenceFactory.getService().persist(selectedFeedbackProvider); - } - secondfbpLbl.setVisible(selectedFeedbackProvider.isFeedbackSupport() && selectedFeedbackProvider.getId() != null); - } - }//GEN-LAST:event_feedbackCBActionPerformed - - private void serialCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_serialCBActionPerformed - String selectedPort = (String) serialCB.getSelectedItem(); - selectedCommandStation.setSerialPort(selectedPort); - persistCommandStation(selectedCommandStation); - }//GEN-LAST:event_serialCBActionPerformed - - private void fbpSerialCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fbpSerialCBActionPerformed - String selectedPort = (String) fbpSerialCB.getSelectedItem(); - selectedFeedbackProvider.setSerialPort(selectedPort); - persistCommandStation(selectedFeedbackProvider); - }//GEN-LAST:event_fbpSerialCBActionPerformed - - private void networkRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_networkRBActionPerformed - if (networkRB.isSelected()) { - selectedCommandStation.setConnectionType(CommandStationBean.ConnectionType.NETWORK); - selectedCommandStation.setSerialPort(null); - } else { - selectedCommandStation.setConnectionType(CommandStationBean.ConnectionType.SERIAL); - } - persistCommandStation(selectedCommandStation); - }//GEN-LAST:event_networkRBActionPerformed - - private void serialRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_serialRBActionPerformed - if (networkRB.isSelected()) { - selectedCommandStation.setConnectionType(CommandStationBean.ConnectionType.NETWORK); - } else { - selectedCommandStation.setConnectionType(CommandStationBean.ConnectionType.SERIAL); - } - persistCommandStation(selectedCommandStation); - }//GEN-LAST:event_serialRBActionPerformed - - private void ipTFActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ipTFActionPerformed - Logger.trace("ip Address: " + this.ipTF.getText()); - selectedCommandStation.setIpAddress(ipTF.getText()); - persistCommandStation(selectedCommandStation); - }//GEN-LAST:event_ipTFActionPerformed - - private void ipTFFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_ipTFFocusLost - Logger.trace("ip Address: " + this.ipTF.getText()); - selectedCommandStation.setIpAddress(ipTF.getText()); - persistCommandStation(selectedCommandStation); - }//GEN-LAST:event_ipTFFocusLost - - private void ipTFMouseExited(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_ipTFMouseExited - Logger.trace("ip Address: " + this.ipTF.getText()); - selectedCommandStation.setIpAddress(ipTF.getText()); - persistCommandStation(selectedCommandStation); - }//GEN-LAST:event_ipTFMouseExited - - private void connectBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_connectBtnActionPerformed - Logger.trace("Try to connect to " + selectedCommandStation.getDescription()); - - if ("Connect".equals(connectBtn.getText())) { - executor.execute(() -> connect(selectedCommandStation)); - } else { - executor.execute(() -> disconnect()); - } - }//GEN-LAST:event_connectBtnActionPerformed - - private void checkBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_checkBtnActionPerformed - executor.execute(() -> checkConnection(selectedCommandStation)); - }//GEN-LAST:event_checkBtnActionPerformed - - private void virtualCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_virtualCBActionPerformed - selectedCommandStation.setVirtual(virtualCB.isSelected()); - persistCommandStation(selectedCommandStation); - }//GEN-LAST:event_virtualCBActionPerformed - - private void updateBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_updateBtnActionPerformed - //TODO in workerthread with some feedback in the UI - - updateSensors(); - }//GEN-LAST:event_updateBtnActionPerformed - - private void updateSensors() { - - List modules = ((FeedbackController) controller).getFeedbackModules(); - - Logger.trace("There are " + modules.size() + " feedback modules"); - for (FeedbackModuleBean fbm : modules) { - List sensors = fbm.getSensors(); - for (SensorBean sb : sensors) { - PersistenceFactory.getService().persist(sb); - } - } - - } - - private InetAddress discover(final CommandStationBean commandStation) { - final JOptionPane optionPane = new JOptionPane("Try to discovering a " + commandStation.getDescription(), - JOptionPane.INFORMATION_MESSAGE, - JOptionPane.DEFAULT_OPTION); - - final JDialog discoverDialog = new JDialog(this, "Discovering..."); - discoverDialog.setContentPane(optionPane); - discoverDialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); - discoverDialog.pack(); - discoverDialog.setLocationRelativeTo(null); - discoverDialog.setVisible(true); - - InetAddress inetAddress = null; - if (MARKLIN_CS.equals(commandStation.getId())) { - inetAddress = CSConnectionFactory.discoverCs(); - } else if (ESU_ECOS.equals(commandStation.getId())) { - inetAddress = EcosConnectionFactory.discoverEcos(); - } - - if (inetAddress != null) { - Logger.trace("Discovered host " + inetAddress.getHostAddress() + " for " + commandStation.getDescription()); - commandStation.setIpAddress(inetAddress.getHostAddress()); - persistCommandStation(commandStation); - } - - java.awt.EventQueue.invokeLater(() -> { - discoverDialog.setVisible(false); - discoverDialog.dispose(); - }); - - return inetAddress; - } - - private void checkConnection(final CommandStationBean commandStation) { - String ip = commandStation.getIpAddress(); - boolean canConnect = Ping.IsReachable(ip); - - java.awt.EventQueue.invokeLater(() -> { - if (canConnect) { - ipTF.setBackground(new java.awt.Color(204, 255, 204)); - connectBtn.setEnabled(true); - } else { - ipTF.setBackground(new java.awt.Color(255, 255, 255)); - connectBtn.setEnabled(false); - JOptionPane.showMessageDialog(this, "Can't connect with host " + ip, "Can't Connect", JOptionPane.WARNING_MESSAGE); - } - }); - } - - private void disconnect() { - if (controller != null) { - controller.disconnect(); - controller = null; - - java.awt.EventQueue.invokeLater(() -> { - setComponents(); - }); - - } - } - - private void connect(final CommandStationBean commandStation) { - final JOptionPane optionPane = new JOptionPane("Try to connect to " + commandStation.getDescription(), - JOptionPane.INFORMATION_MESSAGE, - JOptionPane.DEFAULT_OPTION); - - final JDialog connectingDialog = new JDialog(this, "Connecting..."); - connectingDialog.setContentPane(optionPane); - connectingDialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); - connectingDialog.pack(); - connectingDialog.setLocationRelativeTo(null); - connectingDialog.setVisible(true); - - if (MARKLIN_CS.equals(commandStation.getId())) { - controller = new MarklinCentralStationImpl(commandStation); - } else if (ESU_ECOS.equals(commandStation.getId())) { - controller = new EsuEcosCommandStationImpl(commandStation); - } else if (DCC_EX.equals(commandStation.getId())) { - Logger.info("TODO: DCC-EX!"); - } else if (HSI_S88.equals(commandStation.getId())) { - Logger.info("TODO: HSI-S88!"); - } else { - Logger.trace("Unknown Controller!"); - } - - if (controller == null) { - return; - } - - controller.connect(); - if (controller.isConnected()) { - //Obtain some info from the controller - Logger.trace("Connected to " + controller.getCommandStationInfo()); - - java.awt.EventQueue.invokeLater(() -> { - initTree(); - setComponents(); - - //Query the controller for devices in general and for feedback devices - //how to populate the tree..... - }); - } - - java.awt.EventQueue.invokeLater(() -> { - connectingDialog.setVisible(false); - connectingDialog.dispose(); - }); - - //} catch (UnknownHostException ex) { - // Logger.error("Unknown host " + commandStation.getIpAddress()); - // return false; - //} - } - - @Override - public void setVisible(boolean b) { - super.setVisible(b); - - if (!b && this.controller != null) { - if (controller.isConnected()) { - controller.disconnect(); - } - controller = null; - Logger.trace("Disconnected from " + selectedCommandStation.getId()); - } - } - - /** - * @param args the command line arguments - */ - public static void main(String args[]) { - /* Set the FlatLightLaf look and feel */ - // - try { - UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { - Logger.warn("Can't set the LookAndFeel: " + ex); - } - // - - /* Create and display the dialog */ - java.awt.EventQueue.invokeLater(() -> { - CommandStationDialog1 dialog = new CommandStationDialog1(new javax.swing.JFrame(), true); - dialog.addWindowListener(new java.awt.event.WindowAdapter() { - @Override - public void windowClosing(java.awt.event.WindowEvent e) { - dialog.setVisible(false); - System.exit(0); - } - }); - - dialog.pack(); - dialog.setLocationRelativeTo(null); - dialog.setVisible(true); - - }); - } - - - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JLabel accessoryControllerLbl; - private javax.swing.JSpinner bus1Spinner; - private javax.swing.JSpinner bus2Spinner; - private javax.swing.JSpinner bus3Spinner; - private javax.swing.JButton checkBtn; - private javax.swing.JComboBox commandStationCB; - private javax.swing.JLabel commandStationLbl; - private javax.swing.JButton connectBtn; - private javax.swing.JLabel connectedToLbl; - private javax.swing.ButtonGroup connectionTypeBG; - private javax.swing.JLabel controllerLbl; - private javax.swing.JPanel controllerPanel; - private javax.swing.JButton discoverBtn; - private javax.swing.JComboBox fbpSerialCB; - private javax.swing.JLabel fbpSerialLbl; - private javax.swing.JComboBox feedbackCB; - private javax.swing.JPanel feedbackCSPanel; - private javax.swing.JLabel feedbackLbl; - private javax.swing.JLabel feedbackProviderLbl; - private javax.swing.JPanel feedbackSettingsPanel; - private javax.swing.Box.Filler filler1; - private javax.swing.Box.Filler filler2; - private javax.swing.JLabel hwVersionLbl; - private javax.swing.JLabel ipOrPortLbl; - private javax.swing.JTextField ipTF; - private javax.swing.JLabel jLabel1; - private javax.swing.JLabel jLabel2; - private javax.swing.JLabel jLabel3; - private javax.swing.JLabel jLabel4; - private javax.swing.JPanel jPanel1; - private javax.swing.JPanel jPanel2; - private javax.swing.JPanel jPanel3; - private javax.swing.JPanel jPanel4; - private javax.swing.JPanel jPanel5; - private javax.swing.JPanel jPanel6; - private javax.swing.JScrollPane jScrollPane1; - private javax.swing.JTree jTree1; - private javax.swing.JPanel mainCSPanel; - private javax.swing.JSpinner mainSpinner; - private javax.swing.JRadioButton networkRB; - private javax.swing.JPanel propertiesPanel; - private javax.swing.JLabel secondfbpLbl; - private javax.swing.JComboBox serialCB; - private javax.swing.JLabel serialLbl; - private javax.swing.JRadioButton serialRB; - private javax.swing.JLabel swVersionLbl; - private javax.swing.JPanel topPanel; - private javax.swing.JButton updateBtn; - private javax.swing.JCheckBox virtualCB; - // End of variables declaration//GEN-END:variables - -} diff --git a/src/main/java/jcs/ui/settings/CommandStationPanel.java b/src/main/java/jcs/ui/settings/CommandStationPanel.java index 580eab0a..74edc708 100644 --- a/src/main/java/jcs/ui/settings/CommandStationPanel.java +++ b/src/main/java/jcs/ui/settings/CommandStationPanel.java @@ -56,7 +56,7 @@ import jcs.entities.CommandStationBean; import jcs.entities.CommandStationBean.ConnectionType; import jcs.entities.CommandStationBean.Protocol; -import jcs.entities.FeedbackModuleBean; +import jcs.commandStation.entities.FeedbackModule; import jcs.persistence.PersistenceFactory; import jcs.ui.swing.layout.VerticalFlowLayout; import jcs.util.Ping; @@ -1372,10 +1372,10 @@ private void virtualCBActionPerformed(ActionEvent evt) {//GEN-FIRST:event_virtua private void recreateSensors() { if (selectedCommandStation.isFeedbackSupport()) { - List feedbackModules = ((FeedbackController) selectedCommandStation).getFeedbackModules(); + List feedbackModules = ((FeedbackController) selectedCommandStation).getFeedbackModules(); PersistenceFactory.getService().removeAllSensors(); - for (FeedbackModuleBean fm : feedbackModules) { + for (FeedbackModule fm : feedbackModules) { PersistenceFactory.getService().persistSensorBeans(fm.getSensors()); } } @@ -1502,7 +1502,7 @@ public Void doInBackground() { setProgress(50); if (commandStation instanceof FeedbackController feedbackController) { - List feedbackModules = feedbackController.getFeedbackModules(); + List feedbackModules = feedbackController.getFeedbackModules(); if (!feedbackModules.isEmpty()) { Logger.trace(feedbackController.getCommandStationInfo().getProductName() + " Supports Feedback"); diff --git a/src/main/resources/update-jcs-db-002.sql b/src/main/resources/update-jcs-db-002.sql index 3b7c3500..d05c1091 100644 --- a/src/main/resources/update-jcs-db-002.sql +++ b/src/main/resources/update-jcs-db-002.sql @@ -17,7 +17,14 @@ commit; alter table sensors alter id integer; alter table sensors add node_id integer; +alter table sensors add bus_nr integer not null default 0; + alter table sensors add command_station_id varchar(255) not null; +alter table sensors drop constraint sens_deid_coid_un; +drop index sens_deid_coid_un_idx; + +alter table sensors add constraint sens_deid_coid_un unique (device_id,contact_id,bus_nr,command_station_id); + alter table tiles alter sensor_id integer; alter table blocks alter plus_sensor_id integer; diff --git a/src/test/java/jcs/entities/FeedbackModuleBeanTest.java b/src/test/java/jcs/commandStation/entities/FeedbackModuleTest.java similarity index 72% rename from src/test/java/jcs/entities/FeedbackModuleBeanTest.java rename to src/test/java/jcs/commandStation/entities/FeedbackModuleTest.java index c20e233a..f6f68cfc 100644 --- a/src/test/java/jcs/entities/FeedbackModuleBeanTest.java +++ b/src/test/java/jcs/commandStation/entities/FeedbackModuleTest.java @@ -13,18 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package jcs.entities; +package jcs.commandStation.entities; import java.util.ArrayList; import java.util.List; +import jcs.entities.SensorBean; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; -public class FeedbackModuleBeanTest { +public class FeedbackModuleTest { - public FeedbackModuleBeanTest() { + public FeedbackModuleTest() { } @BeforeEach @@ -38,7 +39,7 @@ public void tearDown() { @Test public void testGetId() { System.out.println("getId"); - FeedbackModuleBean instance = new FeedbackModuleBean(); + FeedbackModule instance = new FeedbackModule(); instance.setId(0); Integer expResult = 0; @@ -49,10 +50,10 @@ public void testGetId() { @Test public void testGetModuleNumber() { System.out.println("getModuleNumber"); - FeedbackModuleBean instance = new FeedbackModuleBean(); + FeedbackModule instance = new FeedbackModule(); instance.setId(0); - instance.setModuleNumber(0); - Integer expResult = 0; + instance.setModuleNumber(1); + Integer expResult = 1; Integer result = instance.getModuleNumber(); assertEquals(expResult, result); } @@ -60,7 +61,7 @@ public void testGetModuleNumber() { @Test public void testGetPortCount() { System.out.println("getPortCount"); - FeedbackModuleBean instance = new FeedbackModuleBean(); + FeedbackModule instance = new FeedbackModule(); instance.setId(0); instance.setModuleNumber(0); instance.setPortCount(16); @@ -72,7 +73,7 @@ public void testGetPortCount() { @Test public void testGetAddressOffset() { System.out.println("getAddressOffset"); - FeedbackModuleBean instance = new FeedbackModuleBean(); + FeedbackModule instance = new FeedbackModule(); instance.setId(0); instance.setModuleNumber(0); instance.setPortCount(16); @@ -85,7 +86,7 @@ public void testGetAddressOffset() { @Test public void testGetIdentifier() { System.out.println("getIdentifier"); - FeedbackModuleBean instance = new FeedbackModuleBean(); + FeedbackModule instance = new FeedbackModule(); instance.setId(0); instance.setModuleNumber(0); instance.setPortCount(16); @@ -99,7 +100,7 @@ public void testGetIdentifier() { @Test public void testGetPorts() { System.out.println("getPorts"); - FeedbackModuleBean instance = new FeedbackModuleBean(); + FeedbackModule instance = new FeedbackModule(); instance.setId(0); instance.setModuleNumber(0); instance.setPortCount(16); @@ -120,7 +121,7 @@ public void testSetPortValue() { System.out.println("setPortValue"); int port = 3; boolean active = true; - FeedbackModuleBean instance = new FeedbackModuleBean(); + FeedbackModule instance = new FeedbackModule(); instance.setId(0); instance.setModuleNumber(0); instance.setPortCount(16); @@ -140,7 +141,7 @@ public void testSetPortValue() { public void testIsPort() { System.out.println("isPort"); int port = 6; - FeedbackModuleBean instance = new FeedbackModuleBean(); + FeedbackModule instance = new FeedbackModule(); instance.setId(0); instance.setModuleNumber(0); instance.setPortCount(16); @@ -157,7 +158,7 @@ public void testIsPort() { @Test public void testGetAccumulatedPortsValue() { System.out.println("getAccumulatedPortsValue"); - FeedbackModuleBean instance = new FeedbackModuleBean(); + FeedbackModule instance = new FeedbackModule(); instance.setId(0); instance.setModuleNumber(0); instance.setPortCount(16); @@ -175,7 +176,7 @@ public void testGetAccumulatedPortsValue() { @Test public void testGetPrevPorts() { System.out.println("getPrevPorts"); - FeedbackModuleBean instance = new FeedbackModuleBean(); + FeedbackModule instance = new FeedbackModule(); instance.setId(0); instance.setModuleNumber(0); instance.setPortCount(16); @@ -208,9 +209,10 @@ public void testGetPrevPorts() { public void testGetSensorMarklin() { System.out.println("getSensorMarklin"); int port = 1; - FeedbackModuleBean instance = new FeedbackModuleBean(); + FeedbackModule instance = new FeedbackModule(); + instance.setCommandStationId("marklin.cs"); instance.setId(0); - instance.setModuleNumber(0); + instance.setModuleNumber(1); instance.setPortCount(16); instance.setAddressOffset(1000); instance.setIdentifier(65); @@ -219,14 +221,19 @@ public void testGetSensorMarklin() { SensorBean expResult = new SensorBean(); expResult.setId(1001); - expResult.setContactId(1); - expResult.setDeviceId(0); + expResult.setCommandStationId("marklin.cs"); + expResult.setContactId(2); + expResult.setDeviceId(1); expResult.setNodeId(65); expResult.setStatus(0); expResult.setPreviousStatus(0); - expResult.setName("B1-M00-C01"); + expResult.setName("B1-M01-C02"); + expResult.setBusNr(1); SensorBean result = instance.getSensor(port); +//expected: +// but was: + assertEquals(expResult, result); } @@ -234,9 +241,10 @@ public void testGetSensorMarklin() { public void testGetSensorEsu() { System.out.println("getSensorEsu"); int port = 5; - FeedbackModuleBean instance = new FeedbackModuleBean(); + FeedbackModule instance = new FeedbackModule(); + instance.setCommandStationId("esu-ecos"); instance.setId(101); - instance.setModuleNumber(1); + instance.setModuleNumber(2); instance.setPortCount(16); instance.setAddressOffset(0); instance.setIdentifier(null); @@ -244,13 +252,13 @@ public void testGetSensorEsu() { SensorBean expResult = new SensorBean(); expResult.setId(21); - - expResult.setContactId(5); - expResult.setDeviceId(1); + expResult.setCommandStationId("esu-ecos"); + expResult.setContactId(6); + expResult.setDeviceId(2); expResult.setNodeId(null); expResult.setStatus(1); expResult.setPreviousStatus(0); - expResult.setName("M01-C05"); + expResult.setName("M02-C06"); SensorBean result = instance.getSensor(port); assertEquals(expResult, result); @@ -259,28 +267,31 @@ public void testGetSensorEsu() { @Test public void testGetSensors() { System.out.println("getSensors"); - FeedbackModuleBean instance = new FeedbackModuleBean(); + FeedbackModule instance = new FeedbackModule(); + instance.setCommandStationId("esu-ecos"); instance.setId(102); instance.setIdentifier(0); instance.setModuleNumber(2); - instance.setPortCount(FeedbackModuleBean.DEFAULT_PORT_COUNT); + instance.setPortCount(FeedbackModule.DEFAULT_PORT_COUNT); instance.setAddressOffset(0); List expResult = new ArrayList<>(); - for (int i = 0; i < FeedbackModuleBean.DEFAULT_PORT_COUNT; i++) { + for (int i = 0; i < FeedbackModule.DEFAULT_PORT_COUNT; i++) { SensorBean sb = new SensorBean(); - sb.setId(2 * FeedbackModuleBean.DEFAULT_PORT_COUNT + i); - sb.setContactId(i); + sb.setCommandStationId("esu-ecos"); + sb.setId(1 * FeedbackModule.DEFAULT_PORT_COUNT + i); + sb.setContactId(i + 1); sb.setDeviceId(2); sb.setStatus(0); sb.setNodeId(0); sb.setPreviousStatus(0); - sb.setName("M02-C" + String.format("%02d", i)); + sb.setName("M02-C" + String.format("%02d", (i + 1))); expResult.add(sb); } List result = instance.getSensors(); + assertEquals(expResult, result); } @@ -288,11 +299,13 @@ public void testGetSensors() { public void testGetChangedSensors() { System.out.println("getChangedSensors"); int port = 5; - FeedbackModuleBean instance = new FeedbackModuleBean(); + + FeedbackModule instance = new FeedbackModule(); + instance.setCommandStationId("esu-ecos"); instance.setId(100); instance.setIdentifier(0); - instance.setModuleNumber(0); - instance.setPortCount(FeedbackModuleBean.DEFAULT_PORT_COUNT); + instance.setModuleNumber(1); + instance.setPortCount(FeedbackModule.DEFAULT_PORT_COUNT); instance.setAddressOffset(0); List expResult = new ArrayList<>(); @@ -300,22 +313,25 @@ public void testGetChangedSensors() { assertEquals(expResult, result); - instance.setPortValue(5, true); + instance.setPortValue(port, true); result = instance.getChangedSensors(); SensorBean expChangedResult = new SensorBean(); - expChangedResult.setId(5); - expChangedResult.setContactId(5); - expChangedResult.setDeviceId(0); + expChangedResult.setId(5); + expChangedResult.setCommandStationId("esu-ecos"); + expChangedResult.setContactId(6); + expChangedResult.setDeviceId(1); expChangedResult.setNodeId(0); expChangedResult.setStatus(1); expChangedResult.setPreviousStatus(0); - expChangedResult.setName("M00-C05"); + expChangedResult.setName("M01-C06"); expResult.add(expChangedResult); + //expected: <[SensorBean{id=5, name=M00-C06, deviceId=0, contactId=6, nodeId=0, status=1, previousStatus=0, millis=null, lastUpdated=null, commandStationId=esu-ecos}]> + // but was: <[SensorBean{id=5, name=M01-C06, deviceId=1, contactId=6, nodeId=0, status=1, previousStatus=0, millis=null, lastUpdated=null, commandStationId=esu-ecos}]> assertEquals(expResult, result); } diff --git a/src/test/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImplTest.java b/src/test/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImplTest.java index b2d278a3..477952c9 100644 --- a/src/test/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImplTest.java +++ b/src/test/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImplTest.java @@ -19,7 +19,7 @@ import jcs.commandStation.entities.InfoBean; import jcs.entities.AccessoryBean; import jcs.entities.CommandStationBean; -import jcs.entities.FeedbackModuleBean; +import jcs.commandStation.entities.FeedbackModule; import jcs.entities.LocomotiveBean; import jcs.persistence.PersistenceFactory; import jcs.persistence.util.PersistenceTestHelper; @@ -383,7 +383,7 @@ public void testGetFeedbackModules() { EsuEcosCommandStationImpl instance = new EsuEcosCommandStationImpl(commandStationBean); instance.connect(); int expResult = 1; - List result = instance.getFeedbackModules(); + List result = instance.getFeedbackModules(); assertEquals(expResult, result.size()); } } diff --git a/src/test/java/jcs/commandStation/esu/ecos/FeedbackManagerTest.java b/src/test/java/jcs/commandStation/esu/ecos/FeedbackManagerTest.java index 142fdf4e..bfc5fc71 100644 --- a/src/test/java/jcs/commandStation/esu/ecos/FeedbackManagerTest.java +++ b/src/test/java/jcs/commandStation/esu/ecos/FeedbackManagerTest.java @@ -15,7 +15,7 @@ */ package jcs.commandStation.esu.ecos; -import jcs.entities.FeedbackModuleBean; +import jcs.commandStation.entities.FeedbackModule; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -151,7 +151,7 @@ public void testGetSize() { instance.update(new EcosMessage("100 state[0x1]")); - FeedbackModuleBean fbmb = instance.getFeedbackModule(100); + FeedbackModule fbmb = instance.getFeedbackModule(100); boolean x = fbmb.isPort(0); assertEquals(true, instance.getFeedbackModule(100).isPort(0)); diff --git a/src/test/java/jcs/persistence/PersistenceServiceTest.java b/src/test/java/jcs/persistence/PersistenceServiceTest.java index fd652e0e..32f54509 100644 --- a/src/test/java/jcs/persistence/PersistenceServiceTest.java +++ b/src/test/java/jcs/persistence/PersistenceServiceTest.java @@ -101,10 +101,10 @@ public void setUp() { jcsPropertyList.add(p10); jcsPropertyList.add(p11); - SensorBean s1 = new SensorBean(1, "M1", 65, 1, null, 0, 0, 0,"marklin.cs"); + SensorBean s1 = new SensorBean(1, "M1", 65, 1, null, 0, 0, 0,"marklin.cs", 1); sensors.add(s1); - SensorBean s2 = new SensorBean(2, "M2", 65, 2, null, 1, 1, 0,"marklin.cs"); + SensorBean s2 = new SensorBean(2, "M2", 65, 2, null, 1, 1, 0,"marklin.cs", 1); sensors.add(s2); LocomotiveBean loco2 = new LocomotiveBean(2L, "BR 81 002", 2L, 2, "DB BR 81 008", "mm_prg", 120, 1, 0, 0, false, true, true); @@ -378,7 +378,7 @@ public void testGetSensorIntegerInteger() { @Order(8) public void testPersistSensorBean() { System.out.println("persistSensorBean"); - SensorBean sensor = new SensorBean(3, "M1P3", 0, 3, 65, 0, 1, 0, "marklin.cs"); + SensorBean sensor = new SensorBean(3, "M1P3", 0, 3, 65, 0, 1, 0, "marklin.cs", 2); PersistenceService instance = PersistenceFactory.getService(); @@ -405,7 +405,7 @@ public void testPersistSensorBean() { @Order(9) public void testRemoveSensorBean() { System.out.println("removeSensorBean"); - SensorBean sensor = new SensorBean(4, "M1P4", 1, 4, 65, 0, 1, 0,"marklin.cs"); + SensorBean sensor = new SensorBean(4, "M1P4", 1, 4, 65, 0, 1, 0,"marklin.cs", 2); PersistenceService instance = PersistenceFactory.getService(); diff --git a/src/test/resources/jcs-test-data-h2.sql b/src/test/resources/jcs-test-data-h2.sql index 5576a4df..2b5a4bef 100755 --- a/src/test/resources/jcs-test-data-h2.sql +++ b/src/test/resources/jcs-test-data-h2.sql @@ -23,9 +23,9 @@ insert into jcs_properties(p_key,p_value) values commit; -insert into sensors (id,name,device_id,contact_id,status,previous_status,millis,last_updated,node_id, command_station_id) values - (1, 'M1',65,1,0,0,0,null,null,'marklin.cs'), - (2, 'M2',65,2,1,1,0,null,null,'marklin.cs'); +insert into sensors (id,name,device_id,contact_id,status,previous_status,millis,last_updated,node_id, command_station_id, bus_nr) values + (1, 'M1',65,1,0,0,0,null,null,'marklin.cs',1), + (2, 'M2',65,2,1,1,0,null,null,'marklin.cs',1); commit; From 4f84c2b1be68d061f5d105bcaf4941a59d9e1434 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Wed, 28 May 2025 21:19:38 +0200 Subject: [PATCH 70/70] Function images now used with ecos --- .../java/jcs/entities/CommandStationBean.java | 8 ++- .../jcs/persistence/H2PersistenceService.java | 71 +++++++++++++++---- .../jcs/persistence/PersistenceService.java | 11 ++- .../jcs/ui/panel/SmallDriverCabPanel.java | 4 +- .../jcs/ui/settings/CommandStationDialog.java | 27 ++++--- .../java/jcs/ui/widgets/FunctionsPanel.java | 2 +- 6 files changed, 90 insertions(+), 33 deletions(-) diff --git a/src/main/java/jcs/entities/CommandStationBean.java b/src/main/java/jcs/entities/CommandStationBean.java index 820400fd..05087540 100644 --- a/src/main/java/jcs/entities/CommandStationBean.java +++ b/src/main/java/jcs/entities/CommandStationBean.java @@ -31,8 +31,7 @@ import java.util.concurrent.ConcurrentHashMap; /** - * - * @author frans + * Represents a Command Station */ @Table(name = "command_stations") public class CommandStationBean { @@ -67,6 +66,11 @@ public class CommandStationBean { protected Integer feedbackBus2ModuleCount; protected Integer feedbackBus3ModuleCount; + public static final String MARKLIN_CS = "marklin.cs"; + public static final String ESU_ECOS = "esu-ecos"; + public static final String DCC_EX = "dcc-ex"; + public static final String HSI_S88 = "hsi-s88"; + @Id @Column(name = "id") public String getId() { diff --git a/src/main/java/jcs/persistence/H2PersistenceService.java b/src/main/java/jcs/persistence/H2PersistenceService.java index 647e5dac..64fe3b1c 100755 --- a/src/main/java/jcs/persistence/H2PersistenceService.java +++ b/src/main/java/jcs/persistence/H2PersistenceService.java @@ -22,6 +22,7 @@ import java.beans.PropertyChangeSupport; import java.io.File; import java.io.IOException; +import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -206,18 +207,50 @@ public void removeAllSensors() { } @Override - public List getLocomotiveFunctions(Long locomotiveId) { + public List getLocomotiveFunctions(LocomotiveBean locomotive) { + Long locomotiveId = locomotive.getId(); + String commandStationId = locomotive.getCommandStationId(); + List locFunctions = database.where("locomotive_id=?", locomotiveId).orderBy("f_number").results(FunctionBean.class); for (FunctionBean fb : locFunctions) { - fb.setInActiveIconImage(this.getFunctionImage(fb.getInActiveIcon())); - fb.setActiveIconImage(this.getFunctionImage(fb.getActiveIcon())); + if (CommandStationBean.ESU_ECOS.equals(commandStationId)) { + String ico = fb.getIcon(); + String path = "/media/esu/f" + ico + ".png"; + + fb.setInActiveIconImage(getFunctionImage(path)); + fb.setActiveIconImage(getFunctionImage(path)); + + // reverseButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/media/left-24.png"))); + } else { + fb.setInActiveIconImage(getFunctionImage(fb.getInActiveIcon())); + fb.setActiveIconImage(getFunctionImage(fb.getActiveIcon())); + } } return locFunctions; } + @Override + public FunctionBean getLocomotiveFunction(LocomotiveBean locomotive, Integer number) { + Long locomotiveId = locomotive.getId(); + String commandStationId = locomotive.getCommandStationId(); + + FunctionBean fb = database.where("locomotive_id=? and f_number=?", locomotiveId, number).first(FunctionBean.class); + if (fb != null) { + if (CommandStationBean.ESU_ECOS.equals(commandStationId)) { + + } else { + fb.setInActiveIconImage(getFunctionImage(fb.getInActiveIcon())); + fb.setActiveIconImage(getFunctionImage(fb.getActiveIcon())); + } + } + return fb; + } + @Override public FunctionBean getLocomotiveFunction(Long locomotiveId, Integer number) { + String commandStationId = getDefaultCommandStation().getId(); + FunctionBean fb = database.where("locomotive_id=? and f_number=?", locomotiveId, number).first(FunctionBean.class); if (fb != null) { fb.setInActiveIconImage(getFunctionImage(fb.getInActiveIcon())); @@ -242,7 +275,7 @@ public LocomotiveBean getLocomotive(Integer address, DecoderType decoderType, St if (loco.getIcon() != null) { loco.setLocIcon(getLocomotiveImage(loco.getIcon())); } - loco.addAllFunctions(getLocomotiveFunctions(loco.getId())); + loco.addAllFunctions(getLocomotiveFunctions(loco)); } return loco; } @@ -256,7 +289,7 @@ public LocomotiveBean getLocomotive(Integer locUid, String commandStionId) { if (loco.getIcon() != null) { loco.setLocIcon(getLocomotiveImage(loco.getIcon())); } - loco.addAllFunctions(getLocomotiveFunctions(loco.getId())); + loco.addAllFunctions(getLocomotiveFunctions(loco)); } return loco; } @@ -266,7 +299,7 @@ public LocomotiveBean getLocomotive(Long id) { LocomotiveBean loco = database.where("id=?", id).first(LocomotiveBean.class); if (loco != null) { loco.setLocIcon(getLocomotiveImage(loco.getIcon())); - loco.addAllFunctions(getLocomotiveFunctions(loco.getId())); + loco.addAllFunctions(getLocomotiveFunctions(loco)); } return loco; } @@ -277,7 +310,7 @@ public List getAllLocomotives() { for (LocomotiveBean loco : locos) { loco.setLocIcon(getLocomotiveImage(loco.getIcon())); - loco.addAllFunctions(getLocomotiveFunctions(loco.getId())); + loco.addAllFunctions(getLocomotiveFunctions(loco)); } return locos; @@ -301,7 +334,7 @@ public List getLocomotivesByCommandStationId(String commandStati for (LocomotiveBean loco : locos) { loco.setLocIcon(getLocomotiveImage(loco.getIcon())); - loco.addAllFunctions(getLocomotiveFunctions(loco.getId())); + loco.addAllFunctions(getLocomotiveFunctions(loco)); } return locos; @@ -315,7 +348,7 @@ public List getLocomotivesByCommandStationId(String commandStati for (LocomotiveBean loco : locos) { loco.setLocIcon(getLocomotiveImage(loco.getIcon())); - loco.addAllFunctions(getLocomotiveFunctions(loco.getId())); + loco.addAllFunctions(getLocomotiveFunctions(loco)); } return locos; @@ -436,23 +469,37 @@ public Image readImage(String imageName, boolean function) { } if (function) { - path = path + "zfunctions" + File.separator; + if (!path.contains("/media/esu")) { + path = path + "zfunctions" + File.separator; + } } File imgFile; - if (path.contains(".")) { + if (path.contains("/media/esu/")) { + //local resourse + imgFile = null; + } else if (path.contains(".")) { imgFile = new File(path); } else { imgFile = new File(path + imageName.toLowerCase() + ".png"); } - if (imgFile.exists()) { + if (imgFile != null && imgFile.exists()) { try { image = ImageIO.read(imgFile); } catch (IOException e) { Logger.trace("Image file " + imageName + ".png does not exists"); } } else { + if (path.contains("/media")) { + URL iconUrl = getClass().getResource(path); + try { + image = ImageIO.read(iconUrl); + } catch (IOException | IllegalArgumentException e) { + Logger.trace("Image URL " + iconUrl + " does not exists"); + } + } + //TODO: // should we attempt to obtain it now and cache it when available, but also when it is not // available put a marker so that we are not trying over and over again... diff --git a/src/main/java/jcs/persistence/PersistenceService.java b/src/main/java/jcs/persistence/PersistenceService.java index 50d64291..39073b3c 100755 --- a/src/main/java/jcs/persistence/PersistenceService.java +++ b/src/main/java/jcs/persistence/PersistenceService.java @@ -236,7 +236,7 @@ public interface PersistenceService { * @param locomotiveId The ID of the locomotive. * @return A List of FunctionBeans. */ - List getLocomotiveFunctions(Long locomotiveId); + List getLocomotiveFunctions(LocomotiveBean locomotive); /** * Retrieves a FunctionBean associated with a locomotive and function number. @@ -245,6 +245,15 @@ public interface PersistenceService { * @param number The function number. * @return The FunctionBean, or null if not found. */ + FunctionBean getLocomotiveFunction(LocomotiveBean locomotive, Integer number); + + /** + * Retrieves a list of FunctionBeans associated with a locomotive. + * + * @param locomotiveId The ID of the locomotive. + * @param number The function number. + * @return The FunctionBean, or null if not found. + */ FunctionBean getLocomotiveFunction(Long locomotiveId, Integer number); /** diff --git a/src/main/java/jcs/ui/panel/SmallDriverCabPanel.java b/src/main/java/jcs/ui/panel/SmallDriverCabPanel.java index 9e8ee77b..0dca20a5 100644 --- a/src/main/java/jcs/ui/panel/SmallDriverCabPanel.java +++ b/src/main/java/jcs/ui/panel/SmallDriverCabPanel.java @@ -1397,8 +1397,8 @@ public void windowClosing(java.awt.event.WindowEvent e) { testFrame.add(testPanel); if (JCS.getJcsCommandStation() != null) { - LocomotiveBean loc = PersistenceFactory.getService().getLocomotive(16417L); - //LocomotiveBean loc = PersistenceFactory.getService().getLocomotive(1001L); + //LocomotiveBean loc = PersistenceFactory.getService().getLocomotive(16417L); + LocomotiveBean loc = PersistenceFactory.getService().getLocomotive(1000L); Logger.debug(loc); testPanel.setLocomotiveBean(loc); diff --git a/src/main/java/jcs/ui/settings/CommandStationDialog.java b/src/main/java/jcs/ui/settings/CommandStationDialog.java index 205d3e1b..8f93c6de 100644 --- a/src/main/java/jcs/ui/settings/CommandStationDialog.java +++ b/src/main/java/jcs/ui/settings/CommandStationDialog.java @@ -46,6 +46,10 @@ import jcs.commandStation.esu.ecos.EsuEcosCommandStationImpl; import jcs.commandStation.marklin.cs.MarklinCentralStationImpl; import jcs.commandStation.entities.FeedbackModule; +import static jcs.entities.CommandStationBean.DCC_EX; +import static jcs.entities.CommandStationBean.ESU_ECOS; +import static jcs.entities.CommandStationBean.HSI_S88; +import static jcs.entities.CommandStationBean.MARKLIN_CS; import jcs.entities.SensorBean; import jcs.util.Ping; @@ -67,11 +71,6 @@ public class CommandStationDialog extends JDialog implements TreeSelectionListen private CommandStationBean emptyCS; private CommandStationBean emptyFB; - private static final String MARKLIN_CS = "marklin.cs"; - private static final String ESU_ECOS = "esu-ecos"; - private static final String DCC_EX = "dcc-ex"; - private static final String HSI_S88 = "hsi-s88"; - private DecoderController controller; /** @@ -650,7 +649,7 @@ private void setComponents() { } } - if (selectedCommandStation.getId().equals(MARKLIN_CS)) { + if (selectedCommandStation.getId().equals(CommandStationBean.MARKLIN_CS)) { bus1Lbl.setVisible(true); bus1Spinner.setVisible(true); bus2Lbl.setVisible(true); @@ -1012,16 +1011,14 @@ private void connect(final CommandStationBean commandStation) { connectingDialog.setLocationRelativeTo(null); connectingDialog.setVisible(true); - if (MARKLIN_CS.equals(commandStation.getId())) { - controller = new MarklinCentralStationImpl(commandStation); - } else if (ESU_ECOS.equals(commandStation.getId())) { - controller = new EsuEcosCommandStationImpl(commandStation); - } else if (DCC_EX.equals(commandStation.getId())) { - Logger.info("TODO: DCC-EX!"); - } else if (HSI_S88.equals(commandStation.getId())) { - Logger.info("TODO: HSI-S88!"); - } else { + if (null == commandStation.getId()) { Logger.trace("Unknown Controller!"); + } else switch (commandStation.getId()) { + case MARKLIN_CS -> controller = new MarklinCentralStationImpl(commandStation); + case ESU_ECOS -> controller = new EsuEcosCommandStationImpl(commandStation); + case DCC_EX -> Logger.info("TODO: DCC-EX!"); + case HSI_S88 -> Logger.info("TODO: HSI-S88!"); + default -> Logger.trace("Unknown Controller!"); } if (controller == null) { diff --git a/src/main/java/jcs/ui/widgets/FunctionsPanel.java b/src/main/java/jcs/ui/widgets/FunctionsPanel.java index 5d8ae96b..05f62b29 100644 --- a/src/main/java/jcs/ui/widgets/FunctionsPanel.java +++ b/src/main/java/jcs/ui/widgets/FunctionsPanel.java @@ -969,7 +969,7 @@ public void windowClosing(java.awt.event.WindowEvent e) { if (JCS.getJcsCommandStation() != null) { //LocomotiveBean loc = PersistenceFactory.getService().getLocomotive(49189L); - LocomotiveBean loc = PersistenceFactory.getService().getLocomotive(1001L); + LocomotiveBean loc = PersistenceFactory.getService().getLocomotive(1000L); Logger.debug(loc); testPanel.setLocomotive(loc);