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/nb-configuration.xml b/nb-configuration.xml index e5ed60ac..1b67107a 100644 --- a/nb-configuration.xml +++ b/nb-configuration.xml @@ -35,5 +35,9 @@ Any value defined here will override the pom.xml file value but is only applicab true project all + true + true + LF + false diff --git a/nbactions.xml b/nbactions.xml index c2d9de65..b341619c 100644 --- a/nbactions.xml +++ b/nbactions.xml @@ -81,4 +81,18 @@ test - \ No newline at end of file + + CUSTOM-checkstyle:check + checkstyle:check + + checkstyle:check + + + + CUSTOM-test + test + + test + + + 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 00000000..194a49f3 Binary files /dev/null and b/nbproject/private/profiler/snapshot-1736349327025.nps differ diff --git a/pom.xml b/pom.xml index 7222ff10..ec56d1c3 100644 --- a/pom.xml +++ b/pom.xml @@ -172,6 +172,11 @@ logback-classic 1.2.13 + org.netbeans.external AbsoluteLayout @@ -204,9 +209,10 @@ maven-compiler-plugin 3.13.0 - --enable-preview + + -verbose 21 - false + true @@ -233,6 +239,7 @@ 3.3.1 UTF-8 + ${project.build.sourceEncoding} db:encryptable db @@ -289,7 +296,7 @@ maven-surefire-plugin 3.5.2 - false + -Dfile.encoding=UTF-8 junit.jupiter.execution.parallel.enabled=false @@ -347,6 +354,27 @@ + + org.apache.maven.plugins + maven-checkstyle-plugin + 3.6.0 + + + com.puppycrawl.tools + checkstyle + 10.23.0 + + + + + checkstyle + checkstyle + + checkstyle + + + + io.github.fvarrui javapackager diff --git a/src/main/java/jcs/JCS.java b/src/main/java/jcs/JCS.java index 93ef061a..a24b9757 100755 --- a/src/main/java/jcs/JCS.java +++ b/src/main/java/jcs/JCS.java @@ -15,27 +15,38 @@ */ 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; import javax.swing.UnsupportedLookAndFeelException; import jcs.commandStation.JCSCommandStation; -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; import jcs.persistence.util.H2DatabaseUtil; 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; @@ -46,22 +57,23 @@ * */ 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 static UICallback uiCallback; + + //private final List refreshEventListeners; + private JCS() { - refreshEventListeners = new ArrayList<>(); + //refreshEventListeners = new ArrayList<>(); } - + public static void logProgress(String message) { if (splashScreen != null) { splashScreen.logProgress(message); @@ -69,80 +81,28 @@ 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) { - jcsCommandStation = new JCSCommandStationImpl(); + jcsCommandStation = new JCSCommandStation(); } else { Logger.error("Can't obtain the persistent store!"); } } 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); - } - - //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. @@ -155,21 +115,7 @@ 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 +125,37 @@ 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 +166,29 @@ 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); + } + + 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); - + logProgress("JCS is Starting..."); //Check the persistent properties, prepare environment @@ -221,24 +201,26 @@ 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 ("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,10 +232,11 @@ public static void main(String[] args) { logProgress("NO Default Command Station found..."); } } - + logProgress("Starting UI..."); - + JCS jcs = JCS.getInstance(); + jcs.startGui(); } else { Logger.error("Could not obtain a Persistent store. Quitting...."); @@ -263,20 +246,119 @@ public static void main(String[] args) { System.exit(0); } } - + + 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() { } - + @Override public void onPowerChange(PowerEvent event) { Logger.info("Track Power is " + (event.isPower() ? "on" : "off")); - + if (JCS.jcsFrame != null) { JCS.jcsFrame.powerChanged(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/commandStation/AbstractController.java b/src/main/java/jcs/commandStation/AbstractController.java index 03ed9600..07df81f5 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; + + protected 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/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/DecoderController.java b/src/main/java/jcs/commandStation/DecoderController.java index 9b914e49..2cf3e5b7 100644 --- a/src/main/java/jcs/commandStation/DecoderController.java +++ b/src/main/java/jcs/commandStation/DecoderController.java @@ -17,12 +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; @@ -54,8 +53,6 @@ public interface DecoderController extends GenericController { void removeLocomotiveSpeedEventListener(LocomotiveSpeedEventListener listener); - //List getLocomotiveSpeedEventListeners(); - List getLocomotives(); Image getLocomotiveImage(String icon); @@ -64,5 +61,8 @@ 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/FeedbackController.java b/src/main/java/jcs/commandStation/FeedbackController.java index 79e27ef1..ea15cffd 100644 --- a/src/main/java/jcs/commandStation/FeedbackController.java +++ b/src/main/java/jcs/commandStation/FeedbackController.java @@ -18,8 +18,7 @@ import java.util.List; import jcs.commandStation.events.SensorEvent; import jcs.commandStation.events.SensorEventListener; -import jcs.commandStation.entities.DeviceBean; -import jcs.entities.FeedbackModuleBean; +import jcs.commandStation.entities.FeedbackModule; public interface FeedbackController extends GenericController { @@ -27,9 +26,9 @@ public interface FeedbackController extends GenericController { void removeSensorEventListener(SensorEventListener listener); - DeviceBean getFeedbackDevice(); + //DeviceBean getFeedbackDevice(); - List getFeedbackModules(); + List getFeedbackModules(); void fireSensorEventListeners(SensorEvent sensorEvent); diff --git a/src/main/java/jcs/commandStation/GenericController.java b/src/main/java/jcs/commandStation/GenericController.java index 3920e50e..374510ba 100755 --- a/src/main/java/jcs/commandStation/GenericController.java +++ b/src/main/java/jcs/commandStation/GenericController.java @@ -16,10 +16,10 @@ package jcs.commandStation; import java.util.List; -import jcs.commandStation.events.DisconnectionEventListener; +import jcs.commandStation.entities.Device; import jcs.entities.CommandStationBean; -import jcs.commandStation.entities.DeviceBean; import jcs.commandStation.entities.InfoBean; +import jcs.commandStation.events.ConnectionEventListener; public interface GenericController { @@ -35,15 +35,13 @@ 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(); + List getDevices(); String getIp(); diff --git a/src/main/java/jcs/commandStation/JCSCommandStation.java b/src/main/java/jcs/commandStation/JCSCommandStation.java index 75babf65..977c55a6 100755 --- a/src/main/java/jcs/commandStation/JCSCommandStation.java +++ b/src/main/java/jcs/commandStation/JCSCommandStation.java @@ -16,93 +16,882 @@ 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.DisconnectionEventListener; +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(DisconnectionEventListener 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 { + executor.execute(() -> { + if (decoderController != null) { + 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 d0b0aa2e..00000000 --- a/src/main/java/jcs/commandStation/JCSCommandStationImpl.java +++ /dev/null @@ -1,909 +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.Timer; -import java.util.TimerTask; -import java.util.stream.Collectors; -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.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.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; -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; - -/** - * 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 anonymousSensorListeners; - //private final Map sensorEventListeners; - - private final List accessoryEventListeners; - private final List LocomotiveFunctionEventListeners; - - private final List locomotiveDirectionEventListeners; - private final List locomotiveSpeedEventListeners; - - private final List measurementEventListeners; - - private final Set supportedProtocols; - private CommandStationBean commandStation; - - public JCSCommandStationImpl() { - this("true".equalsIgnoreCase(System.getProperty("skip.controller.autoconnect", "true"))); - } - - private JCSCommandStationImpl(boolean autoConnectController) { - accessoryControllers = new HashMap<>(); - feedbackControllers = new HashMap<>(); - - anonymousSensorListeners = new LinkedList<>(); - accessoryEventListeners = new LinkedList<>(); - LocomotiveFunctionEventListeners = new LinkedList<>(); - locomotiveDirectionEventListeners = new LinkedList<>(); - locomotiveSpeedEventListeners = new LinkedList<>(); - measurementEventListeners = 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() { - //TODO revice the connect, to nices code and preventing duplicat instantiations... - 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.addDisconnectionEventListener(new DisconnectionListener(this)); - - decoderController.addLocomotiveFunctionEventListener(new LocomotiveFunctionChangeEventListener(this)); - decoderController.addLocomotiveDirectionEventListener(new LocomotiveDirectionChangeEventListener(this)); - decoderController.addLocomotiveSpeedEventListener(new LocomotiveSpeedChangeEventListener(this)); - - supportedProtocols.addAll(decoderController.getCommandStationBean().getSupportedProtocols()); - - if (this.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)); - } - } - } - - if (feedbackCntrConnected > 0 && !allreadyConnected) { - for (FeedbackController fc : feedbackControllers.values()) { - if (fc.isConnected()) { - fc.addSensorEventListener(new SensorChangeEventListener(this)); - fc.addDisconnectionEventListener(new DisconnectionListener(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 - this.decoderController = null; - this.accessoryControllers.clear(); - this.feedbackControllers.clear(); - - this.commandStation = null; - ControllerFactory.reset(); - } - - @Override - public void setVirtual(boolean flag) { - Logger.info("Switch Virtual Mode " + (flag ? "On" : "Off")); - this.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 (this.decoderController != null && this.decoderController.getDevice() != null) { - return this.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(); - } - } else { - return null; - } - } - - //@Override - public String getCommandStationSerialNumber() { - if (decoderController != null && decoderController.getDevice() != null) { - return decoderController.getDevice().getSerial(); - } else { - return null; - } - } - - //@Override - public String getCommandStationArticleNumber() { - if (decoderController != null && decoderController.getDevice() != null) { - return decoderController.getDevice().getArticleNumber(); - } else { - return null; - } - } - - @Override - public void switchPower(boolean on) { - //Logger.trace("Switch Power " + (on ? "On" : "Off")); - if (decoderController != null) { - 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 (supportedProtocols.size() == 1) { - address = locomotive.getAddress(); - } else { - if (locomotive.getUid() != null) { - address = locomotive.getUid().intValue(); - } else { - address = locomotive.getId().intValue(); - } - } - if (decoderController != null) { - //Set the velocity to zero before changing the direction - //Run this in a worker thread... - - 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 (supportedProtocols.size() == 1) { - address = locomotive.getAddress(); - } else { - if (locomotive.getUid() != null) { - address = locomotive.getUid().intValue(); - } else { - address = locomotive.getId().intValue(); - } - } - if (decoderController != null) { - 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 (this.supportedProtocols.size() == 1) { - address = locomotive.getAddress(); - } else { - if (locomotive.getUid() != null) { - address = locomotive.getUid().intValue(); - } else { - address = locomotive.getId().intValue(); - } - } - if (decoderController != null) { - decoderController.changeFunctionValue(address, functionNumber, newValue); - } - } - - @Override - public void switchAccessory(AccessoryBean accessory, AccessoryValue value) { - Integer address = accessory.getAddress(); - Integer switchTime = accessory.getSwitchTime(); - 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.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); - } - } - - @Override - public void addSensorEventListener(SensorEventListener listener) { - this.anonymousSensorListeners.add(listener); - } - - @Override - public void removeSensorEventListener(SensorEventListener listener) { - this.anonymousSensorListeners.remove(listener); - } - - @Override - public void addAccessoryEventListener(AccessoryEventListener listener) { - this.accessoryEventListeners.add(listener); - } - - @Override - public void removeAccessoryEventListener(AccessoryEventListener listener) { - this.accessoryEventListeners.remove(listener); - } - - @Override - public void addLocomotiveFunctionEventListener(LocomotiveFunctionEventListener listener) { - this.LocomotiveFunctionEventListeners.add(listener); - } - - @Override - public void removeLocomotiveFunctionEventListener(LocomotiveFunctionEventListener listener) { - this.LocomotiveFunctionEventListeners.remove(listener); - } - - @Override - public void addLocomotiveDirectionEventListener(LocomotiveDirectionEventListener listener) { - this.locomotiveDirectionEventListeners.add(listener); - } - - @Override - public void removeLocomotiveDirectionEventListener(LocomotiveDirectionEventListener listener) { - this.locomotiveDirectionEventListeners.remove(listener); - } - - @Override - public void addLocomotiveSpeedEventListener(LocomotiveSpeedEventListener listener) { - this.locomotiveSpeedEventListeners.add(listener); - } - - @Override - public void removeLocomotiveSpeedEventListener(LocomotiveSpeedEventListener listener) { - this.locomotiveSpeedEventListeners.remove(listener); - } - - @Override - public void addDisconnectionEventListener(DisconnectionEventListener listener) { - if (this.decoderController != null) { - this.decoderController.addDisconnectionEventListener(listener); - } - for (AccessoryController ac : this.accessoryControllers.values()) { - if (ac != this.decoderController) { - ac.addDisconnectionEventListener(listener); - } - } - - for (FeedbackController fc : this.feedbackControllers.values()) { - if (fc != this.decoderController) { - fc.addDisconnectionEventListener(listener); - } - } - } - - @Override - public void addPowerEventListener(PowerEventListener listener) { - if (this.decoderController != null) { - this.decoderController.addPowerEventListener(listener); - } - } - - @Override - public void removePowerEventListener(PowerEventListener listener) { - if (this.decoderController != null) { - this.decoderController.removePowerEventListener(listener); - } - } - - @Override - public void addMeasurementEventListener(MeasurementEventListener listener) { - this.measurementEventListeners.add(listener); - } - - @Override - public void removeMeasurementListener(MeasurementEventListener listener) { - this.measurementEventListeners.remove(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.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(); - SensorBean dbsb = PersistenceFactory.getService().getSensor(sb.getDeviceId(), sb.getContactId()); - - if (dbsb != null) { - sb.setId(dbsb.getId()); - sb.setName(dbsb.getName()); - PersistenceFactory.getService().persist(sb); - } - - //Avoid concurrent modification exceptions - List snapshot = new ArrayList<>(commandStation.anonymousSensorListeners); - - 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 { - Logger.trace("No loc found for " + lb.toLogString()); - } - } - } - } - - private class DisconnectionListener implements DisconnectionEventListener { - - private final JCSCommandStationImpl jcsCommandStationImpl; - - DisconnectionListener(JCSCommandStationImpl jcsCommandStationImpl) { - this.jcsCommandStationImpl = jcsCommandStationImpl; - } - - @Override - public void onDisconnect(DisconnectionEvent event) { - Logger.trace(event.getSource() + " is Disconnected!"); - jcsCommandStationImpl.disconnect(); - } - } - -} 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 32b22ac2..ec5a5670 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; @@ -37,67 +36,107 @@ import jcs.entities.RouteBean; import jcs.entities.SensorBean; import jcs.persistence.PersistenceFactory; -import jcs.ui.layout.events.TileEvent; -import jcs.ui.layout.tiles.TileFactory; +import jcs.ui.layout.tiles.Tile; +import jcs.ui.layout.tiles.TileCache; 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: AutoPilotMonitorThread. * */ public final class AutoPilot { - private static AutoPilotThread autoPilotThread = null; + private static AutoPilotMonitorThread autoPilotThread = null; 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 sensorHandlers = new HashMap<>(); private static final Map dispatchers = new HashMap<>(); //Need a list to be able to unregister 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 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(); } } - public synchronized static void startAutoMode() { + 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) { @@ -289,6 +355,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 +365,32 @@ 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); + 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); - TileFactory.fireTileEventListener(tileEvent); + PersistenceFactory.getService().persist(tile.getBlockBean()); } JCS.getJcsCommandStation().switchPower(true); - Logger.debug("Occupied blocks: " + occupiedBlockCounter + " Free blocks " + freeBlockCounter + " of total " + blocks.size() + " blocks"); } @@ -360,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.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); + return activeLocomotives; //new ArrayList<>(activeLocomotives); } public static boolean isGostDetected() { @@ -388,44 +457,43 @@ 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.getSensorId()); List blocks = PersistenceFactory.getService().getBlocks(); - String sensorId = event.getId(); + Integer sensorId = event.getSensorId(); 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); - TileFactory.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) { 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.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.getId()); sh.handleEvent(event); } else { //sensor is not registered and thus not expected! @@ -440,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); } @@ -470,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() { @@ -499,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); @@ -527,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); @@ -549,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..."); @@ -564,7 +632,7 @@ public void run() { } while (dispatchersRunning && now < timeout) { - dispatchersRunning = areDispatchersRunning(); + dispatchersRunning = isADispatcherRunning(); try { synchronized (this) { wait(10); @@ -604,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.getSensorId())) { AutoPilot.handleSensorEvent(event); } } 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..eb32c7c7 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; @@ -54,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)) { @@ -89,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 8c982a21..019ea6b2 100644 --- a/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java +++ b/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java @@ -32,13 +32,13 @@ import jcs.entities.RouteElementBean; import jcs.entities.TileBean; import jcs.persistence.PersistenceFactory; -import jcs.ui.layout.events.TileEvent; -import jcs.ui.layout.tiles.TileFactory; +import jcs.ui.layout.tiles.TileCache; +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 { @@ -50,22 +50,22 @@ 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; private final ThreadGroup parent; - private StateMachineThread stateMachineThread; + private StateMachine stateMachine; public Dispatcher(ThreadGroup parent, LocomotiveBean locomotiveBean) { this.parent = parent; @@ -73,11 +73,11 @@ public Dispatcher(ThreadGroup parent, 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() { @@ -108,45 +108,45 @@ void setRouteBean(RouteBean routeBean) { } 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); } @@ -168,13 +168,13 @@ void resetDispatcher() { 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; } @@ -189,7 +189,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; } } @@ -206,59 +206,59 @@ BlockBean getDestinationBlock() { } public String getStateName() { - if (stateMachineThread != null) { - return stateMachineThread.getDispatcherStateName(); + if (stateMachine != null) { + return stateMachine.getDispatcherStateName(); } else { return "#Idle"; } } - 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,32 +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) { @@ -308,7 +307,7 @@ synchronized void changeLocomotiveDirection(LocomotiveBean locomotive, Direction locomotiveBean.setDirection(newDirection); } - void fireStateListeners(String s) { + public void fireStateListeners(String s) { for (StateEventListener sel : stateEventListeners) { sel.onStateChange(this); } @@ -322,36 +321,68 @@ 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) { String tileId = re.getTileId(); - TileEvent tileEvent = new TileEvent(tileId, false); - TileFactory.fireTileEventListener(tileEvent); + Tile tile = TileCache.findTile(tileId); + 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!")); + } } } void showBlockState(BlockBean blockBean) { - Logger.trace("Show block " + blockBean); - TileEvent tileEvent = new TileEvent(blockBean); - TileFactory.fireTileEventListener(tileEvent); + Tile tile = TileCache.findTile(blockBean.getTileId()); + 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(); - TileBean.Orientation incomingSide = re.getIncomingOrientation(); - - TileEvent tileEvent; - if (re.isTurnout()) { - AccessoryBean.AccessoryValue routeState = re.getAccessoryValue(); - tileEvent = new TileEvent(tileId, true, incomingSide, routeState, routeColor); + 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); + } 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 { - tileEvent = new TileEvent(tileId, true, incomingSide, routeColor); + Logger.warn("Tile with id " + tileId + " NOT in TileCache!"); } - TileFactory.fireTileEventListener(tileEvent); } } diff --git a/src/main/java/jcs/commandStation/autopilot/state/EnterBlockState.java b/src/main/java/jcs/commandStation/autopilot/state/EnterBlockState.java index 1d21e6aa..bf72abfd 100644 --- a/src/main/java/jcs/commandStation/autopilot/state/EnterBlockState.java +++ b/src/main/java/jcs/commandStation/autopilot/state/EnterBlockState.java @@ -31,8 +31,7 @@ class EnterBlockState extends DispatcherState implements SensorEventListener { private boolean locomotiveBraking = false; private boolean canAdvanceToNextState = false; - private String inSensorId; - //private Dispatcher dispatcher; + private Integer inSensorId; @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); - dispatcher.showBlockState(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()); } @@ -107,15 +102,14 @@ 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.getSensorId()); synchronized (this) { this.notifyAll(); } } } } - } diff --git a/src/main/java/jcs/commandStation/autopilot/state/IdleState.java b/src/main/java/jcs/commandStation/autopilot/state/IdleState.java index df5b5dbb..4ec46479 100644 --- a/src/main/java/jcs/commandStation/autopilot/state/IdleState.java +++ b/src/main/java/jcs/commandStation/autopilot/state/IdleState.java @@ -59,6 +59,19 @@ DispatcherState execute(Dispatcher dispatcher) { } catch (InterruptedException ex) { Logger.trace("Interrupted: " + ex.getMessage()); } + } else { + //Locomotive is stopped... + Logger.trace(dispatcher.getName() + " Automode: " + AutoPilot.isAutoModeActive() + " Dispacher " + dispatcher.isLocomotiveAutomodeOn()); + + //stop this thread... + try { + synchronized (this) { + wait(10000); + } + } catch (InterruptedException ex) { + Logger.trace("Interrupted: " + ex.getMessage()); + } + } } return this; diff --git a/src/main/java/jcs/commandStation/autopilot/state/PrepareRouteState.java b/src/main/java/jcs/commandStation/autopilot/state/PrepareRouteState.java index c23b62e2..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()); @@ -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()); @@ -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..7e9ad095 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.getSensorId()); synchronized (this) { this.notifyAll(); } 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/dccex/DccExCommandStationImpl.java b/src/main/java/jcs/commandStation/dccex/DccExCommandStationImpl.java index acc797ca..7f292924 100644 --- a/src/main/java/jcs/commandStation/dccex/DccExCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/dccex/DccExCommandStationImpl.java @@ -17,9 +17,7 @@ import java.awt.Image; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.concurrent.Executors; import jcs.JCS; import jcs.commandStation.AbstractController; @@ -29,10 +27,10 @@ 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.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; @@ -43,34 +41,31 @@ 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; public class DccExCommandStationImpl extends AbstractController implements DecoderController, AccessoryController { private DccExConnection connection; private InfoBean infoBean; - private DeviceBean mainDevice; + //private DeviceBean mainDevice; private boolean powerStatusSet = false; - Map measurementChannels; - + //Map measurementChannels; public DccExCommandStationImpl(CommandStationBean commandStationBean) { this(commandStationBean, false); } public DccExCommandStationImpl(CommandStationBean commandStationBean, boolean autoConnect) { super(autoConnect, commandStationBean); - measurementChannels = new HashMap<>(); + //measurementChannels = new HashMap<>(); this.executor = Executors.newCachedThreadPool(); if (commandStationBean != null) { @@ -83,26 +78,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() { if (!connected) { @@ -165,51 +159,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()); @@ -246,8 +238,8 @@ public final boolean connect() { Logger.trace(response); } - initMeasurements(); - Logger.trace("Connected with: " + (this.mainDevice != null ? this.mainDevice.getName() : "Unknown")); + //initMeasurements(); + //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!"); @@ -334,15 +326,8 @@ 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) { + 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,11 +350,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() { throw new UnsupportedOperationException("Not supported yet."); @@ -390,42 +374,34 @@ 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; } @Override - public boolean isSupportTrackMeasurements() { - return true; + public List getDevices() { + List devices = new ArrayList<>(); + return devices; } @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; - } - - private void fireAllDisconnectionEventListeners(final DisconnectionEvent disconnectionEvent) { - for (DisconnectionEventListener listener : this.disconnectionEventListeners) { - listener.onDisconnect(disconnectionEvent); + public boolean isSupportTrackMeasurements() { + return false; // true; + } + +// 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) { + listener.onConnectionChange(disconnectionEvent); } disconnect(); } @@ -494,76 +470,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)); Logger.trace("Info: " + message); @@ -621,22 +596,22 @@ 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]); - } - } - commandStation.mainDevice = d; +// 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); } case "c" -> { @@ -653,7 +628,7 @@ public void onMessage(DccExMessage message) { } case "j" -> { DccExMeasurementEvent me2 = new DccExMeasurementEvent(opcode, content); - commandStation.handleMeasurement(me2); + //commandStation.handleMeasurement(me2); } case "H" -> { } @@ -677,14 +652,15 @@ public void onMessage(DccExMessage message) { } @Override - public void onDisconnect(DisconnectionEvent event) { + public void onDisconnect(ConnectionEvent event) { this.commandStation.fireAllDisconnectionEventListeners(event); } } -////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////// // For testing only + public static void main(String[] a) { System.setProperty("message.debug", "true"); @@ -732,7 +708,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/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/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/entities/DeviceBean.java b/src/main/java/jcs/commandStation/entities/DeviceBean.java deleted file mode 100644 index c9175150..00000000 --- a/src/main/java/jcs/commandStation/entities/DeviceBean.java +++ /dev/null @@ -1,586 +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 - */ -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 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(); - - this.uid = "0x" + Integer.toHexString(uidAsInt); - - //this.uid = resp.getDeviceUidNumberFromMessage(); - //TODO: Version is not same displayed in the CS - this.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); - //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); - } - } - -// 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); - 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/FeedbackModule.java b/src/main/java/jcs/commandStation/entities/FeedbackModule.java new file mode 100644 index 00000000..9c4ca6cc --- /dev/null +++ b/src/main/java/jcs/commandStation/entities/FeedbackModule.java @@ -0,0 +1,305 @@ +/* + * Copyright 2024 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.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 FeedbackModule implements Comparable { + + private Integer id; + private Integer moduleNumber; + private Integer portCount; + private Integer addressOffset; + private Integer identifier; + private Integer busNumber; + private String commandStationId; + private Integer busSize; + + private int[] ports; + private int[] prevPorts; + + public static int DEFAULT_PORT_COUNT = 16; + public static int DEFAULT_ADDRESS_OFFSET = 0; + public static int DEFAULT_IDENTIFIER = 0; + + public FeedbackModule() { + this(null, null, null); + } + + public FeedbackModule(Integer id, Integer moduleNumber, String commandStationId) { + this(id, moduleNumber, DEFAULT_PORT_COUNT, DEFAULT_ADDRESS_OFFSET, DEFAULT_IDENTIFIER, commandStationId); + } + + public FeedbackModule(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]; + } + + @Override + public int compareTo(FeedbackModule 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; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getModuleNumber() { + return moduleNumber; + } + + public void setModuleNumber(Integer moduleNumber) { + this.moduleNumber = moduleNumber; + } + + public Integer getPortCount() { + return portCount; + } + + public void setPortCount(Integer portCount) { + this.portCount = portCount; + if (portCount != null && portCount != ports.length) { + ports = new int[portCount]; + prevPorts = new int[portCount]; + } + } + + public Integer getAddressOffset() { + return addressOffset; + } + + public void setAddressOffset(Integer addressOffset) { + this.addressOffset = addressOffset; + } + + public Integer getIdentifier() { + return identifier; + } + + 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; + } + + public void setPorts(int[] ports) { + this.ports = ports; + } + + public void setPortValue(int port, boolean active) { + //save current values + 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 ports[port] == 1; + } else { + return false; + } + } + + public int getAccumulatedPortsValue() { + int val = 0; + for (int i = 0; i < ports.length; i++) { + int portVal = 0; + if (ports[i] == 1) { + portVal = (int) Math.pow(2, i); + } + val = val + portVal; + } + return val; + } + + public int[] getPrevPorts() { + return prevPorts; + } + + public void setPrevPorts(int[] prevPorts) { + this.prevPorts = prevPorts; + } + + public String getCommandStationId() { + return commandStationId; + } + + 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; + 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 - 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) { + offset = addressOffset; + } else { + Logger.warn("Module connected to bus " + busNumber + " but bus address offset is not specified!"); + } + 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]; + + 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; + } + + 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 = getSensor(i); + changedSensors.add(sb); + } + } + return changedSensors; + } + + public List getChangedSensorEvents() { + List changedSensorEvents = new ArrayList<>(ports.length); + + for (int i = 0; i < ports.length; i++) { + if (ports[i] != prevPorts[i]) { + SensorBean sb = getSensor(i); + SensorEvent se = new SensorEvent(sb); + changedSensorEvents.add(se); + } + } + return changedSensorEvents; + } + + public String portToString() { + StringBuilder sb = new StringBuilder(); + sb.append(" {"); + for (int i = 0; i < ports.length; i++) { + sb.append(i + 1); + sb.append("["); + sb.append(ports[i]); + sb.append("] "); + } + sb.append("}"); + return sb.toString(); + } + + @Override + public String toString() { + return "FeedbackModuleBean{" + "id=" + id + ", moduleNumber=" + moduleNumber + ", portCount=" + portCount + ", addressOffset=" + addressOffset + ", identifier=" + identifier + "}"; + } + +} +// +// 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/commandStation/entities/InfoBean.java b/src/main/java/jcs/commandStation/entities/InfoBean.java index f140c2cf..48e8c7ed 100644 --- a/src/main/java/jcs/commandStation/entities/InfoBean.java +++ b/src/main/java/jcs/commandStation/entities/InfoBean.java @@ -15,8 +15,8 @@ */ package jcs.commandStation.entities; - import jakarta.persistence.Transient; +import java.util.Objects; import jcs.entities.CommandStationBean; /** @@ -32,41 +32,17 @@ public class InfoBean extends CommandStationBean { private String hostname; private String gfpUid; private String guiUid; + private boolean supportMeasurements; -//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() { } public InfoBean(CommandStationBean commandStationBean) { + copyInto(commandStationBean); + } + + public final void copyInto(CommandStationBean commandStationBean) { this.id = commandStationBean.getId(); this.description = commandStationBean.getDescription(); this.shortName = commandStationBean.getShortName(); @@ -169,9 +145,68 @@ 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 + "}"; } + @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/entities/MeasuredChannels.java b/src/main/java/jcs/commandStation/entities/MeasuredChannels.java new file mode 100644 index 00000000..d065c2d6 --- /dev/null +++ b/src/main/java/jcs/commandStation/entities/MeasuredChannels.java @@ -0,0 +1,148 @@ +/* + * 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() { + 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/MeasurementBean.java b/src/main/java/jcs/commandStation/entities/MeasurementBean.java new file mode 100644 index 00000000..722183e4 --- /dev/null +++ b/src/main/java/jcs/commandStation/entities/MeasurementBean.java @@ -0,0 +1,195 @@ +/* + * 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; +import java.util.Objects; + +/** + * A Bean which hold measured values + */ +public class MeasurementBean { + + private Integer channelNumber; + private String name; + private boolean valid; + private Long measurementMillis; + + private Integer measuredValue; + private String unit; + + 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("MeasurementBean{"); + 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/esu/ecos/AccessoryManager.java b/src/main/java/jcs/commandStation/esu/ecos/AccessoryManager.java index f3220b39..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 -> @@ -216,6 +218,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()) { @@ -230,7 +244,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()); } @@ -398,6 +412,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/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 2e2b5766..4d609dc2 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java @@ -19,9 +19,9 @@ 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.Map; import java.util.concurrent.Executors; import java.util.concurrent.TransferQueue; import jcs.JCS; @@ -36,10 +36,8 @@ 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.FeedbackModule; import jcs.commandStation.entities.InfoBean; import jcs.commandStation.esu.ecos.net.EcosHTTPConnection; import jcs.commandStation.events.AccessoryEvent; @@ -53,9 +51,11 @@ 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; +import jcs.util.Ping; import org.tinylog.Logger; public class EsuEcosCommandStationImpl extends AbstractController implements DecoderController, AccessoryController, FeedbackController { @@ -98,12 +98,10 @@ public void setVirtual(boolean flag) { connect(); } - - @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(); } @@ -117,72 +115,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 { - //try to discover the ECoS - InetAddress ecosAddr = EcosConnectionFactory.discoverEcos(); - String ip = ecosAddr.getHostAddress(); - commandStationBean.setIpAddress(ip); - EcosConnectionFactory.writeLastUsedIpAddressProperty(commandStationBean.getIpAddress()); - canConnect = ip != null; - if (!canConnect) { - Logger.error("Can't connect; IP Address not set"); + try { + InetAddress ecosAddr; + if (virtual) { + ecosAddr = InetAddress.getLocalHost(); + } else { + 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() { @@ -230,11 +237,11 @@ 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); - connection.sendMessage(EcosMessageFactory.subscribeFeedbackModule(moduleId)); //Logger.trace("r: "+reply.getResponse()); } @@ -243,18 +250,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 (FeedbackModule 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); } @@ -262,16 +289,19 @@ public void disconnect() { @Override 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()); + InfoBean ib = new InfoBean(commandStationBean); + 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()); + if (ib.getIpAddress() == null) { + ib.setIpAddress(getIp()); + } } else { ib.setDescription("Not Connected"); ib.setHostname("Not Connected"); @@ -279,26 +309,37 @@ 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; - } + 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); - //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; } @@ -401,8 +442,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); } } } @@ -469,21 +509,9 @@ public boolean isSupportTrackMeasurements() { } @Override - public Map getTrackMeasurements() { - throw new UnsupportedOperationException("Not supported yet."); - } - - @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 { @@ -491,8 +519,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; @@ -543,41 +571,24 @@ EcosConnection getConnection() { } @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()); + public List getFeedbackModules() { + List feedbackModules = new ArrayList<>(this.feedbackManager.getModules().values()); return feedbackModules; } @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) { + listener.onSensorChange(sensorEvent); + } } } @Override public void simulateSensor(SensorEvent sensorEvent) { - if (this.connection instanceof VirtualConnection virtualConnection) { + if (connection instanceof VirtualConnection virtualConnection) { virtualConnection.sendEvent(sensorEvent); } } @@ -607,8 +618,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); + } } } @@ -622,7 +635,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; @@ -632,16 +644,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 @@ -651,7 +656,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())); @@ -684,21 +689,25 @@ 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"); } } -////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////// + /// @param a // For testing only public static void main(String[] a) { @@ -753,6 +762,13 @@ public static void main(String[] a) { // // cs.pause(1000); // + List feedbackModules = cs.getFeedbackModules(); + Logger.trace("There are " + feedbackModules + " Feedback Modules"); + 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()); + } // power = cs.power(true); // Logger.trace("4 Power is " + (power ? "On" : "Off")); //EcosMessage reply = cs.connection.sendMessage(new EcosMessage("queryObjects(26)")); @@ -829,6 +845,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/FeedbackManager.java b/src/main/java/jcs/commandStation/esu/ecos/FeedbackManager.java index 87c97142..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; /** @@ -31,9 +31,12 @@ 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 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; @@ -42,7 +45,6 @@ class FeedbackManager { } private List parse(EcosMessage message) { - Logger.trace(message.getMessage()); Logger.trace(message.getResponse()); List changedSensors; @@ -51,14 +53,22 @@ private List parse(EcosMessage message) { int objectId = message.getObjectId(); if (ID != objectId) { - FeedbackModuleBean feedbackModule; - if (this.modules.containsKey(objectId)) { - feedbackModule = this.modules.get(objectId); + FeedbackModule feedbackModule; + if (modules.containsKey(objectId)) { + feedbackModule = modules.get(objectId); } else { - feedbackModule = new FeedbackModuleBean(); + feedbackModule = new FeedbackModule(); feedbackModule.setId(objectId); - feedbackModule.setAddressOffset(S88_OFFSET); - feedbackModule.setModuleNumber(objectId - S88_OFFSET); + feedbackModule.setAddressOffset(0); + feedbackModule.setModuleNumber(objectId - S88_OFFSET + 1); + //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)) { @@ -67,19 +77,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); - changedSensors = feedbackModule.getChangedSensors(); + modules.put(objectId, feedbackModule); + changedSensors = feedbackModule.getChangedSensorEvents(); if (event) { - if (this.ecosCommandStation != null) { + if (ecosCommandStation != null) { for (SensorEvent sensorEvent : changedSensors) { - this.ecosCommandStation.fireSensorEventListeners(sensorEvent); + ecosCommandStation.fireSensorEventListeners(sensorEvent); } } } @@ -88,14 +100,24 @@ 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(); - fbmb.setAddressOffset(S88_OFFSET); - fbmb.setModuleNumber(i); - fbmb.setId(S88_OFFSET+i); - this.modules.put(fbmb.getId(), fbmb); + FeedbackModule fbmb = new FeedbackModule(); + fbmb.setAddressOffset(0); + 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) { + fbmb.setCommandStationId(ecosCommandStation.getCommandStationBean().getId()); + } else { + fbmb.setCommandStationId(ESU_ECOS_CS); + } + + modules.put(fbmb.getId(), fbmb); } } - } changedSensors = Collections.EMPTY_LIST; } @@ -111,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++) { @@ -122,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); @@ -139,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) { - return this.modules.get(id); + public FeedbackModule getFeedbackModule(int id) { + return modules.get(id); } } 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/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 a7a613e9..a1cdd443 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; /** @@ -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(); - DisconnectionEvent de = new DisconnectionEvent(msg); + 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()); @@ -259,29 +266,29 @@ 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); } - } } catch (SocketException se) { Logger.error(se.getMessage()); String msg = "Host " + ecosAddress.getHostName(); - DisconnectionEvent de = new DisconnectionEvent(msg); - this.messageListener.onDisconnect(de); + ConnectionEvent de = new ConnectionEvent(msg, false); + 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/esu/ecos/net/EcosVirtualConnection.java b/src/main/java/jcs/commandStation/esu/ecos/net/EcosVirtualConnection.java index db9dad58..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; @@ -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 @@ -178,7 +180,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(); @@ -195,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()); @@ -332,6 +334,7 @@ public synchronized EcosMessage sendMessage(EcosMessage message) { replyBuilder.append("]"); } } + } replyBuilder.append(""); @@ -400,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); @@ -424,8 +427,8 @@ 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()); - //Logger.trace(fbm.getId()+" nr: "+fbm.getModuleNumber() + " Current ports: " + fbm.portToString()); + 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()); //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 6da6b9b2..34f94a98 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; @@ -32,27 +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 String getId() { - return this.accessoryBean.getId(); + 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 getIdString() { + return accessoryBean.getId(); } } 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/JCSActionEvent.java b/src/main/java/jcs/commandStation/events/JCSActionEvent.java new file mode 100644 index 00000000..e353eee1 --- /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 getIdString(); + +} 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/events/SensorEvent.java b/src/main/java/jcs/commandStation/events/SensorEvent.java index 2021fcfb..3cb14f62 100755 --- a/src/main/java/jcs/commandStation/events/SensorEvent.java +++ b/src/main/java/jcs/commandStation/events/SensorEvent.java @@ -18,59 +18,57 @@ 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; } - 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 Integer getSensorId() { + return sensorBean.getId(); + } + + @Deprecated + @Override + public String getIdString() { + return sensorBean.getId().toString(); } 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 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 1be08b88..8dd0d3c0 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; @@ -23,20 +24,20 @@ 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; import jcs.entities.CommandStationBean; import jcs.entities.CommandStationBean.ConnectionType; -import jcs.commandStation.entities.DeviceBean; -import jcs.entities.FeedbackModuleBean; +import jcs.commandStation.entities.FeedbackModule; 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; +import jcs.commandStation.events.ConnectionEventListener; /** * @@ -47,9 +48,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 +60,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 +124,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,28 +157,18 @@ 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() { + public List getFeedbackModules() { return null; } @@ -202,9 +193,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(); } @@ -237,7 +228,7 @@ public void onMessage(final HSIMessage message) { } @Override - public void onDisconnect(DisconnectionEvent event) { + public void onDisconnect(ConnectionEvent event) { this.hsiImpl.fireAllDisconnectionEventListeners(event); } } @@ -279,7 +270,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/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 09c31a62..4184a799 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java +++ b/src/main/java/jcs/commandStation/marklin/cs/MarklinCentralStationImpl.java @@ -15,13 +15,22 @@ */ 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.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; import java.util.Date; 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.stream.Collectors; +import java.util.concurrent.TransferQueue; import jcs.JCS; import jcs.commandStation.AbstractController; import jcs.commandStation.AccessoryController; @@ -44,61 +53,70 @@ 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.HTTPConnection; 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.cs2.AccessoryEventParser; -import jcs.entities.FeedbackModuleBean; -import jcs.commandStation.marklin.cs2.InfoBeanParser; +import jcs.commandStation.marklin.cs.can.parser.AccessoryMessage; +import jcs.commandStation.entities.FeedbackModule; 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.marklin.cs2.SensorMessageParser; 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; +import jcs.commandStation.marklin.cs.can.device.ConfigChannel; +import jcs.commandStation.marklin.cs.can.device.MeasuringChannel; +import jcs.commandStation.marklin.parser.CanDeviceParser; +import jcs.commandStation.marklin.cs.can.parser.LocomotiveEmergencyStopMessage; 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; import org.tinylog.Logger; +import jcs.commandStation.marklin.cs.net.CSHTTPConnection; +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; +import jcs.util.Ping; /** - * - * @author Frans Jacobs + * Command Station Implementation for Marklin CS-2/3 */ -public class MarklinCentralStationImpl extends AbstractController implements DecoderController, AccessoryController, FeedbackController { +public class MarklinCentralStationImpl extends AbstractController implements DecoderController, AccessoryController, FeedbackController, ConnectionEventListener { 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; + + private DriveSimulator simulator; + + private Long canBootLoaderLastCallMillis; + private WatchdogTask watchdogTask; + private Timer watchDogTimer; + + private MeasurementTask measurementTask; + private Timer measurementTimer; - Map analogChannels; + private SortedMap measuredValues; public MarklinCentralStationImpl(CommandStationBean commandStationBean) { this(commandStationBean, false); @@ -106,8 +124,8 @@ public MarklinCentralStationImpl(CommandStationBean commandStationBean) { 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) { @@ -123,14 +141,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); + boolean isCS3() { + if (infoBean != null && infoBean.getArticleNumber() != null) { + return "60216".equals(infoBean.getArticleNumber()) || "60226".equals(infoBean.getArticleNumber()); } else { return false; } @@ -141,24 +154,77 @@ 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(); + } + + 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) { - 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(); - connection = csConnection; + 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 = CSConnectionFactory.getConnection(commandStationBean); if (connection != null) { - //Wait, if needed until the receiver thread has started long now = System.currentTimeMillis(); - long timeout = now + 1000L; + long timeout = now + 5000L; while (!connected && now < timeout) { - connected = csConnection.isConnected(); + connected = connection.isConnected(); now = System.currentTimeMillis(); } if (!connected && now > timeout) { @@ -166,142 +232,352 @@ 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); + CanDevice gfp = getGFP(); + canDevices.put(gfp.getUidInt(), gfp); + csUid = gfp.getUidInt(); + + 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(); + } - infoBean = getCSInfo(); + //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(); - //request all members on the Marklin CAN bus to give a response - long start = System.currentTimeMillis(); - now = System.currentTimeMillis(); - timeout = now + 30000L; + connection.addDisconnectionEventListener(this); + startWatchdog(); - 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(); - } - } + power = isPower(); + JCS.logProgress("Power is " + (power ? "On" : "Off")); - if (mainDevice != null) { - Logger.trace("Found " + mainDevice.getName() + ", " + mainDevice.getArticleNumber() + " SerialNumber: " + mainDevice.getSerial() + " in " + (now - start) + " ms"); - JCS.logProgress("Connected with " + infoBean.getProductName()); +// if (gfp.getMeasureChannelCount() != null && gfp.getMeasureChannelCount() > 0) { +// Logger.trace("Measurements are possible..."); +// } +// else { +// queryDevice(gfp); +// Logger.trace("GFP Measurement Count: " + gfp.getMeasureChannelCount()); +// } + startMeasurements(); - power = isPower(); - JCS.logProgress("Power is " + (power ? "On" : "Off")); - } else { - Logger.warn("No main Device found yet..."); - } + Logger.trace("Connected to " + gfp.getName() + ", " + gfp.getArticleNumber() + " SerialNumber: " + gfp.getSerial()); } - Logger.trace("Connected: " + connected + " Default Accessory SwitchTime: " + this.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!"); } return connected; } - //The Central station has a "geraet.vrs" files which can be retrieved via HTTP. + //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 3 the data can ve retreived via JSON else use CAN - private InfoBean getCSInfo() { - HTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(); + //In case of a CS-3 the information can be retrieved via JSON else use CAN + CanDevice getGFP() { + CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(); String geraet = httpCon.getInfoFile(); - InfoBean ib = InfoBeanParser.parseFile(geraet); + CanDevice gfp = GeraetParser.parseFile(geraet); + return gfp; + } + + InfoBean createInfoBean(Map canDevices) { + InfoBean ib = new InfoBean(commandStationBean); + if (connection != null && connection.getControllerAddress() != null) { + ib.setIpAddress(connection.getControllerAddress().getHostAddress()); + } - if ("60126".equals(ib.getArticleNumber()) || "60226".equals(ib.getArticleNumber())) { - //CS3 - String json = httpCon.getInfoJSON(); - ib = InfoBeanParser.parseJson(json); - httpCon.setCs3(true); + 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 "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); + 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() { - HTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(); + void obtainDevices() { + 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())) { - //Logger.trace("Updating " + d.getUid() + ", " + d.getName()); - devices.put(d.getUidAsInt(), d); + List devices = CanDeviceParser.parse(msg); + Logger.trace("Found " + devices.size() + " CANDevices"); + for (CanDevice d : devices) { + if (!canDevices.containsKey(d.getUidInt())) { + canDevices.put(d.getUidInt(), 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); + 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); } + } + + //Lets get some info about these members + for (CanDevice device : canDevices.values()) { + queryDevice(device); + } + } + + void queryDevice(CanDevice device) { + Logger.trace("Query for information about device " + device); + CanMessage updateMessage = sendMessage(CanMessageFactory.statusDataConfig(device.getUidInt(), 0)); - if ("60883".equals(an)) { - this.feedbackDevice = d; - Logger.trace("FeedbackDevice: " + d); + 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); } - Logger.trace("Found " + devices.size() + " devices"); } - @Override - public DeviceBean getDevice() { - return this.mainDevice; - } + /** + * 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 List getCS3Devices() { + CSHTTPConnection httpCon = CSConnectionFactory.getHTTPConnection(); - @Override - public List getDevices() { - return this.devices.values().stream().collect(Collectors.toList()); + String devJson = httpCon.getDevicesJSON(); + List devices = CanDeviceJSONParser.parse(devJson); + return devices; } @Override public InfoBean getCommandStationInfo() { + if (infoBean == null) { + infoBean = createInfoBean(canDevices); + } return infoBean; } @Override - public DeviceBean getFeedbackDevice() { - return this.feedbackDevice; + 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()); + d.setFeedback(CanDevice.FEEDBACK_DEVICE_NAME.equals(cd.getName())); + devices.add(d); + } + + return devices; } - //TODO! @Override - public List getFeedbackModules() { - return null; + 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(CanDevice.FEEDBACK_DEVICE_NAME); + int bus1Len = 0, bus2Len = 0, bus3Len = 0, nodeId = 0; + if (links88 != null) { + nodeId = links88.getIdentifierInt() + 1; + for (ConfigChannel cc : links88.getConfigChannels()) { + if (cc.getNumber() == 2) { + bus1Len = cc.getActualValue(); + } + if (cc.getNumber() == 3) { + bus2Len = cc.getActualValue(); + } + 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 + FeedbackModule l = new FeedbackModule(); + l.setId(0); + + l.setAddressOffset(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++) { + FeedbackModule b1 = new FeedbackModule(); + //Use the offset plus module nr as the id + b1.setId(1000 + i); + b1.setAddressOffset(1000); + 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++) { + FeedbackModule b2 = new FeedbackModule(); + b2.setId(2000 + i); + b2.setAddressOffset(2000); + 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++) { + FeedbackModule b3 = new FeedbackModule(); + b3.setId(3000 + i); + b3.setAddressOffset(3000); + b3.setModuleNumber(i + 1); + b3.setPortCount(16); + b3.setIdentifier(nodeId); + b3.setBusNumber(3); + b3.setCommandStationId(commandStationBean.getId()); + b3.setBusSize(bus3Len); + + feedbackModules.add(b3); + } + } + + return feedbackModules; } /** @@ -311,36 +587,31 @@ 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; } /** - * 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 */ @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; @@ -349,15 +620,36 @@ public boolean power(boolean on) { @Override public void disconnect() { + Logger.trace("Start disconnecting..."); + //Stop all schedules + if (measurementTimer != null) { + measurementTimer.cancel(); + } + if (watchDogTimer != null) { + 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) { + listener.onMeasurement(me); + } + try { if (connection != null) { + if (eventMessageHandler != null) { + eventMessageHandler.quit(); + } + eventMessageHandler.join(2000); connection.close(); connected = false; } - if (executor != null) { - executor.shutdown(); - } executor = null; connection = null; @@ -368,164 +660,67 @@ public void disconnect() { Logger.trace("Disconnected"); } - void getMembers() { - CanMessage msg = CanMessageFactory.getMembersPing(); - this.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"); + @Override + public void onConnectionChange(ConnectionEvent event) { + String s = event.getSource(); + boolean con = event.isConnected(); + if (con) { + Logger.trace(s + " has re-connected"); + } else { + disconnect(); } - while (mainDevice == null) { - for (DeviceBean d : this.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); - } - } - d.updateFromMessage(updateMessage); - if (debug) { - if (d.isDataComplete()) { - Logger.trace("Updated: " + d); - } else { - Logger.trace("No data received for Device uid: " + d.getUid()); - } - } - } - } - - for (DeviceBean d : this.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", this.mainDevice.getArticleNumber()); - System.setProperty("cs.serial", this.mainDevice.getSerial()); - System.setProperty("cs.name", this.mainDevice.getName()); - System.setProperty("cs.cs3", (isCS3() ? "true" : "false")); - } - } else { - if (debug) { - Logger.trace(d); - } - } - } + for (ConnectionEventListener listener : connectionEventListeners) { + listener.onConnectionChange(event); } } - private void updateMember(CanMessage message) { - executor.execute(() -> updateDevice(message)); + @Override + public boolean isSupportTrackMeasurements() { + if (!virtual) { + CanDevice gfp = canDevices.get(csUid); + return gfp != null && gfp.getMeasureChannelCount() != null && gfp.getMeasureChannelCount() > 0; + } else { + return false; + } } - 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); - } else { - device = new DeviceBean(message); - this.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); + void performMeasurements() { + //The measurable channels are in the GFP. + CanDevice gfp = canDevices.get(csUid); + if (gfp != null) { + List channels = gfp.getMeasuringChannels(); + 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, now); + measuredChannels.addMeasurement(measurement); + //Logger.trace(measurement); + measuredValues.put(now, measuredChannels); + if (measuredValues.size() > 100) { + long first = measuredValues.firstKey(); + measuredValues.remove(first); } - //Can the main device be set from the avaliable data - for (DeviceBean d : this.devices.values()) { - if (d.isDataComplete() && ("60214".equals(d.getArticleNumber()) || "60226".equals(d.getArticleNumber()) || "60126".equals(d.getArticleNumber()))) { - this.csUid = d.getUidAsInt(); - this.mainDevice = d; - if (debug) { - Logger.trace("Main Device: " + d); - } - } - } - } - if (this.mainDevice == null) { - //Lets send a ping again - getMembers(); - } else { - if (this.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()); - System.setProperty("cs.name", this.mainDevice.getName()); - System.setProperty("cs.cs3", (isCS3() ? "true" : "false")); - if (debug) { - Logger.trace("CS " + (isCS3() ? "3" : "2") + " Device: " + device); - } - } + MeasurementEvent me = new MeasurementEvent(measuredChannels); + for (MeasurementEventListener listener : measurementEventListeners) { + listener.onMeasurement(me); } } + } else { + Logger.warn("No measurable channels available"); } } - @Override - public boolean isSupportTrackMeasurements() { - return true; + public List getMeasurements() { + return new ArrayList<>(measuredValues.values()); } - @Override - public synchronized Map getTrackMeasurements() { - if (this.connected && this.mainDevice != null) { - //main device - int nrOfChannels = this.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 this.analogChannels; + public MeasuredChannels getLastMeasurment() { + return measuredValues.firstEntry().getValue(); } /** @@ -537,8 +732,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 && connected) { + connection.sendCanMessage(canMessage); } else { Logger.warn("NOT connected!"); Logger.trace("Message: " + canMessage + " NOT Send!"); @@ -546,58 +741,49 @@ 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 (this.power && this.connected) { + 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 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) { - CanMessage message = sendMessage(CanMessageFactory.setLocSpeed(locUid, speed, this.csUid)); - LocomotiveSpeedEvent vme = LocomotiveSpeedEventParser.parseMessage(message); - this.notifyLocomotiveSpeedEventListeners(vme); + if (power && connected) { + 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); + + 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); + simulator.simulateDriving(locUid, speed, direction); + } + } } } @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)); } } @Override - public void switchAccessory(Integer address, AccessoryValue value) { - switchAccessory(address, value, defaultSwitchTime); - } - - @Override - public void switchAccessory(Integer address, AccessoryValue value, Integer switchTime) { - if (this.power && this.connected) { + public void switchAccessory(Integer address, String protocol, AccessoryValue value, Integer switchTime) { + if (power && connected) { //make sure a time is set! int st; if (switchTime == null || switchTime == 0) { @@ -605,36 +791,30 @@ 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 = AccessoryEventParser.parseMessage(message); - + 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."); - } - - private void sendJCSUID() { - executor.execute(() -> sendJCSUIDMessage()); - } - - private void sendJCSUIDMessage() { + void sendJCSUIDMessage() { sendMessage(CanMessageFactory.getMemberPingResponse(CanMessage.JCS_UID, 1, CanMessage.JCS_DEVICE_ID)); } - private void sendJCSInformation() { - executor.execute(() -> sentJCSInformationMessage()); - } - - 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); @@ -643,7 +823,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(); @@ -651,14 +831,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 +866,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 +896,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"); @@ -737,12 +917,7 @@ 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(); + power = powerEvent.isPower(); for (PowerEventListener listener : powerEventListeners) { listener.onPowerChange(powerEvent); } @@ -757,26 +932,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); @@ -784,11 +951,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); @@ -796,11 +959,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); @@ -808,178 +967,265 @@ private void fireAllLocomotiveSpeedEventListeners(final LocomotiveSpeedEvent spe } } - private void notifyLocomotiveSpeedEventListeners(final LocomotiveSpeedEvent locomotiveEvent) { - executor.execute(() -> fireAllLocomotiveSpeedEventListeners(locomotiveEvent)); - } - - private class CanFeedbackMessageListener implements FeedbackListener { + /** + * Handle Event Message, which are unsolicited messages from the CS. + */ + private class EventMessageHandler extends Thread { - private final MarklinCentralStationImpl controller; + @SuppressWarnings("FieldMayBeFinal") + private boolean stop = false; + private boolean quit = true; - CanFeedbackMessageListener(MarklinCentralStationImpl controller) { - this.controller = controller; - } + private final TransferQueue eventMessageQueue; - @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); - } - } - } - } + public EventMessageHandler(CSConnection csConnection) { + eventMessageQueue = csConnection.getEventQueue(); } - } - - private class CanPingMessageListener implements CanPingListener { - private final MarklinCentralStationImpl controller; - - CanPingMessageListener(MarklinCentralStationImpl controller) { - this.controller = controller; + void quit() { + this.quit = true; } - @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 isRunning() { + return !this.quit; } - @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); - } - } - } + boolean isFinished() { + return this.stop; } @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 (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); +// 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); + } + } + case CanMessage.STATUS_CONFIG -> { + if (CanMessage.JCS_UID == uid && CanMessage.DLC_5 == dlc) { + Logger.trace("StatusConfig RQ: " + eventMessage); + //sentJCSInformationMessage(); + } + } + case CanMessage.STATUS_CONFIG_RESP -> { + Logger.trace("StatusConfigResponse RX: " + eventMessage); + //add to an list of resposne check - private class CanSystemMessageListener implements SystemListener { + } + 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) { + fireSensorEventListeners(sme); + } + } + } + case CanMessage.SX1_EVENT -> { + if (CanMessage.DLC_8 == dlc) { + SensorBean sb = FeedbackEventMessage.parse(eventMessage, new Date()); + SensorEvent sme = new SensorEvent(sb); + if (sme.getSensorBean() != null) { + fireSensorEventListeners(sme); + } + } + } + case CanMessage.SYSTEM_COMMAND -> { + //Logger.trace("SystemConfigCommand RX: " + eventMessage); + } + 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 -> { + //stop specific loc + LocomotiveSpeedEvent lse = LocomotiveEmergencyStopMessage.parse(eventMessage); + notifyLocomotiveSpeedEventListeners(lse); + } + case CanMessage.OVERLOAD_SUB_CMD -> { + PowerEvent gpe = PowerEventParser.parseMessage(eventMessage); + notifyPowerEventListeners(gpe); + } + } + } + case CanMessage.ACCESSORY_SWITCHING -> { + Logger.trace("AccessorySwitching RX: " + eventMessage); + } + case CanMessage.ACCESSORY_SWITCHING_RESP -> { + AccessoryEvent ae = AccessoryMessage.parse(eventMessage); + if (ae.isValid()) { + notifyAccessoryEventListeners(ae); + } + } + case CanMessage.LOC_VELOCITY -> { + Logger.trace("VelocityChange# " + eventMessage); - private final MarklinCentralStationImpl controller; + } + case CanMessage.LOC_VELOCITY_RESP -> { + Logger.trace("VelocityChange " + eventMessage); - CanSystemMessageListener(MarklinCentralStationImpl controller) { - this.controller = controller; - } + notifyLocomotiveSpeedEventListeners(LocomotiveVelocityMessage.parse(eventMessage)); + } + case CanMessage.LOC_DIRECTION -> { + Logger.trace("DirectionChange# " + eventMessage); - @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_DIRECTION_RESP -> { + Logger.trace("DirectionChange " + eventMessage); + notifyLocomotiveDirectionEventListeners(LocomotiveDirectionEventParser.parseMessage(eventMessage)); } - case CanMessage.HALT_SUB_CMD -> { - PowerEvent gpe = PowerEventParser.parseMessage(message); - controller.notifyPowerEventListeners(gpe); + case CanMessage.LOC_FUNCTION -> { + } - case CanMessage.LOC_STOP_SUB_CMD -> { - PowerEvent gpe = PowerEventParser.parseMessage(message); - controller.notifyPowerEventListeners(gpe); + case CanMessage.LOC_FUNCTION_RESP -> { + notifyLocomotiveFunctionEventListeners(LocomotiveFunctionEventParser.parseMessage(eventMessage)); } - case CanMessage.OVERLOAD_SUB_CMD -> { - PowerEvent gpe = PowerEventParser.parseMessage(message); - controller.notifyPowerEventListeners(gpe); + case CanMessage.BOOTLOADER_CAN -> { + //Update the last time millis. Used for the watchdog timer. + canBootLoaderLastCallMillis = System.currentTimeMillis(); } default -> { } } + + } catch (InterruptedException ex) { + Logger.error(ex); } } + + Logger.debug("Stop Event handling"); } } - private class CanAccessoryMessageListener implements AccessoryListener { + private void startWatchdog() { + long checkInterval = Long.parseLong(System.getProperty("connection.watchdog.interval", "10")); + checkInterval = checkInterval * 1000; - private final MarklinCentralStationImpl controller; + 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"); + } + } - CanAccessoryMessageListener(MarklinCentralStationImpl controller) { - this.controller = controller; + 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 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); + 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!"); + ConnectionEvent de = new ConnectionEvent("Marklin Central Station", false); + commandStation.onConnectionChange(de); + } + } else { + //Try to reconnect + if (!virtual && "true".equalsIgnoreCase(System.getProperty("controller.autoconnect", "true"))) { + boolean con = commandStation.connect(); + if (con) { + ConnectionEvent de = new ConnectionEvent("Marklin Central Station", true); + commandStation.onConnectionChange(de); } } } } } - private class CanLocomotiveMessageListener implements LocomotiveListener { + 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("MeasurementsTimer"); + measurementTimer.schedule(measurementTask, 10, measureInterval); + Logger.debug("Started Measurements Timer with an interval of " + measureInterval + "ms"); + } else { + Logger.debug("Skipping Measurements Timer"); + } + } + + private class MeasurementTask extends TimerTask { - private final MarklinCentralStationImpl controller; + private final MarklinCentralStationImpl commandStation; - CanLocomotiveMessageListener(MarklinCentralStationImpl controller) { - this.controller = controller; + MeasurementTask(MarklinCentralStationImpl commandStation) { + this.commandStation = commandStation; } @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)); + public void run() { + if (commandStation.isConnected() && !virtual) { + if (commandStation.isSupportTrackMeasurements()) { + commandStation.performMeasurements(); + } else { + Logger.debug("Track Measurement are not supported. Cancelling the Measurements schedule..."); + measurementTimer.cancel(); + } } } } -//////////// For Testing only.....////// + //////////// For Testing only.....////// + /// @param a + /// public static void main(String[] a) { RunUtil.loadExternalProperties(); @@ -999,26 +1245,45 @@ public static void main(String[] a) { csb.setProtocols("DCC,MFX,MM"); csb.setDefault(true); csb.setEnabled(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")); +// 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); + List feedbackModules = cs.getFeedbackModules(); + Logger.trace("There are " + feedbackModules + " Feedback Modules"); + 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()); + } //cs.getLocomotivesViaCAN(); //cs.getAccessoriesViaCan(); - //cs3.pause(2000); + //cs.pause(2000); + //cs.getMembers(); + //cs.memberPing(); //Logger.trace("getStatusDataConfig CS3"); - //cs3.getStatusDataConfigCS3(); - //cs3.pause(2000); + //cs.getStatusDataConfigCS3(); + //cs.pause(2000); //Logger.trace("getStatusDataConfig"); //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(); @@ -1029,63 +1294,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()) { - 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); -// -// 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(); @@ -1102,11 +1311,12 @@ public static void main(String[] a) { // for (LocomotiveBean loc : locs) { // Logger.trace(loc); // } + //cs.pause(40000); 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 6566133e..b70d8898 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; @@ -92,10 +91,32 @@ 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]; + } + public static final byte[] to2Bytes(int value) { byte[] bts = new byte[]{ (byte) ((value >> 8) & 0xFF), @@ -274,44 +295,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; @@ -392,9 +375,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; } @@ -408,7 +391,7 @@ public boolean isResponseComplete() { @Override public String toString() { - return ByteUtil.toHexString(this.getMessage()); + return ByteUtil.toHexString(getMessage()); } public int getNumberOfMeasurementValues() { @@ -468,6 +451,43 @@ 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 + * @return + */ + 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 +526,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 +629,4 @@ public boolean equals(Object obj) { // return "Unknown: " + cmd; // } // } +} 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..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; } @@ -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; @@ -402,6 +421,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()); @@ -415,15 +460,14 @@ 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)); + 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/MarklinCan.java b/src/main/java/jcs/commandStation/marklin/cs/can/MarklinCan.java index 0a668163..7ceaec50 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; @@ -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/device/CanDevice.java b/src/main/java/jcs/commandStation/marklin/cs/can/device/CanDevice.java new file mode 100644 index 00000000..5b358d8c --- /dev/null +++ b/src/main/java/jcs/commandStation/marklin/cs/can/device/CanDevice.java @@ -0,0 +1,326 @@ +/* + * 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.HashMap; +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
+ * Example devices are:
+ * - Central Station self
+ * - GFP (Gleis Format Prozessor)
+ * - Link S88
+ */ +public class CanDevice { + + private String uid; + private String guiUid; + private String version; + private String hwVersion; + private String identifier; + private Integer measureChannelCount; + private Integer configChannelCount; + 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<>(); + } + + 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 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(); + } + return name; + } + + 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; + } + + 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); + } + + 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 void setSerial(Integer serial) { + this.serial = serial.toString(); + } + + 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; + } + + public String getHwVersion() { + return hwVersion; + } + + public void setHwVersion(String HwVersion) { + this.hwVersion = HwVersion; + } + + 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 List getMeasuringChannels() { + return new ArrayList<>(measuringChannels.values()); + } + + public void addConfigChannel(ConfigChannel configChannel) { + configChannels.put(configChannel.getNumber(), configChannel); + } + + public ConfigChannel getConfigChannel(Integer number) { + return configChannels.get(number); + } + + public List getConfigChannels() { + return new ArrayList<>(configChannels.values()); + } + + @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); + } else if (getName() != null) { + sb.append(", derivedname=").append(getName()); + } + 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); + } + 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(); + } + + @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.hwVersion); + 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.hwVersion, other.hwVersion)) { + 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..c2ddf901 --- /dev/null +++ b/src/main/java/jcs/commandStation/marklin/cs/can/device/MeasuringChannel.java @@ -0,0 +1,329 @@ +/* + * 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; + +/** + * Represents a Measurement Channel in the Marklin Central Station + */ +public class MeasuringChannel { + + 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/AccessoryMessage.java b/src/main/java/jcs/commandStation/marklin/cs/can/parser/AccessoryMessage.java new file mode 100644 index 00000000..210b664e --- /dev/null +++ b/src/main/java/jcs/commandStation/marklin/cs/can/parser/AccessoryMessage.java @@ -0,0 +1,80 @@ +/* + * 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.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 AccessoryMessage { + + private AccessoryMessage() { + + } + + public static AccessoryEvent parse(CanMessage message) { + if(message == null) { + return null; + } + CanMessage msg; + if (!message.isResponseMessage()) { + msg = message.getResponse(); + } else { + msg = message; + } + + int cmd = msg.getCommand(); + int dlc = msg.getDlc(); + byte[] data = msg.getData(); + + if (CanMessage.ACCESSORY_SWITCHING_RESP == cmd || CanMessage.ACCESSORY_SWITCHING == cmd) { + byte[] addressData = new byte[]{data[2], data[3]}; + int address = CanMessage.toInt(addressData); + String protocol; + //CS is zero based + 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, 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); + } else { + 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/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/cs2/SensorMessageParser.java b/src/main/java/jcs/commandStation/marklin/cs/can/parser/FeedbackEventMessage.java similarity index 63% 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..f8938fe6 100644 --- a/src/main/java/jcs/commandStation/marklin/cs2/SensorMessageParser.java +++ b/src/main/java/jcs/commandStation/marklin/cs/can/parser/FeedbackEventMessage.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 java.util.Date; import jcs.commandStation.marklin.cs.can.CanMessage; @@ -23,11 +23,13 @@ /** * - * @author Frans Jacobs + * Parse Sensor messages */ -public class SensorMessageParser { +public class FeedbackEventMessage { - public static SensorBean parseMessage(CanMessage message, Date eventDate) { + private static final String MARKLIN_CS = "marklin.cs"; + + public static SensorBean parse(CanMessage message, Date eventDate) { CanMessage resp; if (!message.isResponseMessage()) { resp = message.getResponse(); @@ -38,18 +40,32 @@ public static SensorBean parseMessage(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; - SensorBean sensorBean = new SensorBean(deviceId, contactId, status, previousStatus, millis, eventDate); + + //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); return null; } } + } 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/cs2/LocomotiveSpeedEventParser.java b/src/main/java/jcs/commandStation/marklin/cs/can/parser/LocomotiveVelocityMessage.java similarity index 64% 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..9f727a42 100644 --- a/src/main/java/jcs/commandStation/marklin/cs2/LocomotiveSpeedEventParser.java +++ b/src/main/java/jcs/commandStation/marklin/cs/can/parser/LocomotiveVelocityMessage.java @@ -13,9 +13,9 @@ * 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.events.LocomotiveSpeedEvent; import jcs.commandStation.marklin.cs.can.CanMessage; import jcs.entities.LocomotiveBean; import org.tinylog.Logger; @@ -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/cs/can/parser/SystemStatus.java b/src/main/java/jcs/commandStation/marklin/cs/can/parser/SystemStatus.java index a255d97d..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 @@ -15,69 +15,29 @@ */ 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) { + int powerVal = cm.getData()[4]; + return powerVal == 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/CSConnection.java b/src/main/java/jcs/commandStation/marklin/cs/net/CSConnection.java index c49d47d5..2048f354 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.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; +import jcs.commandStation.events.ConnectionEventListener; -/** - * - * @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(ConnectionEventListener listener); + + } 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..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; @@ -36,107 +36,147 @@ 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 */ public class CSConnectionFactory { private static final String MARKLIN_CS_SERVICE = "_workstation._tcp"; + private static final String BROADCAST_ADDRESS = "255.255.255.255"; - private static CSConnectionFactory instance; - - private CSConnection controllerConnection; - private HTTPConnection httpConnection; - private InetAddress controllerHost; + private static InetAddress controllerHost; + private static boolean forceVirtual = false; + private static boolean virtual; - private static final String BROADCAST_ADDRESS = "255.255.255.255"; + private static CSConnection controllerConnection; + private static CSHTTPConnection httpConnection; - private static final String LAST_USED_IP_PROP_FILE = RunUtil.DEFAULT_PATH + "last-used-marklin-cs-ip.properties"; + static { + forceVirtual = "true".equals(System.getProperty("connection.always.virtual", "false")); + } - private CSConnectionFactory() { + public static CSConnection getConnection(CommandStationBean commandStation) { + return getConnection(commandStation, (virtual != commandStation.isVirtual())); } - public static CSConnectionFactory getInstance() { - if (instance == null) { - instance = new CSConnectionFactory(); + public static CSConnection getConnection(CommandStationBean commandStation, boolean reconnect) { + if (reconnect) { + disconnectAll(); } - return instance; - } - CSConnection getConnectionImpl() { - if (controllerConnection == null) { + virtual = commandStation.isVirtual(); + if (!virtual && forceVirtual) { + virtual = forceVirtual; + Logger.info("Forcing a virtual connection!"); + } - 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 CS IP: " + lastUsedIp + " is invalid!"); - lastUsedIp = null; - } + try { + if (virtual) { + controllerHost = InetAddress.getLocalHost(); + } else { + controllerHost = InetAddress.getByName(commandStation.getIpAddress()); } + } catch (UnknownHostException ex) { + Logger.error("Invalid ip address : " + commandStation.getIpAddress()); + return null; + } - if (this.controllerHost == null) { - Logger.trace("Try to discover a Marklin CS..."); - JCS.logProgress("Discovering a Marklin Central Station..."); - sendMobileAppPing(); + if (controllerConnection == null) { + if (virtual) { + controllerConnection = new CSVirtualConnection(controllerHost); + } else { + controllerConnection = new CSTCPConnection(controllerHost); } + } - 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()); + return controllerConnection; + } - controllerConnection = new TCPConnection(controllerHost); + public static CSHTTPConnection getHTTPConnection() { + if (httpConnection == null) { + if (virtual) { + httpConnection = new CSHTTPConnectionVirt(controllerHost); } else { - Logger.warn("Can't find a Marklin Controller host!"); - JCS.logProgress("Can't find a Marklin Central Station on the Network"); + httpConnection = new CSHTTPConnectionImpl(controllerHost); } } - return this.controllerConnection; - } - - public static CSConnection getConnection() { - return getInstance().getConnectionImpl(); + 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; } - HTTPConnection getHTTPConnectionImpl() { - if (controllerConnection == null) { - getConnectionImpl(); - } - if (httpConnection == null) { - httpConnection = new HTTPConnection(controllerHost); + public static String getControllerIp() { + if (controllerHost != null) { + return controllerHost.getHostAddress(); + } else { + return "Unknown"; } - return httpConnection; } - public static HTTPConnection getHTTPConnection() { - return getInstance().getHTTPConnectionImpl(); + /** + * 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; } - 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 discoverCsUsingMobileAppPing() { + InetAddress csIp = null; try { InetAddress localAddress; if (RunUtil.isLinux()) { @@ -168,9 +208,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,57 +219,6 @@ void sendMobileAppPing() { } catch (IOException ex) { Logger.error(ex); } - } - - String getControllerIpImpl() { - if (this.controllerHost != null) { - return this.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.
- * mDNS is used to discover the ECoS - * - * @return the IP Address of the ECoS 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/commandStation/marklin/cs/net/CSHTTPConnection.java b/src/main/java/jcs/commandStation/marklin/cs/net/CSHTTPConnection.java new file mode 100644 index 00000000..3a9bd622 --- /dev/null +++ b/src/main/java/jcs/commandStation/marklin/cs/net/CSHTTPConnection.java @@ -0,0 +1,48 @@ +/* + * 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; + +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); + + Image getFunctionImageCS2(String imageName); + +} diff --git a/src/main/java/jcs/commandStation/marklin/cs/net/HTTPConnection.java b/src/main/java/jcs/commandStation/marklin/cs/net/CSHTTPConnectionImpl.java similarity index 70% rename from src/main/java/jcs/commandStation/marklin/cs/net/HTTPConnection.java rename to src/main/java/jcs/commandStation/marklin/cs/net/CSHTTPConnectionImpl.java index 2e771de7..53e2d47c 100755 --- a/src/main/java/jcs/commandStation/marklin/cs/net/HTTPConnection.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; @@ -36,28 +33,28 @@ * * @author Frans Jacobs */ -public class HTTPConnection { - +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"; @@ -67,29 +64,32 @@ public class HTTPConnection { // http://cs3host/app/api/mags // http://cs3host/app/api/info // - HTTPConnection(InetAddress csAddress) { + 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); + 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; @@ -105,11 +105,12 @@ public String getLocomotivesFile() { } return locs.toString(); } - + + @Override 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; @@ -125,11 +126,12 @@ public String getLocomotivesJSON() { } return loks.toString(); } - + + @Override 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; @@ -145,11 +147,12 @@ public String getAccessoriesFile() { } return locs.toString(); } - + + @Override 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; @@ -165,11 +168,12 @@ public String getFunctionsSvgJSON() { } return json.toString(); } - + + @Override 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; @@ -185,11 +189,12 @@ public String getAccessoriesSvgJSON() { } return json.toString(); } - + + @Override 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; @@ -205,12 +210,13 @@ public String getAccessoriesJSON() { } 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); + URL url = URI.create(HTTP + csAddress.getHostAddress() + DEVICES).toURL(); URLConnection lc = url.openConnection(); try (BufferedReader in = new BufferedReader(new InputStreamReader(lc.getInputStream()))) { String inputLine; @@ -229,11 +235,12 @@ public String getDevicesJSON() { } return device.toString(); } - + + @Override 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; @@ -249,12 +256,13 @@ public String getInfoFile() { } 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); + 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; @@ -273,17 +281,18 @@ public String getInfoJSON() { } 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")); + 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); image = ImageIO.read(url); } catch (MalformedURLException ex) { @@ -293,13 +302,14 @@ public Image getLocomotiveImage(String imageName) { } 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); + URL url = URI.create(iurl).toURL(); image = ImageIO.read(url); } catch (IIOException iio) { //Image not avalable @@ -311,65 +321,9 @@ public Image getFunctionImageCS2(String imageName) { } 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"); - } - HTTPConnection hc = new HTTPConnection(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); - + @Override + public void close() throws Exception { } + } 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..e18a0080 --- /dev/null +++ b/src/main/java/jcs/commandStation/marklin/cs/net/CSHTTPConnectionVirt.java @@ -0,0 +1,591 @@ +/* + * 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.URI; +import java.net.URL; +import java.net.URLConnection; +import java.net.UnknownHostException; +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() throws UnknownHostException { + this(InetAddress.getLocalHost()); + } + + 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 = URI.create(HTTP + csAddress.getHostAddress() + CONFIG + LOCOMOTIVE).toURL(); + 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 = URI.create(HTTP + csAddress.getHostAddress() + LOCOMOTIVE_JSON).toURL(); + 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 = URI.create(HTTP + csAddress.getHostAddress() + CONFIG + MAGNETARTIKEL).toURL(); + 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 = URI.create(HTTP + csAddress.getHostAddress() + FUNCTION_SVG_URL).toURL(); + 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 = URI.create(HTTP + csAddress.getHostAddress() + ACCESSORIES_SVG_URL).toURL(); + 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 = URI.create(HTTP + csAddress.getHostAddress() + ACCESSORIES_URL).toURL(); + 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\": \"224\","); + 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 = URI.create(fixURL(HTTP + csAddress.getHostAddress() + IMAGE_FOLDER_CS3 + imageName + ".png")).toURL(); + } else { + url = URI.create(fixURL(HTTP + csAddress.getHostAddress() + IMAGE_FOLDER_CS2 + imageName + ".png")).toURL(); + } + + 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 = URI.create(iurl).toURL(); + 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 new file mode 100755 index 00000000..41bcda64 --- /dev/null +++ b/src/main/java/jcs/commandStation/marklin/cs/net/CSTCPConnection.java @@ -0,0 +1,338 @@ +/* + * 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.io.BufferedInputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +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.ConnectionEvent; +import jcs.commandStation.marklin.cs.can.CanMessage; +import org.tinylog.Logger; +import jcs.commandStation.events.ConnectionEventListener; + +/** + * + * @author Frans Jacobs + */ +class CSTCPConnection implements CSConnection { + + private final InetAddress centralStationAddress; + + private Socket clientSocket; + 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 eventQueue; + + CSTCPConnection(InetAddress csAddress) { + centralStationAddress = csAddress; + debug = System.getProperty("message.debug", "false").equalsIgnoreCase("true"); + eventQueue = new LinkedTransferQueue<>(); + disconnectionEventListeners = new ArrayList<>(); + checkConnection(); + } + + private void checkConnection() { + try { + if (clientSocket == null || !clientSocket.isConnected()) { + clientSocket = new Socket(centralStationAddress, CSConnection.CS_RX_PORT); + clientSocket.setKeepAlive(true); + clientSocket.setTcpNoDelay(true); + dos = new DataOutputStream(clientSocket.getOutputStream()); + + messageReceiver = new ClientMessageReceiver(clientSocket); + messageReceiver.setDaemon(true); + messageReceiver.start(); + } + } catch (IOException ex) { + this.clientSocket = null; + Logger.error("Can't (re)connect with Central Station " + centralStationAddress.getHostAddress() + ". Cause: " + ex.getMessage()); + Logger.trace(ex); + } + } + + @Override + public TransferQueue getEventQueue() { + return this.eventQueue; + } + + @Override + public void addDisconnectionEventListener(ConnectionEventListener listener) { + this.disconnectionEventListeners.add(listener); + } + + private void disconnect() { + messageReceiver.quit(); + if (dos != null) { + try { + dos.close(); + } catch (IOException ex) { + Logger.error("Can't close output stream. Cause: " + ex.getMessage()); + Logger.trace(ex); + } + } + + disconnectionEventListeners.clear(); + if (clientSocket != null) { + try { + clientSocket.close(); + } catch (IOException ex) { + Logger.error("Can't close socket. Cause: " + ex.getMessage()); + Logger.trace(ex); + } + } + } + + private class ResponseCallback { + + private final CanMessage tx; + private boolean done = false; + + ResponseCallback(final CanMessage tx) { + this.tx = tx; + } + + public boolean isSubscribedfor(int command) { + int txCmd = this.tx.getCommand(); + if (CanMessage.REQUEST_CONFIG_DATA == txCmd) { + //Special case so valid are +1 and +2 + return txCmd == (command - 1) || txCmd == (command - 2); + } else { + return txCmd == (command - 1); + } + } + + public void addResponse(CanMessage rx, int moreAvailable) { + this.tx.addResponse(rx); + this.done = moreAvailable == 0; + } + + public boolean isResponseComplete() { + //Most of the messages will have just one response but there are some which have more + return tx.isResponseComplete() && this.done; + } + } + + @Override + public synchronized CanMessage sendCanMessage(CanMessage message) { + if (message == null) { + Logger.warn("Message is NULL?"); + return null; + } + + ResponseCallback callback = null; + + if (message.expectsResponse() || message.expectsLongResponse()) { + //Message is expecting response so lets register for response + callback = new ResponseCallback(message); + messageReceiver.registerResponseCallback(callback); + } + + try { + byte[] bytes = message.getMessage(); + //Send the message + dos.write(bytes); + dos.flush(); + } catch (IOException ex) { + Logger.error(ex.getMessage()); + } + + 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; + + 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(); + + //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(); + 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"); + } + } + + //Remove the callback + messageReceiver.unRegisterResponseCallback(); + } + + //Capture messages for now to be able to develop the virtual mode + Logger.trace("#TX: " + message + (message.isResponseMessage() ? " response msg" : "")); + 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; + } + + @Override + public void close() throws Exception { + disconnect(); + } + + @Override + public InetAddress getControllerAddress() { + return centralStationAddress; + } + + @Override + public boolean isConnected() { + return messageReceiver != null && messageReceiver.isRunning(); + } + + private void pause10Millis() { + try { + Thread.sleep(10); + } catch (InterruptedException ex) { + } + } + + private class ClientMessageReceiver extends Thread { + + private boolean quit = true; + private DataInputStream din; + + private ResponseCallback callBack; + + public ClientMessageReceiver(Socket socket) { + try { + BufferedInputStream bis = new BufferedInputStream(socket.getInputStream()); + din = new DataInputStream(bis); + } catch (IOException ex) { + Logger.error(ex); + } + } + + void registerResponseCallback(ResponseCallback callBack) { + this.callBack = callBack; + } + + void unRegisterResponseCallback() { + callBack = null; + } + + synchronized void quit() { + quit = true; + } + + synchronized boolean isRunning() { + return !quit; + } + + @Override + public void run() { + Thread.currentThread().setName("CS-CAN-RX"); + + quit = false; + Logger.trace("Started listening on port " + clientSocket.getLocalPort() + "..."); + + while (isRunning()) { + try { + int prio = din.readUnsignedByte(); + int cmd = din.readUnsignedByte(); + int hash = din.readUnsignedShort(); + int dlc = din.readUnsignedByte(); + //read the data + int dataIdx = 0; + byte[] data = new byte[CanMessage.DATA_SIZE]; + while (dataIdx < CanMessage.DATA_SIZE) { + data[dataIdx] = din.readByte(); + dataIdx++; + } + CanMessage rx = new CanMessage(prio, cmd, hash, dlc, data); + + //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()); + } + + } catch (SocketException se) { + if (!quit) { + String msg = "Host " + centralStationAddress.getHostName(); + ConnectionEvent de = new ConnectionEvent(msg, false); + for (ConnectionEventListener listener : disconnectionEventListeners) { + listener.onConnectionChange(de); + } + } + + quit(); + } catch (IOException ex) { + Logger.error(ex); + } + } + + Logger.debug("Stop receiving"); + try { + din.close(); + } catch (IOException ex) { + Logger.error(ex); + } + } + } +} 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..4802eb57 --- /dev/null +++ b/src/main/java/jcs/commandStation/marklin/cs/net/CSVirtualConnection.java @@ -0,0 +1,304 @@ +/* + * 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.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 + */ +class CSVirtualConnection implements CSConnection, VirtualConnection { + + final static int LINK_S88_UID = 1396202561; + + 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) { + 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() { + periodicMessageSender = new PeriodicCSMessageSender(); + periodicMessageSender.start(); + //periodicMessageSender.setDaemon(true); + } + + @Override + public TransferQueue getEventQueue() { + return this.eventQueue; + } + + @Override + public void addDisconnectionEventListener(ConnectionEventListener 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); +// } +// } + +//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 -> { + } + case CanMessage.ACCESSORY_SWITCHING -> { + 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)); + } + 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(); + 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/cs/net/TCPConnection.java b/src/main/java/jcs/commandStation/marklin/cs/net/TCPConnection.java deleted file mode 100755 index 9a3a8a0c..00000000 --- a/src/main/java/jcs/commandStation/marklin/cs/net/TCPConnection.java +++ /dev/null @@ -1,399 +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.net; - -import java.io.BufferedInputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.net.InetAddress; -import java.net.Socket; -import java.net.SocketException; -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; - -/** - * - * @author Frans Jacobs - */ -class TCPConnection implements CSConnection { - - private final InetAddress centralStationAddress; - - private Socket clientSocket; - private DataOutputStream dos; - - private ClientMessageReceiver messageReceiver; - - private static final long SHORT_TIMEOUT = 1000L; - private static final long LONG_TIMEOUT = 5000L; - - private boolean debug = false; - - TCPConnection(InetAddress csAddress) { - centralStationAddress = csAddress; - debug = System.getProperty("message.debug", "false").equalsIgnoreCase("true"); - checkConnection(); - } - - private void checkConnection() { - try { - if (clientSocket == null || !clientSocket.isConnected()) { - clientSocket = new Socket(centralStationAddress, CSConnection.CS_RX_PORT); - clientSocket.setKeepAlive(true); - clientSocket.setTcpNoDelay(true); - dos = new DataOutputStream(clientSocket.getOutputStream()); - - messageReceiver = new ClientMessageReceiver(clientSocket); - messageReceiver.setDaemon(true); - messageReceiver.start(); - } - } catch (IOException ex) { - this.clientSocket = null; - Logger.error("Can't (re)connect with Central Station " + centralStationAddress.getHostAddress() + ". Cause: " + ex.getMessage()); - Logger.trace(ex); - } - } - - private void disconnect() { - this.messageReceiver.quit(); - if (dos != null) { - try { - dos.close(); - } catch (IOException ex) { - Logger.error("Can't close output stream. Cause: " + ex.getMessage()); - Logger.trace(ex); - } - } - if (clientSocket != null) { - try { - clientSocket.close(); - } catch (IOException ex) { - Logger.error("Can't close socket. Cause: " + ex.getMessage()); - Logger.trace(ex); - } - } - } - - private class ResponseCallback { - - private final CanMessage tx; - private boolean done = false; - - ResponseCallback(final CanMessage tx) { - this.tx = tx; - } - - public boolean isSubscribedfor(int command) { - int txCmd = this.tx.getCommand(); - if (CanMessage.REQUEST_CONFIG_DATA == txCmd) { - //Special case so valid are +1 and +2 - return txCmd == (command - 1) || txCmd == (command - 2); - } else { - return txCmd == (command - 1); - } - } - - public void addResponse(CanMessage rx, int moreAvailable) { - this.tx.addResponse(rx); - this.done = moreAvailable == 0; - } - - public boolean isResponseComplete() { - //Most of the messages will have just one response but there are some which have more - return tx.isResponseComplete() && this.done; - } - } - - @Override - 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); - } - - 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); - } - } - - 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 (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"); - } - } - - //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); - } - } - - @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); - } - } - - @Override - public void close() throws Exception { - disconnect(); - } - - @Override - public InetAddress getControllerAddress() { - return centralStationAddress; - } - - @Override - public boolean isConnected() { - return this.messageReceiver != null && this.messageReceiver.isRunning(); - } - - 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) { - try { - BufferedInputStream bis = new BufferedInputStream(socket.getInputStream()); - din = new DataInputStream(bis); - } catch (IOException ex) { - Logger.error(ex); - } - } - - void registerResponseCallback(ResponseCallback callBack) { - this.callBack = 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; - } - - synchronized void quit() { - this.quit = true; - } - - synchronized boolean isRunning() { - return !this.quit; - } - - @Override - public void run() { - Thread.currentThread().setName("CAN-RX"); - - this.quit = false; - Logger.trace("Started listening on port " + clientSocket.getLocalPort() + "..."); - - while (isRunning()) { - try { - int prio = din.readUnsignedByte(); - int cmd = din.readUnsignedByte(); - int hash = din.readUnsignedShort(); - int dlc = din.readUnsignedByte(); - //read the data - int dataIdx = 0; - byte[] data = new byte[CanMessage.DATA_SIZE]; - while (dataIdx < CanMessage.DATA_SIZE) { - data[dataIdx] = din.readByte(); - dataIdx++; - } - CanMessage rx = new CanMessage(prio, cmd, hash, dlc, data); - - //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); - } - } - } - } catch (SocketException se) { - quit(); - } catch (IOException ioe) { - Logger.error(ioe); - } - } - - Logger.debug("Stop receiving"); - try { - din.close(); - } catch (IOException ex) { - Logger.error(ex); - } - } - } - -// 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; -// } -// -// TCPConnection c = new TCPConnection(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/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/cs2/AccessoryEventParser.java b/src/main/java/jcs/commandStation/marklin/cs2/AccessoryEventParser.java deleted file mode 100644 index ead78225..00000000 --- a/src/main/java/jcs/commandStation/marklin/cs2/AccessoryEventParser.java +++ /dev/null @@ -1,54 +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.commandStation.marklin.cs2; - -import jcs.commandStation.events.AccessoryEvent; -import jcs.commandStation.marklin.cs.can.CanMessage; -import jcs.entities.AccessoryBean; -import org.tinylog.Logger; - -public class AccessoryEventParser { - - public static AccessoryEvent parseMessage(CanMessage message) { - CanMessage resp; - if (!message.isResponseMessage()) { - resp = message.getResponse(); - } else { - resp = message; - } - - if (resp.isResponseMessage() && CanMessage.ACCESSORY_SWITCHING_RESP == resp.getCommand()) { - byte[] data = resp.getData(); - int address = data[3]; - int position = data[4]; - //CS is zero based - address = address + 1; - String id = address + ""; - - AccessoryBean accessoryBean = new AccessoryBean(id, address, null, null, position, null, null, null, CanMessage.MARKLIN_COMMANDSTATION_ID); - if (resp.getDlc() == CanMessage.DLC_8) { - 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); - return null; - } - } - -} 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 c5c34816..00000000 --- a/src/main/java/jcs/commandStation/marklin/cs2/ChannelDataParser.java +++ /dev/null @@ -1,199 +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(); - - 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); - - //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/LocomotiveBeanParser.java b/src/main/java/jcs/commandStation/marklin/cs2/LocomotiveBeanParser.java index 89f5d049..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; @@ -269,18 +265,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/marklin/cs3/DeviceJSONParser.java b/src/main/java/jcs/commandStation/marklin/cs3/DeviceJSONParser.java deleted file mode 100644 index 5b85c61d..00000000 --- a/src/main/java/jcs/commandStation/marklin/cs3/DeviceJSONParser.java +++ /dev/null @@ -1,77 +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.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; - -/** - * - * @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"); - - String devicesFile = Files.readString(path); - - List devices = DeviceJSONParser.parse(devicesFile); - -// for (DeviceBean dev : devices) { -// Logger.trace(dev); -// } - - 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/commandStation/marklin/parser/CanDeviceJSONParser.java b/src/main/java/jcs/commandStation/marklin/parser/CanDeviceJSONParser.java new file mode 100644 index 00000000..10704670 --- /dev/null +++ b/src/main/java/jcs/commandStation/marklin/parser/CanDeviceJSONParser.java @@ -0,0 +1,147 @@ +/* + * 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")); + + //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")); + + 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/parser/CanDeviceParser.java b/src/main/java/jcs/commandStation/marklin/parser/CanDeviceParser.java new file mode 100644 index 00000000..0053a204 --- /dev/null +++ b/src/main/java/jcs/commandStation/marklin/parser/CanDeviceParser.java @@ -0,0 +1,433 @@ +/* + * 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.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 CanDeviceParser { + + public static List parse(CanMessage memberPingmessage) { + List devices = new ArrayList<>(); + 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; + } + + 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); + + 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); + } + } + 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/main/java/jcs/commandStation/marklin/cs2/InfoBeanParser.java b/src/main/java/jcs/commandStation/marklin/parser/GeraetParser.java similarity index 58% rename from src/main/java/jcs/commandStation/marklin/cs2/InfoBeanParser.java rename to src/main/java/jcs/commandStation/marklin/parser/GeraetParser.java index 16f61e39..1af28f9f 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; } + + CanDevice gfp = new CanDevice(); + //InfoBean ib = new InfoBean(); + //ib.copyInto(commandStationBean); - InfoBean ib = new InfoBean(); - - String[] lines = file.split("\n"); + String[] lines = geraetFile.split("\n"); String minor = ""; String major = ""; for (String line : lines) { @@ -40,10 +50,10 @@ public static InfoBean parseFile(String file) { } String key = line.substring(0, eqidx).trim(); String value = line.substring(eqidx).replace("=", "").trim(); - + switch (key) { case "[geraet]" -> { - + } case ".major" -> { major = value; @@ -52,57 +62,65 @@ 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); + gfp.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() != null & 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.setShortName(shortName); + + 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; } - + InfoBean ib = new InfoBean(); - + JSONObject infoObject = new JSONObject(json); ib.setSoftwareVersion(infoObject.optString("softwareVersion")); ib.setHardwareVersion(infoObject.optString("hardwareVersion")); @@ -112,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/marklin/parser/SystemStatusMessage.java b/src/main/java/jcs/commandStation/marklin/parser/SystemStatusMessage.java new file mode 100644 index 00000000..16746441 --- /dev/null +++ b/src/main/java/jcs/commandStation/marklin/parser/SystemStatusMessage.java @@ -0,0 +1,108 @@ +/* + * 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) { + return parse(channel, systemStatusmessage, System.currentTimeMillis()); + } + + 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) { + 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(), measurementMillis, 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 7dedcfc9..56adfb87 100644 --- a/src/main/java/jcs/commandStation/virtual/VirtualCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/virtual/VirtualCommandStationImpl.java @@ -19,13 +19,13 @@ import java.awt.Image; import java.util.ArrayList; import java.util.List; -import java.util.Map; import jcs.JCS; import jcs.commandStation.AbstractController; import jcs.commandStation.AccessoryController; 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; @@ -39,14 +39,11 @@ import jcs.commandStation.events.SensorEvent; import jcs.commandStation.events.SensorEventListener; 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.FeedbackModule; import jcs.commandStation.entities.InfoBean; import jcs.entities.LocomotiveBean; import jcs.util.NetworkUtil; -import jcs.util.VersionInfo; import org.tinylog.Logger; /** @@ -55,7 +52,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; @@ -82,18 +80,17 @@ 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.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); @@ -104,7 +101,7 @@ public synchronized boolean connect() { public void disconnect() { this.connected = false; this.infoBean = null; - this.mainDevice = null; + //this.mainDevice = null; } @Override @@ -118,19 +115,12 @@ public InfoBean getCommandStationInfo() { } @Override - public DeviceBean getDevice() { - return this.mainDevice; - } - - @Override - public List getDevices() { - List devices = new ArrayList<>(); - if (mainDevice != null) { - devices.add(this.mainDevice); - } + public List getDevices() { + List devices = new ArrayList<>(); + return devices; } - + @Override public String getIp() { return NetworkUtil.getIPv4HostAddress().getHostAddress(); @@ -261,25 +251,11 @@ public boolean isSupportTrackMeasurements() { } @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) { + 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) { @@ -291,7 +267,9 @@ public void switchAccessory(Integer address, AccessoryBean.AccessoryValue value, 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!"); @@ -302,6 +280,7 @@ 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.getIdString()); } } @@ -311,12 +290,7 @@ public List getAccessories() { } @Override - public DeviceBean getFeedbackDevice() { - throw new UnsupportedOperationException("Not supported yet."); - } - - @Override - public List getFeedbackModules() { + public List getFeedbackModules() { throw new UnsupportedOperationException("Not supported yet."); } 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/CommandStationBean.java b/src/main/java/jcs/entities/CommandStationBean.java index bee8946d..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() { @@ -116,7 +120,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/entities/FeedbackModuleBean.java b/src/main/java/jcs/entities/FeedbackModuleBean.java deleted file mode 100644 index af710dd7..00000000 --- a/src/main/java/jcs/entities/FeedbackModuleBean.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright 2024 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 java.util.ArrayList; -import java.util.List; -import jcs.commandStation.events.SensorEvent; - -/** - * Represents 1 Feedback Module (S88) with a number of ports (usually 16) - */ -public class FeedbackModuleBean { - - private Integer id; - private Integer moduleNumber; - private Integer portCount; - private Integer addressOffset; - private Integer identifier; - - private int[] ports; - private int[] prevPorts; - - public static int DEFAULT_PORT_COUNT = 16; - - public FeedbackModuleBean() { - } - - public Integer getId() { - return id; - } - - public void setId(Integer id) { - this.id = id; - } - - public Integer getModuleNumber() { - return moduleNumber; - } - - public void setModuleNumber(Integer moduleNumber) { - this.moduleNumber = moduleNumber; - } - - public Integer getPortCount() { - return portCount; - } - - 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]; - } - } - } - } - - public Integer getAddressOffset() { - return addressOffset; - } - - public void setAddressOffset(Integer addressOffset) { - this.addressOffset = addressOffset; - } - - public Integer getIdentifier() { - return identifier; - } - - public void setIdentifier(Integer identifier) { - this.identifier = identifier; - } - - public int[] getPorts() { - return ports; - } - - public void setPorts(int[] ports) { - this.ports = 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; - } - - public int getAccumulatedPortsValue() { - int val = 0; - for (int i = 0; i < ports.length; i++) { - int portVal = 0; - if (ports[i] == 1) { - portVal = (int) Math.pow(2, i); - } - val = val + portVal; - } - return val; - } - - public int[] getPrevPorts() { - return prevPorts; - } - - public void setPrevPorts(int[] prevPorts) { - this.prevPorts = prevPorts; - } - - public SensorBean getSensor(int port) { - SensorBean sb = new SensorBean(id, port, ports[port]); - 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]); - SensorEvent se = new SensorEvent(sb); - changedSensors.add(se); - } - } - return changedSensors; - } - - public List getSensors() { - List sensors = 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]); - sensors.add(sb); - } - } - return sensors; - } - - public String portToString() { - StringBuilder sb = new StringBuilder(); - sb.append(" {"); - for (int i = 0; i < ports.length; i++) { - sb.append(i + 1); - sb.append("["); - sb.append(ports[i]); - sb.append("] "); - } - sb.append("}"); - return sb.toString(); - } - - @Override - public String toString() { - return "FeedbackModuleBean{" + "id=" + id + ", moduleNumber=" + moduleNumber + ", portCount=" + portCount + ", addressOffset=" + addressOffset + ", identifier=" + identifier + "}"; - } - -} 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/entities/SensorBean.java b/src/main/java/jcs/entities/SensorBean.java index 74a76cf2..a9d69ca8 100755 --- a/src/main/java/jcs/entities/SensorBean.java +++ b/src/main/java/jcs/entities/SensorBean.java @@ -21,83 +21,96 @@ 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; private Integer status; private Integer previousStatus; private Integer millis; - private Date lastUpdated; + private Long lastUpdated; + private Integer nodeId; + private String commandStationId; + private Integer busNr; public SensorBean() { - this(null, null, null, null, null, null, null, null); + this(null, null, null, null, null, null, null, 0); } - public SensorBean(Integer deviceId, Integer contactId, Integer status) { - this(null, null, deviceId, contactId, status, null, null, null); + 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 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, 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(String name, Integer deviceId, Integer contactId) { - this(null, name, deviceId, contactId, null, null, null, null); + 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(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(String id, String name, Integer deviceId, Integer contactId, Integer status, Integer previousStatus, Integer millis, Date lastUpdated) { + 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; this.previousStatus = previousStatus; this.deviceId = deviceId; this.contactId = contactId; + this.nodeId = nodeId; this.millis = millis; this.lastUpdated = lastUpdated; - } + this.commandStationId = commandStationId; + this.busNr = busNr; - @Id - @Column(name = "id", nullable = false) - public String getId() { - if (id == null) { - id = generateId(); + //TODO! + if (name == null) { + //this.name = generateName(); } - return id; } - private String generateId() { - //Format the id start with the device then "-" - //than a 4 char contact id - if (contactId == null) { + private String generateNameOld() { + 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; + } + + return dn + "-" + cn; + } else { 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) { + @Id + @Column(name = "id", nullable = false) + public Integer getId() { + return id; + } + + public void setId(Integer id) { this.id = id; } @Column(name = "name", length = 255, nullable = false) public String getName() { + if (name == null) { + //name = generateName(); + } return name; } @@ -123,6 +136,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; @@ -141,25 +163,41 @@ 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; + } + + @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) { status = 0; } previousStatus = status; - Date lastChanged = this.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(); } @@ -172,13 +210,34 @@ 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 lastUpdated) { - this.lastUpdated = lastUpdated; + public void setLastUpdated(Date updatedOn) { + Long prevUpdated = lastUpdated; + if (updatedOn != null) { + lastUpdated = updatedOn.getTime(); + } + + if (lastUpdated != null && prevUpdated != null) { + Long m = (lastUpdated - prevUpdated) / 10; + millis = m.intValue(); + } } @Transient @@ -191,22 +250,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; @@ -214,10 +279,13 @@ 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); hash = 41 * hash + Objects.hashCode(this.lastUpdated); + hash = 41 * hash + Objects.hashCode(this.commandStationId); + hash = 41 * hash + Objects.hashCode(this.busNr); return hash; } @@ -245,6 +313,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; } @@ -254,9 +325,16 @@ public boolean equals(Object obj) { if (!Objects.equals(this.millis, other.millis)) { return false; } + 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; @@ -268,18 +346,43 @@ 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; } 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; + //return name; + return toLogString(); } public String toLogString() { +// String ids; +// if (id == null) { +// ids = "(" + generateId() + ")"; +// } else { +// ids = id; +// } + return "SensorBean{" + "id=" + id @@ -289,6 +392,8 @@ public String toLogString() { + deviceId + ", contactId=" + contactId + + ", nodeId=" + + nodeId + ", status=" + status + ", previousStatus=" @@ -297,22 +402,10 @@ public String toLogString() { + millis + ", lastUpdated=" + lastUpdated - + '}'; + + ", commandStationId=" + + commandStationId + + ", busNr=" + + busNr + + "}"; } } - -// 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 6b4e8534..64fe3b1c 100755 --- a/src/main/java/jcs/persistence/H2PersistenceService.java +++ b/src/main/java/jcs/persistence/H2PersistenceService.java @@ -18,14 +18,16 @@ 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.net.URL; 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.Set; import javax.imageio.ImageIO; import jcs.entities.AccessoryBean; @@ -40,29 +42,48 @@ 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 { - private Database database; + protected Database database; - private final HashMap imageCache; - private final HashMap functionImageCache; + 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); + postInit(); + } + + private void initConnect() { + connect(); + } + + private void postInit() { setJCSPropertiesAsSystemProperties(); } - private void 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); + } + @Override public List getProperties() { List props = database.results(JCSPropertyBean.class); @@ -77,15 +98,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; } @@ -93,14 +114,27 @@ 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 - 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); @@ -117,13 +151,12 @@ 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; } @Override - public SensorBean getSensor(String id) { + public SensorBean getSensor(Integer id) { SensorBean sensor = database.where("id=?", id).first(SensorBean.class); return sensor; } @@ -133,14 +166,21 @@ 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; } + @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 @@ -151,83 +191,66 @@ 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 - public List generateSensorBeans(Integer deviceId, Integer bus0len, Integer bus1len, Integer bus2len, Integer bus3len) { - Map sensorBeans = new HashMap<>(); + 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(); - 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); - } - } + int rows = database.sql("delete from sensors").execute().getRowsAffected(); + Logger.trace("All " + rows + " Sensors deleted"); + } - 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)); - String id = sb.getId(); - sensorBeans.put(id, sb); - } - } + @Override + public List getLocomotiveFunctions(LocomotiveBean locomotive) { + Long locomotiveId = locomotive.getId(); + String commandStationId = locomotive.getCommandStationId(); - 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)); - String id = sb.getId(); - sensorBeans.put(id, sb); - } - } + List locFunctions = database.where("locomotive_id=?", locomotiveId).orderBy("f_number").results(FunctionBean.class); - 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)); - String id = sb.getId(); - sensorBeans.put(id, sb); - } - } + for (FunctionBean fb : locFunctions) { + if (CommandStationBean.ESU_ECOS.equals(commandStationId)) { + String ico = fb.getIcon(); + String path = "/media/esu/f" + ico + ".png"; - List existing = getSensors(); - for (SensorBean sb : existing) { - if (!sensorBeans.containsKey(sb.getId())) { - Logger.trace("Removing " + sb); - remove(sb); - } - } + fb.setInActiveIconImage(getFunctionImage(path)); + fb.setActiveIconImage(getFunctionImage(path)); - for (SensorBean sb : sensorBeans.values()) { - persist(sb); + // reverseButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/media/left-24.png"))); + } else { + fb.setInActiveIconImage(getFunctionImage(fb.getInActiveIcon())); + fb.setActiveIconImage(getFunctionImage(fb.getActiveIcon())); + } } - - return getSensors(); + return locFunctions; } @Override - public List getLocomotiveFunctions(Long locomotiveId) { - List locFunctions = database.where("locomotive_id=?", locomotiveId).orderBy("f_number").results(FunctionBean.class); + public FunctionBean getLocomotiveFunction(LocomotiveBean locomotive, Integer number) { + Long locomotiveId = locomotive.getId(); + String commandStationId = locomotive.getCommandStationId(); - for (FunctionBean fb : locFunctions) { - fb.setInActiveIconImage(this.getFunctionImage(fb.getInActiveIcon())); - fb.setActiveIconImage(this.getFunctionImage(fb.getActiveIcon())); + 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 locFunctions; + 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())); @@ -252,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; } @@ -266,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; } @@ -276,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; } @@ -287,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; @@ -311,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; @@ -325,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; @@ -341,11 +364,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()); @@ -366,12 +391,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); } @@ -387,11 +414,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 @@ -402,10 +430,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 @@ -416,10 +444,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 @@ -441,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... @@ -531,11 +573,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; } @@ -545,6 +589,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) { @@ -611,24 +656,20 @@ public synchronized TileBean persist(TileBean tileBean) { if (tileBean == null) { return null; } - TileBean tb; - 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) { + TileBean prev = database.where("id=?", tileBean.getId()).first(TileBean.class); + if (prev != null) { + database.update(tileBean).getRowsAffected(); //Logger.trace("Updated " + tileBean); } else { - database.insert(tb); + database.insert(tileBean); } + changeSupport.firePropertyChange("data.tile", prev, tileBean); } if (tileBean.getBlockBean() != null) { - this.persist(tileBean.getBlockBean()); + persist(tileBean.getBlockBean()); } return tileBean; @@ -636,17 +677,20 @@ 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); + remove(bb); } int rows = database.delete(tileBean).getRowsAffected(); Logger.trace(rows + " TileBean(s) deleted"); + changeSupport.firePropertyChange("data.tile.deleted", tileBean, null); } @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()); @@ -665,12 +709,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) { @@ -692,7 +737,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); @@ -757,7 +803,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); @@ -778,9 +825,35 @@ public synchronized RouteBean persist(RouteBean route) { } route.setRouteElements(rblr); } + changeSupport.firePropertyChange("data.route", prev, 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) { + RouteBean route = this.getRoute(rid); + database.sql("delete from routes where id =?", rid).execute(); + changeSupport.firePropertyChange("data.route.deleted", route, null); + } + } + @Override public synchronized void remove(RouteBean route) { if (route.getRouteElements() != null && !route.getRouteElements().isEmpty()) { @@ -790,15 +863,17 @@ 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() { + protected void setJCSPropertiesAsSystemProperties() { List props = getProperties(); props.forEach(p -> { System.setProperty(p.getKey(), p.getValue()); @@ -880,12 +955,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; } @@ -893,12 +975,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 @@ -918,20 +1002,30 @@ 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) { - 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..39073b3c 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. @@ -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,545 @@ /** * 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 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. + * + * @return A List of assigned SensorBeans. + */ List getAssignedSensors(); - SensorBean getSensor(String id); - + /** + * 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(Integer 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); + /** + * Persists a list of SensorBeans + * + * @param sensors a list of SensorBeans top persist + * @return the persisted list + */ + List persistSensorBeans(List sensors); + + /** + * Removes a SensorBean. + * + * @param sensor The SensorBean to remove. + */ void remove(SensorBean sensor); - List generateSensorBeans(Integer deviceId, Integer bus0len, Integer bus1len, Integer bus2len, Integer bus3len); + /** + * Removes all SensorBean from de persistent store.
+ * + * Also references to BlockBeans and TileBeans are removed + */ + void removeAllSensors(); // 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); - List getLocomotiveFunctions(Long locomotiveId); - + /** + * Retrieves a list of FunctionBeans associated with a locomotive. + * + * @param locomotiveId The ID of the locomotive. + * @return A List of FunctionBeans. + */ + List getLocomotiveFunctions(LocomotiveBean locomotive); + + /** + * 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(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); + /** + * 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); - void persist(List tiles); - + /** + * Persists a list of TileBeans. + * + * @param tiles The list of TileBeans to persist. + */ + List 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(); + /** + * + * @return the enabled feedback provider + */ + CommandStationBean getEnabledFeedbackProvider(); + + /** + * 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/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/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/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 8495ad73..ffa01da7 100644 --- a/src/main/java/jcs/ui/DispatcherStatusPanel.java +++ b/src/main/java/jcs/ui/DispatcherStatusPanel.java @@ -18,22 +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() { + tabsPane.setSelectedIndex(1); + } + + public void showLocomotiveTab() { + tabsPane.setSelectedIndex(0); + } + + public void 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); } /** @@ -44,12 +67,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); @@ -58,8 +82,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/DriverCabFrame.java b/src/main/java/jcs/ui/DriverCabFrame.java index 80ca25fe..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; @@ -39,15 +40,16 @@ 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; /** + * 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; private List filteredLocos; List locoNames; @@ -309,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); } @@ -320,12 +323,16 @@ 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)); 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/DriverCabPanel.java b/src/main/java/jcs/ui/DriverCabPanel.java index 5fe0e085..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; @@ -339,7 +341,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 +454,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 +461,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/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 73% rename from src/main/java/jcs/ui/monitor/FeedbackMonitor.java rename to src/main/java/jcs/ui/FeedbackSensorDialog.java index 283fd315..a6b95a63 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.settings.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 65291d38..6906cabb 100755 --- a/src/main/java/jcs/ui/JCSFrame.form +++ b/src/main/java/jcs/ui/JCSFrame.form @@ -31,44 +31,140 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
- + - - + + - + - - + + + + - + - + - - + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -77,6 +173,7 @@ + @@ -84,30 +181,62 @@ + + + + + + + + + + - + - - + + - + + + + + + + + + + + - - + + + - + - + - + + - + + + + + + + + + + + @@ -139,17 +268,17 @@ - + - + - + @@ -172,6 +301,9 @@ + + + @@ -181,11 +313,6 @@ - - - - - @@ -195,18 +322,18 @@ - + - + - + - + @@ -226,17 +353,20 @@ - + - + + + + - + @@ -256,50 +386,12 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + @@ -319,34 +411,31 @@ - + - + - - - - + - + - + - + - + - + @@ -389,29 +478,12 @@ - - - - - - - - - - - - - - - - - - + @@ -482,7 +554,7 @@ - + @@ -515,7 +587,7 @@ - + @@ -526,7 +598,7 @@ - + @@ -563,7 +635,7 @@ - + @@ -574,7 +646,7 @@ - + @@ -585,7 +657,7 @@ - + @@ -618,51 +690,29 @@ - + - - - - - - - - - - - - - - - - - - - + - + - - - - - + - + - - - + + + - + - + - + @@ -670,6 +720,10 @@ + + + + @@ -681,63 +735,40 @@ - + - + - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - + + @@ -752,14 +783,14 @@ - + - + @@ -784,7 +815,7 @@ - + @@ -807,7 +838,13 @@ + + + + + + @@ -818,11 +855,11 @@ - + - + @@ -835,7 +872,7 @@ - + @@ -855,11 +892,11 @@ - + - + @@ -873,9 +910,12 @@ - + + + + @@ -928,7 +968,7 @@ - + @@ -994,7 +1034,7 @@ - + @@ -1007,7 +1047,13 @@ + + + + + + @@ -1020,11 +1066,11 @@ - + - + @@ -1038,534 +1084,43 @@ - + - - - - - - - - - - - - + + + + - + - - - + - + - - - - - - - - - - + - - - + + + + + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - - - - - - - - - - diff --git a/src/main/java/jcs/ui/JCSFrame.java b/src/main/java/jcs/ui/JCSFrame.java index 8db050af..7ed6e4d9 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.JCheckBox; +import javax.swing.JCheckBoxMenuItem; import javax.swing.JFrame; -import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; @@ -58,31 +56,46 @@ 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; +import jcs.ui.layout.LayoutCanvas; 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; +import jcs.ui.panel.SmallDriverCabPanel; +import jcs.ui.settings.AccessoryDialog; +import jcs.ui.settings.CommandStationDialog; +import jcs.ui.settings.CommandStationPanel; +import jcs.ui.settings.LocomotiveDialog; +import jcs.ui.settings.SettingsDialog; +import jcs.ui.settings.PropertiesDialog; import jcs.ui.util.FrameMonitor; import jcs.ui.util.UICallback; import jcs.util.RunUtil; 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; private final Map actionMap; - private FeedbackMonitor feedbackMonitor; + private FeedbackSensorDialog feedbackMonitor; + + private boolean editMode = false; + + private LocomotiveDialog locomotiveDialog; + private AccessoryDialog accessoryDialog; + private CommandStationDialog commandStationDialog; + private PropertiesDialog propertiesDialog; + + private SettingsDialog settingsDialog; /** * Creates new form JCSFrame @@ -92,63 +105,82 @@ public JCSFrame() { initComponents(); if (RunUtil.isMacOSX()) { - this.quitMI.setVisible(false); - this.optionsMI.setVisible(false); - this.toolsMenu.setVisible(false); + //quitMI.setVisible(false); + //optionsMI.setVisible(false); + //settingsMenu.setVisible(false); + //see https://www.formdev.com/flatlaf/macos/ 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 ); - } + getRootPane().putClientProperty("apple.awt.transparentTitleBar", false); + getRootPane().putClientProperty("apple.awt.fullWindowContent", false); - initJCS(); - - if (SystemInfo.isMacFullWindowContentSupported) { + //getRootPane().putClientProperty("apple.awt.windowTitleVisible", false); //avoid overlap of the red/orange/green buttons and the window title - this.jcsToolBar.add(Box.createHorizontalStrut(70), 0); + //jcsToolBar.add(Box.createHorizontalStrut(70), 0); } - - initKeyStrokes(); } + initJCS(); + initKeyStrokes(); } private void initJCS() { if (PersistenceFactory.getService() != null) { - this.setTitle(this.getTitleString()); - - if (RunUtil.isMacOSX()) { - this.setTitle(""); - } + setTitle(getTitleString()); if (JCS.getJcsCommandStation().isConnected()) { setControllerProperties(); } + //Connect the panels so that they are notified with the locomotive selection + dispatcherStatusPanel.addLocomotiveSelectionChangeListener(smallDriverCabPanel); + //Show the default panel showOverviewPanel(); - - JCS.addRefreshListener(dispatcherStatusPanel); - + editMode = false; + //JCS.addRefreshListener(dispatcherStatusPanel); } } private void initKeyStrokes() { - KeyStroke key0 = KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_DOWN_MASK); + KeyStroke keySpace = KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0); + KeyStroke keyQuit = KeyStroke.getKeyStroke(KeyEvent.VK_Q, KeyEvent.CTRL_DOWN_MASK); - actionMap.put(key0, new AbstractAction("stopAction") { - @Override - public void actionPerformed(ActionEvent e) { - stop(); - } - }); + 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); + 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(keyEdit, new EditAction()); + + 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); + 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); @@ -160,64 +192,86 @@ public void actionPerformed(ActionEvent e) { } public void showExtraToolbar(JToolBar toolbar) { - this.jcsToolBar.add(toolbar); + jcsToolBar.add(toolbar); jcsToolBar.doLayout(); - this.repaint(); + toolbarPanel.repaint(); } public void hideExtraToolbar(JToolBar toolbar) { - this.jcsToolBar.remove(toolbar); + jcsToolBar.remove(toolbar); jcsToolBar.doLayout(); - 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"); + editMode = false; + 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(this.centerPanel, "turnoutsPanel"); + 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(this.centerPanel, "signalsPanel"); + private void showProperties() { + if (propertiesDialog == null) { + propertiesDialog = new PropertiesDialog(this, true); + propertiesDialog.pack(); + propertiesDialog.setLocationRelativeTo(null); + } + propertiesDialog.setVisible(true); } - public void showKeyboards() { - CardLayout card = (CardLayout) this.centerPanel.getLayout(); - card.show(this.centerPanel, "diagnosticPanel"); + private void showCommandStations() { + if (commandStationDialog == null) { + commandStationDialog = new CommandStationDialog(this, true); + commandStationDialog.pack(); + commandStationDialog.setLocationRelativeTo(null); + } + commandStationDialog.setVisible(true); } - public void showSettings() { - CardLayout card = (CardLayout) this.centerPanel.getLayout(); - card.show(this.centerPanel, "settingsPanel"); + private void showRoutes() { + if (editMode) { + layoutPanel.showRoutes(); + } } - public void showVNCConsole() { + private void showKeyboards() { CardLayout card = (CardLayout) this.centerPanel.getLayout(); - card.show(this.centerPanel, "vncPanel"); + card.show(centerPanel, "diagnosticPanel"); + editMode = false; } - public void showDesignLayoutPanel() { - if (!AutoPilot.isAutoModeActive()) { - CardLayout card = (CardLayout) this.centerPanel.getLayout(); - card.show(this.centerPanel, "designPanel"); - this.layoutPanel.loadLayout(); - } + private void showVNCConsole() { + CardLayout card = (CardLayout) this.centerPanel.getLayout(); + card.show(centerPanel, "vncPanel"); + editMode = false; } - public void stop() { - if (JCS.getJcsCommandStation() != null) { - JCS.getJcsCommandStation().switchPower(false); + private void showEditLayoutPanel() { + if (!AutoPilot.isAutoModeActive()) { + CardLayout card = (CardLayout) centerPanel.getLayout(); + card.show(centerPanel, "designPanel"); + layoutPanel.loadLayout(); + editMode = true; } } @@ -227,28 +281,23 @@ 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(); - this.virtualCB.setSelected(virt); + virtualCBMI.setSelected(virt); } } 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()); + feedbackMonitor = new FeedbackSensorDialog(this, false); + FrameMonitor.registerFrame(feedbackMonitor, FeedbackSensorDialog.class.getName()); } - this.feedbackMonitor.showMonitor(); + feedbackMonitor.showMonitor(); } /** @@ -261,25 +310,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)); - 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)); + 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(); - startAllLocomotivesBtn = new JToggleButton(); - resetAutoPilotBtn = new JButton(); - filler9 = new Box.Filler(new Dimension(20, 0), new Dimension(20, 0), new Dimension(20, 32767)); - showSettingsBtn = new JButton(); + filler5 = new Box.Filler(new Dimension(5, 0), new Dimension(5, 0), new Dimension(5, 32767)); + startAllLocsBtn = new JButton(); + 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(); @@ -291,44 +336,43 @@ 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)); + locoSplitPane = new JSplitPane(); dispatcherStatusPanel = new DispatcherStatusPanel(); + smallDriverCabPanel = new SmallDriverCabPanel(); jcsMenuBar = new JMenuBar(); fileMenu = new JMenu(); quitMI = new JMenuItem(); connectMI = new JMenuItem(); - viewMenu = new JMenu(); + 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(); + windowMenu = new JMenu(); showHome = new JMenuItem(); - showLocosMI = new JMenuItem(); editLayout = new JMenuItem(); + vncMI = new JMenuItem(); showKeyboard = new JMenuItem(); showSensorMonitor = new JMenuItem(); - toolsMenu = new JMenu(); - optionsMI = new JMenuItem(); - commandStationsMI = new JMenuItem(); + showRoutesMI = new JMenuItem(); + settingsMenu = new JMenu(); + showLocosMI = new JMenuItem(); + showAccessoryMI = new JMenuItem(); + showCommandStationsMI = new JMenuItem(); + showPropertiesMI = new JMenuItem(); helpMenu = new JMenu(); aboutMI = new JMenuItem(); 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); @@ -336,18 +380,40 @@ public void windowClosing(WindowEvent evt) { }); toolbarPanel.setName("toolbarPanel"); // NOI18N - FlowLayout flowLayout8 = new FlowLayout(FlowLayout.LEFT); - flowLayout8.setAlignOnBaseline(true); - toolbarPanel.setLayout(flowLayout8); + toolbarPanel.setPreferredSize(new Dimension(1350, 52)); + FlowLayout flowLayout2 = new FlowLayout(FlowLayout.LEFT); + flowLayout2.setAlignOnBaseline(true); + toolbarPanel.setLayout(flowLayout2); - 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)); + + 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"); @@ -369,51 +435,9 @@ public void actionPerformed(ActionEvent evt) { }); jcsToolBar.add(connectButton); - 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); - 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))); @@ -433,11 +457,8 @@ 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("Design Layout"); + showEditDesignBtn.setToolTipText("Edit Layout"); showEditDesignBtn.setBorder(BorderFactory.createLineBorder(new Color(204, 204, 204))); showEditDesignBtn.setFocusable(false); showEditDesignBtn.setHorizontalTextPosition(SwingConstants.CENTER); @@ -474,7 +495,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); @@ -493,8 +514,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"); @@ -513,11 +534,11 @@ 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("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); @@ -536,87 +557,59 @@ 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() { - public void actionPerformed(ActionEvent evt) { - startAllLocomotivesBtnActionPerformed(evt); - } - }); - jcsToolBar.add(startAllLocomotivesBtn); - - resetAutoPilotBtn.setIcon(new ImageIcon(getClass().getResource("/media/director-red.png"))); // NOI18N - resetAutoPilotBtn.setToolTipText("Design Layout"); - 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); - - 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() { + 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))); + 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) { - showSettingsBtnActionPerformed(evt); + startAllLocsBtnActionPerformed(evt); } }); - jcsToolBar.add(showSettingsBtn); + jcsToolBar.add(startAllLocsBtn); + + filler8.setName("filler8"); // NOI18N + jcsToolBar.add(filler8); toolbarPanel.add(jcsToolBar); 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)); @@ -638,109 +631,30 @@ 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")); - 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); + locoSplitPane.setDividerLocation(500); + locoSplitPane.setOrientation(JSplitPane.VERTICAL_SPLIT); + locoSplitPane.setToolTipText(""); + locoSplitPane.setName("locoSplitPane"); // NOI18N dispatcherStatusPanel.setName("dispatcherStatusPanel"); // NOI18N - leftPanel.add(dispatcherStatusPanel, BorderLayout.CENTER); + locoSplitPane.setLeftComponent(dispatcherStatusPanel); + + smallDriverCabPanel.setName("smallDriverCabPanel"); // NOI18N + locoSplitPane.setRightComponent(smallDriverCabPanel); + + leftPanel.add(locoSplitPane, BorderLayout.CENTER); locoDisplaySP.setLeftComponent(leftPanel); @@ -771,47 +685,141 @@ 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); - viewMenu.setText("View"); - viewMenu.setName("viewMenu"); // NOI18N + editMenu.setText("Edit"); + editMenu.setName("editMenu"); // NOI18N - showHome.setText("Home"); - showHome.setName("showHome"); // NOI18N - showHome.addActionListener(new ActionListener() { + 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) { - showHomeActionPerformed(evt); + rotateTileMIActionPerformed(evt); } }); - viewMenu.add(showHome); + editMenu.add(rotateTileMI); - showLocosMI.setLabel("Locomotives"); - showLocosMI.setName("showLocosMI"); // NOI18N - showLocosMI.addActionListener(new ActionListener() { + flipTileHorizontallyMI.setText("Flip Horizontally"); + flipTileHorizontallyMI.setToolTipText("Flip selected Tile Horizontally"); + flipTileHorizontallyMI.setName("flipTileHorizontallyMI"); // NOI18N + flipTileHorizontallyMI.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { - showLocosMIActionPerformed(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); + + windowMenu.setText("Window"); + windowMenu.setName("windowMenu"); // NOI18N + + showHome.setMnemonic('H'); + showHome.setText("Home"); + showHome.setToolTipText("Home screen"); + showHome.setName("showHome"); // NOI18N + showHome.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + showHomeActionPerformed(evt); } }); - viewMenu.add(showLocosMI); + windowMenu.add(showHome); + 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) { editLayoutActionPerformed(evt); } }); - viewMenu.add(editLayout); + windowMenu.add(editLayout); + vncMI.setMnemonic('V'); + vncMI.setText("VNC"); + vncMI.setToolTipText("Show VNC screen"); + vncMI.setName("vncMI"); // NOI18N + vncMI.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + vncMIActionPerformed(evt); + } + }); + windowMenu.add(vncMI); + + showKeyboard.setMnemonic('K'); showKeyboard.setText("Keyboard"); + showKeyboard.setToolTipText("Accessory keyboard"); showKeyboard.setName("showKeyboard"); // NOI18N showKeyboard.addActionListener(new ActionListener() { 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() { @@ -819,32 +827,64 @@ public void actionPerformed(ActionEvent evt) { showSensorMonitorActionPerformed(evt); } }); - viewMenu.add(showSensorMonitor); + 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); - toolsMenu.setText("Tools"); - toolsMenu.setName("toolsMenu"); // NOI18N + 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) { + showLocosMIActionPerformed(evt); + } + }); + settingsMenu.add(showLocosMI); + + 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); - optionsMI.setText("Options"); - optionsMI.setName("optionsMI"); // NOI18N - optionsMI.addActionListener(new ActionListener() { + showCommandStationsMI.setText("Command Stations"); + showCommandStationsMI.setToolTipText("Commans Station Settings"); + showCommandStationsMI.setName("showCommandStationsMI"); // NOI18N + showCommandStationsMI.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { - optionsMIActionPerformed(evt); + showCommandStationsMIActionPerformed(evt); } }); - toolsMenu.add(optionsMI); + settingsMenu.add(showCommandStationsMI); - commandStationsMI.setText("Command Stations"); - commandStationsMI.setName("commandStationsMI"); // NOI18N - commandStationsMI.addActionListener(new ActionListener() { + showPropertiesMI.setText("Properties"); + showPropertiesMI.setToolTipText("Property Settings"); + showPropertiesMI.setName("showPropertiesMI"); // NOI18N + showPropertiesMI.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { - commandStationsMIActionPerformed(evt); + showPropertiesMIActionPerformed(evt); } }); - toolsMenu.add(commandStationsMI); + settingsMenu.add(showPropertiesMI); - jcsMenuBar.add(toolsMenu); + jcsMenuBar.add(settingsMenu); helpMenu.setText("Help"); helpMenu.setName("helpMenu"); // NOI18N @@ -863,6 +903,7 @@ public void actionPerformed(ActionEvent evt) { setJMenuBar(jcsMenuBar); pack(); + setLocationRelativeTo(null); }// //GEN-END:initComponents private void showLocosMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_showLocosMIActionPerformed @@ -874,41 +915,24 @@ 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); - 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 - handlePreferences(); - }//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 showOverviewPanel(); - this.overviewPanel.loadLayout(); }//GEN-LAST:event_showOverviewBtnActionPerformed 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); } @@ -918,6 +942,27 @@ 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); + + //Disconnect Command stations + JCS.getJcsCommandStation().switchPower(false); + JCS.getJcsCommandStation().disconnect(); + + setVisible(false); + dispose(); + + //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) { @@ -928,37 +973,25 @@ 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); + 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); + powerButton.setSelected(JCS.getJcsCommandStation().isPowerOn()); } } else { JCS.getJcsCommandStation().disconnect(); - this.controllerDescriptionLbl.setText("-"); - this.controllerCatalogNumberLbl.setText("-"); - this.controllerSerialNumberLbl.setText("-"); - this.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 @@ -968,11 +1001,10 @@ 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 - showDesignLayoutPanel(); + showEditLayoutPanel(); }//GEN-LAST:event_editLayoutActionPerformed private void showKeyboardActionPerformed(ActionEvent evt) {//GEN-FIRST:event_showKeyboardActionPerformed @@ -986,18 +1018,12 @@ 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 - CommandStationDialog csd = new CommandStationDialog(this, true); - csd.setLocationRelativeTo(null); - csd.setVisible(true); - }//GEN-LAST:event_commandStationsMIActionPerformed - - private void showSettingsBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_showSettingsBtnActionPerformed - showSettings(); - }//GEN-LAST:event_showSettingsBtnActionPerformed + private void showCommandStationsMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_showCommandStationsMIActionPerformed + showCommandStations(); + }//GEN-LAST:event_showCommandStationsMIActionPerformed private void aboutMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_aboutMIActionPerformed Logger.trace(evt.getActionCommand()); @@ -1013,39 +1039,93 @@ 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"); + startAutopilot(); + }//GEN-LAST:event_autoPilotBtnActionPerformed - if (this.autoPilotBtn.isSelected()) { - this.startAllLocomotivesBtn.setEnabled(true); + private void startAutopilot() { + 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()); - }//GEN-LAST:event_autoPilotBtnActionPerformed + AutoPilot.runAutoPilot(autoPilotBtn.isSelected()); + } - 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(); + + private void startAllLocsBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_startAllLocsBtnActionPerformed + startAllLocomotives(); + }//GEN-LAST:event_startAllLocsBtnActionPerformed + + private void showAccessoryMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_showAccessoryMIActionPerformed + showAccessories(); + }//GEN-LAST:event_showAccessoryMIActionPerformed + + private void showPropertiesMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_showPropertiesMIActionPerformed + showProperties(); + }//GEN-LAST:event_showPropertiesMIActionPerformed + + private void rotateTileMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_rotateTileMIActionPerformed + if (editMode) { + layoutPanel.rotateSelectedTile(); } - }//GEN-LAST:event_startAllLocomotivesBtnActionPerformed + }//GEN-LAST:event_rotateTileMIActionPerformed - private void resetAutoPilotBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_resetAutoPilotBtnActionPerformed - AutoPilot.resetStates(); - }//GEN-LAST:event_resetAutoPilotBtnActionPerformed + private void flipTileHorizontallyMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_flipTileHorizontallyMIActionPerformed + if (editMode) { + layoutPanel.flipSelectedTileHorizontal(); + } + }//GEN-LAST:event_flipTileHorizontallyMIActionPerformed + + private void flipTileVerticallyMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_flipTileVerticallyMIActionPerformed + if (editMode) { + layoutPanel.flipSelectedTileVerical(); + } + }//GEN-LAST:event_flipTileVerticallyMIActionPerformed - private void virtualCBActionPerformed(ActionEvent evt) {//GEN-FIRST:event_virtualCBActionPerformed - Logger.trace(evt.getActionCommand() + " Switch Virtual Mode " + (this.virtualCB.isSelected() ? "On" : "Off")); + private void deleteTileMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_deleteTileMIActionPerformed + 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(this.virtualCB.isSelected()); + JCS.getJcsCommandStation().setVirtual(virtualCBMI.isSelected()); } - }//GEN-LAST:event_virtualCBActionPerformed + }//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 + showRoutes(); + }//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(); @@ -1064,19 +1144,22 @@ public void openFiles(List files) { } @Override - 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); + 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 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 @@ -1090,71 +1173,63 @@ 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) { - this.powerButton.setSelected(event.isPower()); + powerButton.setSelected(event.isPower()); } // Variables declaration - do not modify//GEN-BEGIN:variables private JMenuItem aboutMI; private JToggleButton autoPilotBtn; - private JPanel bottomLeftPanel; + private JMenuItem autoPilotMI; private JPanel centerPanel; private CommandStationPanel commandStationPanel; - private JMenuItem commandStationsMI; 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 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 JMenuBar jcsMenuBar; private JToolBar jcsToolBar; private KeyboardSensorPanel keyboardSensorMessagePanel; private LayoutPanel layoutPanel; private JPanel leftPanel; private JSplitPane locoDisplaySP; + private JSplitPane locoSplitPane; private JPanel mainPanel; - private JMenuItem optionsMI; private LayoutPanel overviewPanel; private JToggleButton powerButton; private JMenuItem quitMI; - private JButton resetAutoPilotBtn; + private JMenuItem resetAutopilotMI; + private JMenuItem rotateTileMI; + private JMenu settingsMenu; private JPanel settingsPanel; + private JMenuItem showAccessoryMI; + private JMenuItem showCommandStationsMI; private JButton showEditDesignBtn; private JButton showFeedbackMonitorBtn; private JMenuItem showHome; @@ -1162,15 +1237,137 @@ public void powerChanged(PowerEvent event) { private JButton showKeyboardBtn; private JMenuItem showLocosMI; private JButton showOverviewBtn; + private JMenuItem showPropertiesMI; + private JMenuItem showRoutesMI; private JMenuItem showSensorMonitor; - private JButton showSettingsBtn; private JButton showVNCBtn; - private JToggleButton startAllLocomotivesBtn; + private SmallDriverCabPanel smallDriverCabPanel; + private JButton startAllLocsBtn; + private JMenuItem startAllLocsMI; private StatusPanel statusPanel; private JPanel toolbarPanel; - private JMenu toolsMenu; - 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..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("-"); + } } /** @@ -70,6 +74,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 +88,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 +128,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/VNCPanel.java b/src/main/java/jcs/ui/VNCPanel.java index deced133..7f2ed948 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; @@ -42,17 +41,16 @@ import javax.swing.JPanel; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; -import jcs.commandStation.esu.ecos.net.EcosConnectionFactory; +import jcs.JCS; 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,19 +59,24 @@ 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(); } private void initVnc() { - addDrawingSurface(); - initialiseVernacularClient(); - //clipboardMonitor.start(); - + if (JCS.getJcsCommandStation() != null) { + if (!JCS.getJcsCommandStation().getCommandStationBean().isVirtual()) { + addDrawingSurface(); + //clipboardMonitor.start(); + initialiseVernacularClient(); + if (JCS.getJcsCommandStation().isConnected()) { + String ip = JCS.getJcsCommandStation().getCommandStationInfo().getIpAddress(); + int port = DEFAULT_VNC_PORT; + connect(ip, port); + } + } + } } private void addDrawingSurface() { @@ -367,8 +370,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()); @@ -386,22 +387,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/main/java/jcs/ui/layout/LayoutCanvas.form b/src/main/java/jcs/ui/layout/LayoutCanvas.form index 4a20d061..0253ad8b 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.form +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.form @@ -194,15 +194,13 @@ - + - - + - - + @@ -226,7 +224,7 @@ - + diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.java b/src/main/java/jcs/ui/layout/LayoutCanvas.java index 40a5407e..a3ce2914 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.java +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.java @@ -17,49 +17,35 @@ import java.awt.BasicStroke; import java.awt.Color; +import java.awt.Component; import java.awt.Cursor; 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; import java.awt.event.MouseAdapter; 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.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; 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.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 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; @@ -70,6 +56,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; @@ -81,14 +68,16 @@ 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; /** * 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, @@ -99,45 +88,38 @@ 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; - private TileBean.TileType tileType; + private TileType tileType; private Point mouseLocation = new Point(); - private BufferedImage grid; - private final ExecutorService executor; - private final Map tiles; - private final Map altTiles; - private final Set selectedTiles; - private Tile selectedTile; private RoutesDialog routesDialog; - private final Map selectedRouteElements; - - private Point movingTileCenterPoint; - private BufferedImage movingTileImage; public LayoutCanvas() { this(false); } public LayoutCanvas(boolean readonly) { - this.readonly = readonly; - this.tiles = new HashMap<>(); - this.altTiles = new HashMap<>(); - - this.selectedTiles = new HashSet<>(); - this.selectedRouteElements = new HashMap<>(); + super(); + setLayout(null); + setOpaque(true); + setDoubleBuffered(true); + this.readonly = readonly; this.executor = Executors.newSingleThreadExecutor(); //this.executor = Executors.newCachedThreadPool(); @@ -151,163 +133,82 @@ public LayoutCanvas(boolean readonly) { private void postInit() { routesDialog = new RoutesDialog(getParentFrame(), false, this, this.readonly); - lineGrid = "true".equals(System.getProperty("draw.linegrid", "true")); + } + + public boolean isReadonly() { + return readonly; } @Override - protected void paintComponent(Graphics g) { - Graphics2D g2 = (Graphics2D) g.create(); - Set snapshot = new HashSet<>(tiles.values()); + public void paint(Graphics g) { + //long started = System.currentTimeMillis(); + super.paint(g); - if (this.drawGrid) { - if (lineGrid) { + if (drawGrid) { + if (this.gridType == LINE_GRID) { paintLineGrid(g); } else { paintDotGrid(g); } - } else { - paintNullGrid(g); - } - - for (Tile tile : snapshot) { - 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, drawGrid); - //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 - public void propertyChange(PropertyChangeEvent evt) { - if ("repaintTile".equals(evt.getPropertyName())) { - Tile tile = (Tile) evt.getNewValue(); - this.repaint(tile.getBounds()); + public Component add(Component component) { + super.add(component); + if (component instanceof Tile tile) { + tile.setBounds(tile.getTileBounds()); } + return component; } - 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(); + @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); } - Graphics2D g2 = (Graphics2D) g; - //Draw grid from pre computed image - g2.drawImage(grid, null, 0, 0); + return component; } 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(); - - 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); - } + 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++) { + 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); } 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(); - - if (pw != gw || ph != gh) { - this.grid = null; - } + 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); } - - 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); - - 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(); + 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) { @@ -316,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) { @@ -331,263 +242,231 @@ void setDirection(Direction direction) { void loadLayoutInBackground() { this.executor.execute(() -> loadTiles()); - } - public void loadTiles() { - boolean showValues = Mode.CONTROL.equals(mode); +// new Thread(new Runnable() { +// public void run() { +// final String text = readHugeFile(); +// SwingUtilities.invokeLater(new Runnable() { +// public void run() { +// canvas.setTiles(); +// } +// }); +// } +// }).start(); + } - List tileBeans = PersistenceFactory.getService().getTileBeans(); + private void loadTiles() { + List tiles = TileCache.loadTiles(readonly); - selectedTiles.clear(); - altTiles.clear(); - tiles.clear(); - selectedRouteElements.clear(); + removeAll(); + selectedTile = null; - for (TileBean tb : tileBeans) { - Tile tile = TileFactory.createTile(tb, drawGrid, showValues); - tile.setPropertyChangeListener(this); - tiles.put(tile.getCenter(), tile); + Dimension minSize = TileCache.getMinCanvasSize(); + setMinimumSize(minSize); - //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); - } - } + //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; } - Logger.debug("Loaded " + tiles.size() + " Tiles..."); - repaint(); - } - - public 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)); - } - - private synchronized void saveTiles(Set snapshot) { - 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?"); - } + if (h < minSize.height) { + h = minSize.height; + changeSize = true; } - 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?"); + if (changeSize) { + setPreferredSize(new Dimension(w, h)); + setSize(new Dimension(w, h)); + Logger.trace("Changed size to w: " + w + " h: " + h); } - } - 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?"); + for (Tile tile : tiles) { + add(tile); + boolean showCenter = "true".equalsIgnoreCase(System.getProperty("tile.show.center", "false")); + if (showCenter) { + tile.setDrawCenterPoint(showCenter); + } } } private void mouseMoveAction(MouseEvent evt) { Point sp = LayoutUtil.snapToGrid(evt.getPoint()); - Tile tile = 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); - if (t != null) { - return t; - } - } - } - return t; - } - private void mousePressedAction(MouseEvent evt) { + Logger.trace("@ (" + evt.getX() + "," + evt.getY() + ")"); Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); - Tile tile = findTile(snapPoint); - //Clear any previous selection - selectedTiles.clear(); - if (tile != null) { - selectedTiles.addAll(tile.getAllPoints()); + Tile previousSelected = selectedTile; + selectedTile = TileCache.findTile(snapPoint); + //Only show selected tile in edit mode + 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 (tile != null) { + if (selectedTile != null) { if (evt.getButton() == MouseEvent.BUTTON1) { - executeControlActionForTile(tile, snapPoint); + executeControlActionForTile(selectedTile, snapPoint); } else { - Logger.trace("Show menuitems for tile " + tile); - this.selectedTile = tile; - 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); - if (addedTile != null) { - selectedTiles.addAll(addedTile.getAllPoints()); - - if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { - this.saveTile(tile); - } + 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 -> { - removeTiles(selectedTiles); + Tile toBeDeleted = (Tile) getComponentAt(snapPoint); + if (toBeDeleted != null) { + removeTile(toBeDeleted); + //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 @ (" + snapPoint.x + "," + snapPoint.y + ")")); if (MouseEvent.BUTTON3 == evt.getButton()) { - showOperationsPopupMenu(tile, snapPoint); + showOperationsPopupMenu(selectedTile, snapPoint); } } } - repaint(); } - private void mouseDragAction(MouseEvent evt) { - Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); - Tile selTile = getSelectedTile(); - if (selTile != null) { - movingTileImage = selTile.getTileImage(); - movingTileCenterPoint = 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); + Tile tile = TileCache.createTile(tileType, orientation, direction, p); + + if (TileCache.canMoveTo(tile, p)) { + tile.setSelected(selected); + tile.setDrawCenterPoint(showCenter); + add(tile); + TileCache.addAndSaveTile(tile); + return tile; } else { - movingTileImage = null; - movingTileCenterPoint = null; + Tile occ = TileCache.findTile(p); + Logger.trace("Can't add tile " + tile.getId() + " on " + tile.xyToString() + " Is occupied by " + occ.getId()); + TileCache.rollback(tile); + return null; } - 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; + void deleteSelectedTile() { + Logger.trace("Selected Tile " + selectedTile.getId()); + removeTile(selectedTile); + selectedTile = null; } - private void mouseReleasedAction(MouseEvent evt) { - Tile selTile = getSelectedTile(); - if (selTile != null) { - Logger.trace("Selected tile: " + selTile.getId() + ", " + selTile.xyToString()); + 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) { + //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 + ")"); + + if (TileCache.canMoveTo(selectedTile, snapPoint)) { + selectedTile.setSelectedColor(Tile.DEFAULT_SELECTED_COLOR); + } else { + selectedTile.setSelectedColor(Tile.DEFAULT_WARN_COLOR); + } - 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)) { - Tile tile = findTile(snapPoint); - if (selTile.getId().equals(tile.getId())) { - //same tile so we can move - canMove = true; + 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 { - Logger.debug("Position " + snapPoint + " is occupied with tile: " + tile + ", can't move tile " + selTile.getId()); - canMove = false; + curX = snapPoint.x - Tile.GRID; + curY = snapPoint.y - Tile.GRID - Tile.GRID * 2; } } - - 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); + case CROSS -> { + switch (selectedTile.getOrientation()) { + case SOUTH -> { + curX = snapPoint.x - Tile.GRID; + curY = snapPoint.y - Tile.GRID; } - - //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); - } - selectedTiles.clear(); - selectedTiles.addAll(movingTile.getAllPoints()); - } 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); - } + case WEST -> { + curX = snapPoint.x - Tile.GRID - Tile.GRID * 2; + curY = snapPoint.y - Tile.GRID; } - - if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { - this.saveTile(movingTile); + 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()); } - movingTileImage = null; - movingTileCenterPoint = null; + } - repaint(); + private void mouseReleasedAction(MouseEvent evt) { + Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); + if (!Mode.CONTROL.equals(mode) && MouseEvent.BUTTON1 == evt.getButton() && selectedTile != null) { + if (TileCache.canMoveTo(selectedTile, snapPoint)) { + TileCache.moveTo(selectedTile, snapPoint); + } else { + selectedTile.setSelectedColor(Tile.DEFAULT_SELECTED_COLOR); + selectedTile.setBounds(selectedTile.getTileBounds()); + } + } } private void executeControlActionForTile(Tile tile, Point p) { @@ -598,7 +477,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()); @@ -607,68 +486,23 @@ 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()); + Logger.trace("Block properties closed"); + this.repaint(block.getTileBounds()); + } + 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.setValue(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()); - } - } - - 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()); - repaint(signal.getX(), signal.getY(), signal.getWidth(), signal.getHeight()); - } else { - Logger.trace("No AccessoryBean configured for Signal: " + signal.getId()); - } - } - - 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()); - - sensor.repaintTile(); - - SensorEvent sensorEvent = new SensorEvent(sb); - //this.executor.execute(() -> fireFeedbackEvent(sensorEvent)); - 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; @@ -677,12 +511,9 @@ private void editSelectedTileProperties() { boolean showMove = false; boolean showDelete = false; - if (!this.selectedTiles.isEmpty()) { - Point tcp = this.selectedTiles.iterator().next(); - Tile tile = 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 -> { @@ -702,32 +533,31 @@ 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 -> { } } + repaint(); } - //this.executor.execute(() -> repaint()); - repaint(); } private void showBlockPopupMenu(Tile tile, Point p) { @@ -765,11 +595,13 @@ 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(); + TileType tt = tile.getTileType(); switch (tt) { case SENSOR -> { showProperties = true; @@ -823,241 +655,25 @@ 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 = getCheckAvailable(p); - 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; - } - } - } - - 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); - } - - 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) { - this.repaint(); - } - - if (canBeAdded) { - return tile; - } else { - return null; - } - } - - 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(); - repaint(); - } - private JFrame getParentFrame() { JFrame frame = (JFrame) SwingUtilities.getRoot(this); return frame; } 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); - } - } - } - repaint(); + Logger.trace("Selected Tile " + selectedTile.getId()); + selectedTile = TileCache.rotateTile(selectedTile); + selectedTile.setBounds(selectedTile.getTileBounds()); } 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()); + selectedTile = TileCache.flipHorizontal(selectedTile); + selectedTile.setBounds(selectedTile.getTileBounds()); } 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()); + selectedTile = TileCache.flipVertical(selectedTile); + selectedTile.setBounds(selectedTile.getTileBounds()); } void routeLayout() { @@ -1066,20 +682,19 @@ void routeLayout() { private void routeLayoutWithAStar() { //Make sure the layout is saved - Set snapshot = new HashSet<>(tiles.values()); - this.saveTiles(snapshot); + TileCache.persistAllTiles(); 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()) { - this.routesDialog.loadRoutes(); + if (routesDialog.isVisible()) { + routesDialog.loadRoutes(); } } void showRoutesDialog() { - this.routesDialog.setVisible(true); + routesDialog.setVisible(true); } /** @@ -1270,11 +885,9 @@ public void actionPerformed(ActionEvent evt) { }); blockPopupMenu.add(blockPropertiesMI); - setBackground(new Color(250, 250, 250)); - setAutoscrolls(true); - setMinimumSize(new Dimension(1398, 848)); - setOpaque(false); - setPreferredSize(new Dimension(1398, 848)); + setBackground(new Color(255, 255, 255)); + setMinimumSize(new Dimension(1000, 760)); + setPreferredSize(new Dimension(1000, 760)); addMouseMotionListener(new MouseMotionAdapter() { public void mouseDragged(MouseEvent evt) { formMouseDragged(evt); @@ -1307,7 +920,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 @@ -1316,7 +928,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 @@ -1325,7 +936,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 @@ -1334,7 +944,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 @@ -1360,7 +969,11 @@ 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); + if (selectedTile != null) { + removeTile(selectedTile); + repaint(selectedTile.getTileBounds()); + selectedTile = null; + } }//GEN-LAST:event_deleteMIActionPerformed private void propertiesMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_propertiesMIActionPerformed @@ -1372,22 +985,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.getBlockBean().getLocomotive(); - - this.executor.execute(() -> AutoPilot.startStopLocomotive(locomotive, true)); - repaint(); + 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 (this.selectedTile != null) { - Block block = (Block) selectedTile; - LocomotiveBean locomotive = block.getBlockBean().getLocomotive(); - - this.executor.execute(() -> AutoPilot.startStopLocomotive(locomotive, false)); - repaint(); + 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 @@ -1396,37 +1005,36 @@ 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 private void removeLocMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_removeLocMIActionPerformed - if (this.selectedTile != null) { - Block block = (Block) selectedTile; - LocomotiveBean locomotive = block.getBlockBean().getLocomotive(); + if (selectedTile != null && selectedTile.isBlock()) { + LocomotiveBean locomotive = selectedTile.getLocomotive(); locomotive.setDispatcherDirection(null); - block.getBlockBean().setLocomotive(null); - block.setBlockState(BlockState.FREE); - block.getBlockBean().setArrivalSuffix(null); + selectedTile.setLocomotive(null); - this.executor.execute(() -> { - PersistenceFactory.getService().persist(block.getBlockBean()); + executor.execute(() -> { + PersistenceFactory.getService().persist(selectedTile.getBlockBean()); PersistenceFactory.getService().persist(locomotive); + + AutoPilot.removeLocomotive(locomotive); }); - this.repaint(); } }//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); - this.repaint(block.getX(), block.getY(), block.getWidth(), block.getHeight()); + repaint(selectedTile.getTileBounds()); } }//GEN-LAST:event_blockPropertiesMIActionPerformed @@ -1434,35 +1042,36 @@ 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()); - this.executor.execute(() -> PersistenceFactory.getService().persist(block.getBlockBean())); - this.repaint(); + block.setReverseArrival(!block.isReverseArrival()); + this.executor.execute(() -> { + PersistenceFactory.getService().persist(block.getBlockBean()); + }); } }//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); - block.repaintTile(); + PersistenceFactory.getService().persist(block.getTileBean()); }); } }//GEN-LAST:event_toggleLocomotiveDirectionMIActionPerformed @@ -1470,16 +1079,17 @@ 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()) { - this.executor.execute(() -> PersistenceFactory.getService().persist(block.getBlockBean())); - this.repaint(); + if (currentState != block.getBlockState()) { + this.executor.execute(() -> { + PersistenceFactory.getService().persist(block.getBlockBean()); + }); } } }//GEN-LAST:event_toggleOutOfOrderMIActionPerformed @@ -1488,14 +1098,16 @@ 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) { + if (block.getLocomotive() != null) { block.setBlockState(BlockBean.BlockState.OCCUPIED); } else { block.setBlockState(BlockBean.BlockState.FREE); } - this.executor.execute(() -> PersistenceFactory.getService().persist(block.getBlockBean())); - this.repaint(); + this.executor.execute(() -> { + PersistenceFactory.getService().persist(block.getBlockBean()); + }); } } }//GEN-LAST:event_resetGhostMIActionPerformed diff --git a/src/main/java/jcs/ui/layout/LayoutPanel.form b/src/main/java/jcs/ui/layout/LayoutPanel.form index 7fc284b9..b512ef69 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 @@
- + - + @@ -163,10 +163,6 @@ - - - - @@ -175,35 +171,12 @@ - + - - - - - - - - - - - - - - - - - - - - - - - @@ -227,29 +200,6 @@ - - - - - - - - - - - - - - - - - - - - - - - @@ -367,6 +317,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -452,39 +435,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -845,29 +795,6 @@ - - - - - - - - - - - - - - - - - - - - - - - @@ -914,29 +841,6 @@ - - - - - - - - - - - - - - - - - - - - - - - @@ -1013,17 +917,19 @@
- - + - + + + + @@ -1034,13 +940,21 @@ + + + + + + - + + + diff --git a/src/main/java/jcs/ui/layout/LayoutPanel.java b/src/main/java/jcs/ui/layout/LayoutPanel.java index 52efe209..4f14ede6 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; @@ -45,12 +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 { + private static final long serialVersionUID = 2275543202224445302L; + private final boolean readonly; public LayoutPanel() { @@ -73,17 +80,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,71 +136,42 @@ 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); -// this.autoPilotBtn.setVisible(readonly); -// this.resetAutopilotBtn.setEnabled(readonly); -// this.resetAutopilotBtn.setVisible(readonly); -// 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); -// 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); - } } - public void saveLayout() { - this.canvas.saveLayout(); + public void loadLayout() { + canvas.loadLayoutInBackground(); } - public void loadLayout() { - this.canvas.loadLayoutInBackground(); + public void rotateSelectedTile() { + canvas.rotateSelectedTile(); } - public void loadTiles() { - this.canvas.loadTiles(); + public void flipSelectedTileHorizontal() { + canvas.flipSelectedTileHorizontal(); + } + + public void flipSelectedTileVerical() { + canvas.flipSelectedTileVertical(); + } + + public void deleteSelectedTile() { + canvas.deleteSelectedTile(); } /** @@ -227,20 +198,18 @@ 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(); 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(); @@ -254,10 +223,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); @@ -344,9 +311,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); @@ -361,33 +328,16 @@ 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); - 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)); - - 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); + toolBar.setPreferredSize(new Dimension(980, 42)); loadBtn.setIcon(new ImageIcon(getClass().getResource("/media/load-24.png"))); // NOI18N loadBtn.setToolTipText("Load"); @@ -404,21 +354,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); @@ -485,6 +420,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); @@ -531,20 +480,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("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"); @@ -746,21 +681,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); @@ -791,35 +711,21 @@ 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); - 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(1000, 720)); canvas.setName(""); // NOI18N - canvas.setLayout(new BorderLayout()); + 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 @@ -877,17 +783,13 @@ 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 // editSelectedTileProperties(); }//GEN-LAST:event_propertiesMIActionPerformed - private void saveBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_saveBtnActionPerformed - this.saveLayout(); - }//GEN-LAST:event_saveBtnActionPerformed - private void loadBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_loadBtnActionPerformed this.loadLayout(); }//GEN-LAST:event_loadBtnActionPerformed @@ -902,13 +804,9 @@ 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 - this.canvas.repaint(); - }//GEN-LAST:event_repaintBtnActionPerformed - private void straightBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_straightBtnActionPerformed setTileType(TileBean.TileType.STRAIGHT); }//GEN-LAST:event_straightBtnActionPerformed @@ -921,10 +819,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 @@ -933,10 +827,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); @@ -957,7 +847,6 @@ private void sensorBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_sensor private void gridBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_gridBtnActionPerformed this.canvas.setDrawGrid(this.gridBtn.isSelected()); - this.canvas.repaint(); }//GEN-LAST:event_gridBtnActionPerformed private void formComponentResized(ComponentEvent evt) {//GEN-FIRST:event_formComponentResized @@ -976,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 @@ -1006,27 +894,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()) { + if (startAllLocomotivesBtn.isSelected()) { AutoPilot.startAllLocomotives(); - } else { - AutoPilot.stopAllLocomotives(); } }//GEN-LAST:event_startAllLocomotivesBtnActionPerformed @@ -1035,18 +920,22 @@ 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) { - this.canvas.setTileType(tileType); + canvas.setTileType(tileType); } private void setDirection(Direction direction) { - this.canvas.setDirection(direction); + canvas.setDirection(direction); } - private void setMode(LayoutCanvas.Mode mode) { + public void showRoutes() { + canvas.showRoutesDialog(); + } + + public void setMode(LayoutCanvas.Mode mode) { switch (mode) { case SELECT -> { selectBtn.setIcon(new ImageIcon(getClass().getResource("/media/cursor-24-y.png"))); @@ -1070,20 +959,14 @@ private 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")); + //Logger.info("Track Power is " + (event.isPower() ? "on" : "off")); if (!event.isPower() && autoPilotBtn.isSelected()) { autoPilotBtn.doClick(); @@ -1120,18 +1003,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/LayoutPanelTester.java b/src/main/java/jcs/ui/layout/LayoutPanelTester.java index bf0c9cac..3dbe297b 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); } @@ -43,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) { @@ -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..80807bf7 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); } @@ -43,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) { @@ -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/LayoutUtil.java b/src/main/java/jcs/ui/layout/LayoutUtil.java index d8525e07..14a1361b 100644 --- a/src/main/java/jcs/ui/layout/LayoutUtil.java +++ b/src/main/java/jcs/ui/layout/LayoutUtil.java @@ -18,16 +18,8 @@ import jcs.ui.layout.tiles.Tile; import java.awt.Point; -/** - * - * @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 +58,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 +72,4 @@ 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; -// } } diff --git a/src/main/java/jcs/ui/layout/RoutesDialog.java b/src/main/java/jcs/ui/layout/RoutesDialog.java index b23106e4..12cf89a2 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; @@ -32,8 +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.TileFactory; +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); - TileFactory.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); } - TileFactory.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 30d4b4fb..1fe853fa 100644 --- a/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java +++ b/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java @@ -24,19 +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.TileFactory; +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; /** @@ -49,86 +47,87 @@ 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) { 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); 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); } } } @@ -413,93 +412,119 @@ 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); + + AutoPilot.addLocomotive(loc); } - TileEvent tileEvent = new TileEvent(bb); - TileFactory.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); + Logger.trace(evt.getActionCommand() + " -> " + locomotiveComboBoxModel.getSelectedItem()); + + LocomotiveBean selected = (LocomotiveBean) locomotiveComboBoxModel.getSelectedItem(); + + LocomotiveBean previous = block.getLocomotive(); + if (selected.getId() != null) { + block.setLocomotive(selected); } else { - block.getBlockBean().setBlockState(BlockBean.BlockState.FREE); + block.setLocomotive(null); } - + 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); } + + 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 = this.block.getBlockBean().getLocomotive(); + LocomotiveBean loc = block.getLocomotive(); if (loc != null) { - AutoPilot.startStopLocomotive(loc, this.startLocButton.isSelected()); + if (startLocButton.isSelected()) { + AutoPilot.startLocomotive(loc); + } else { + AutoPilot.stopLocomotive(loc); + } } }//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/dialogs/BlockDialog.java b/src/main/java/jcs/ui/layout/dialogs/BlockDialog.java index 69e9826b..9a29d5e2 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.tiles.TileCache; import jcs.ui.layout.tiles.Block; import jcs.ui.layout.tiles.Sensor; import jcs.ui.layout.tiles.Tile; @@ -38,6 +39,8 @@ */ public class BlockDialog extends javax.swing.JDialog { + private static final long serialVersionUID = 6278388475191663591L; + private final Block block; private final LayoutCanvas layoutCanvas; @@ -60,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()); @@ -84,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())) { @@ -100,7 +103,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 +164,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..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,19 +60,19 @@ 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()); } } - //Filter the unused turnouts + //Filter the unused sensors List filtered = new ArrayList<>(); for (SensorBean sb : sensors) { if (!usedSensorIds.contains(sb.getId())) { @@ -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) { @@ -263,18 +266,20 @@ 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) { - 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); sensor.setSensorBean(sensorBean); Logger.trace("Created " + sensorBean); - PersistenceFactory.getService().persist((sensor)); + PersistenceFactory.getService().persist((sensor.getTileBean())); JCS.getJcsCommandStation().addSensorEventListener(sensor); } } @@ -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/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/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/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/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..8a6eb0a7 100755 --- a/src/main/java/jcs/ui/layout/tiles/Block.java +++ b/src/main/java/jcs/ui/layout/tiles/Block.java @@ -15,83 +15,77 @@ */ package jcs.ui.layout.tiles; -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Font; -import java.awt.Graphics2D; -import java.awt.Image; +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 jcs.entities.BlockBean; -import jcs.entities.BlockBean.BlockState; +import javax.swing.UIManager; 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; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; -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; -import static jcs.ui.layout.tiles.Tile.RENDER_WIDTH; -import jcs.ui.util.ImageUtil; +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 AbstractTile implements Tile { +/** + * Representation of a Block on the layout + */ +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) { + public 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.type = tileBean.getType(); + setModel(new DefaultTileModel(tileBean.getOrientation())); + populateModel(); + initUI(); } - 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, tileWidth(orientation, TileType.BLOCK), tileHeight(orientation, TileType.BLOCK)); + } - 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.type = TileType.BLOCK.getTileType(); + public Block(Orientation orientation, int x, int y, int width, int height) { + super(TileType.BLOCK, 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.BlockUI"); + setUI((TileUI) UIManager.getUI(this)); + invalidate(); } @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())) { @@ -118,6 +112,33 @@ public Set getAllPoints() { 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(); @@ -259,29 +280,30 @@ public String getIdSuffix(Tile other) { } } + Orientation tileOrientation = model.getTileOrienation(); 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 = "-"; } } @@ -289,106 +311,18 @@ public String getIdSuffix(Tile other) { } @Override - public void rotate() { + public Orientation rotate() { super.rotate(); - if (Orientation.EAST.equals(getOrientation()) || Orientation.WEST.equals(getOrientation())) { - 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; - - 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; - } - /** - * 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 - */ - public Color getBlockStateColor() { - if (blockBean != null) { - BlockState blockState = blockBean.getBlockState(); - return getBlockStateColor(blockState); - } else { - return Color.white; - } - } + Orientation tileOrientation = model.getTileOrienation(); + int w = tileWidth(tileOrientation, TileType.BLOCK); + int h = tileHeight(tileOrientation, TileType.BLOCK); - public 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 void setRouteBlockState(BlockState routeBlockState) { - this.routeBlockState = routeBlockState; - } - - 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); + Dimension d = new Dimension(w, h); + setPreferredSize(d); + setSize(d); + setBounds(getTileBounds()); + return model.getTileOrienation(); } public static String getDepartureSuffix(Orientation tileOrientation, boolean reverseArrival, LocomotiveBean.Direction direction) { @@ -424,380 +358,27 @@ 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 + 20, yy - 0, rw + 20, 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 (getBlockBean() != null && getBlockBean().getLocomotive() != null && getBlockBean().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 orientation = this.getOrientation(); - BlockBean bb = this.getBlockBean(); - boolean reverseArrival = bb.isReverseArrival(); - - LocomotiveBean.Direction logicalDirection; - if (bb.getLogicalDirection() != null) { - logicalDirection = LocomotiveBean.Direction.get(bb.getLogicalDirection()); + 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 { - logicalDirection = bb.getLocomotive().getDirection(); - } - - String departureSuffix = bb.getDepartureSuffix(); - if (departureSuffix == null) { - departureSuffix = Block.getDepartureSuffix(orientation, reverseArrival, logicalDirection); + xx = tileX - GRID * multiplier; + yy = tileY - GRID * multiplier - GRID * multiplier * 2; } - //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) { - 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); - } - } - } - } + if (model.isScaleImage()) { + return new Rectangle(xx, yy, tileWidth(tileOrientation, TileType.BLOCK), tileHeight(tileOrientation, TileType.BLOCK)); } else { - if (Orientation.EAST == orientation || Orientation.SOUTH == orientation) { - 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); - } - } - } - } - } + int renderWidth = getUI().getRenderWidth(); + int renderHeight = getUI().getRenderHeight(); - } - - 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 (routeBlockState != null) { - backgroundColor = getBlockStateColor(routeBlockState); + return new Rectangle(xx, yy, renderWidth, renderHeight); } } - protected void overlayLocImage(Graphics2D g2d) { - Image locImage = getLocImage(); - String departureSuffix = null; - boolean reverseImage = true; - if (getBlockBean() != null) { - reverseImage = getBlockBean().isReverseArrival(); - } - - if (getBlockBean() != null) { - departureSuffix = getBlockBean().getDepartureSuffix(); - } - if (locImage != 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 - switch (getOrientation()) { - case WEST -> { - int xx; - int w = locImage.getWidth(null); - int h = locImage.getHeight(null); - - if (null == departureSuffix) { - xx = x - width / 2 + w; - } else { - switch (departureSuffix) { - case "+" -> { - xx = x - width / 2 + w - 25; - } - default -> { - xx = x - width / 2 + w + 10; - } - } - } - int yy = y - 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); - - int xx = x - w / 2; - int yy; - if (null == departureSuffix) { - yy = y - height / 2 + h; - } else { - switch (departureSuffix) { - case "-" -> { - yy = y - height / 2 + h - 25; - } - default -> { - yy = y - height / 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); - - int w = locImage.getWidth(null); - int h = locImage.getHeight(null); - - int xx = x - w / 2; - int yy; - if (null == departureSuffix) { - int minY = y - height / 2 + h; - yy = minY; - } else { - switch (departureSuffix) { - case "+" -> { - yy = y - height / 2 + h - 25; - } - default -> { - yy = y - height / 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); - - if (null == departureSuffix) { - xx = x - width / 2 + w; - } else { - switch (departureSuffix) { - case "-" -> { - xx = x - width / 2 + w - 25; - } - default -> { - xx = x - width / 2 + w + 10; - } - } - } - int yy = y - 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 - * @param drawOutline - */ - @Override - public void drawTile(Graphics2D g2d, boolean drawOutline) { - super.drawTile(g2d, drawOutline); - if (getLocImage() != null) { - overlayLocImage(g2d); - } - } - - @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)) { - repaintTile(); - } - } - - 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; - } - } else { - return null; - } - } - - public String getBlockText() { - String blockText; - if (!drawOutline && getBlockBean() != null && getBlockBean().getDescription() != null) { - if (blockBean.getLocomotive() != null && blockBean.getLocomotive().getName() != null && BlockState.GHOST != blockBean.getBlockState()) { - blockText = getBlockBean().getLocomotive().getName(); - } else { - if (getBlockBean().getDescription().length() > 0) { - blockText = getBlockBean().getDescription(); - } else { - blockText = getId(); - } - } - } else { - // Design mode show description when available - if (getBlockBean() != null && getBlockBean().getDescription() != null && getBlockBean().getDescription().length() > 0) { - blockText = getBlockBean().getDescription(); - } else { - blockText = getId(); - } - } - return blockText; - } - - @Override - public void drawName(Graphics2D g2d) { - Image locImage = getLocImage(); - - if (locImage == null) { - 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(); - - switch (getOrientation()) { - 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); - } - } } diff --git a/src/main/java/jcs/ui/layout/tiles/Cross.java b/src/main/java/jcs/ui/layout/tiles/Cross.java index 691758e8..4fa88889 100644 --- a/src/main/java/jcs/ui/layout/tiles/Cross.java +++ b/src/main/java/jcs/ui/layout/tiles/Cross.java @@ -15,26 +15,35 @@ */ package jcs.ui.layout.tiles; -import java.awt.BasicStroke; import java.awt.Color; -import java.awt.Graphics2D; +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 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 jcs.ui.layout.tiles.ui.CrossUI; +import jcs.ui.layout.tiles.ui.TileUI; -public class Cross extends Switch implements Tile { +/** + * Representation of a Cross switch on the layout + */ +public class Cross extends Switch { public static final int CROSS_WIDTH = DEFAULT_WIDTH * 2; public static final int CROSS_HEIGHT = DEFAULT_HEIGHT * 2; @@ -47,52 +56,81 @@ 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(); + public Cross(Orientation orientation, Direction direction, Point center) { + this(orientation, direction, center.x, center.y); } - Cross(Orientation orientation, Direction direction, int x, int y) { - this(orientation, direction, new Point(x, 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, Point center) { - super(orientation, direction, center); - this.type = TileType.CROSS.getTileType(); - 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(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 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 + * @return the Set of points which mark the position of the Cross */ @Override public Set getAltPoints() { - int xx = this.x; - int yy = this.y; - Set alternatives = new HashSet<>(); + 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(xx, (yy + DEFAULT_HEIGHT)); - alternatives.add(sp); + Point sp = new Point(center.x, (center.y + DEFAULT_HEIGHT)); + alts.add(sp); } case WEST -> { - Point wp = new Point((xx - DEFAULT_WIDTH), yy); - alternatives.add(wp); + Point wp = new Point((center.x - DEFAULT_WIDTH), center.y); + alts.add(wp); } case NORTH -> { - Point np = new Point(xx, (yy - DEFAULT_HEIGHT)); - alternatives.add(np); + Point np = new Point(center.x, (center.y - DEFAULT_HEIGHT)); + alts.add(np); } default -> { //East so default - Point ep = new Point((x + DEFAULT_WIDTH), yy); - alternatives.add(ep); + Point ep = new Point((center.x + DEFAULT_WIDTH), center.y); + alts.add(ep); } } - return alternatives; + return alts; } @Override @@ -160,8 +198,8 @@ public Map getNeighborPoints() { @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); - Orientation orientation = this.getOrientation(); - Direction direction = this.getDirection(); + Orientation orientation = getOrientation(); + Direction direction = getDirection(); int cx = this.getCenterX(); int cy = this.getCenterY(); @@ -219,285 +257,6 @@ public Map getEdgePoints() { return edgeConnections; } - @Override - public void rotate() { - super.rotate(); - setWidthHeightAndOffsets(); - } - - 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; - 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) { @@ -566,4 +325,79 @@ public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { return AccessoryValue.OFF; } } + + @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() { + this.renderOffsetY = 0; + this.renderOffsetX = 0; + if (isHorizontal()) { + this.renderOffsetY = 0; + } else { + this.renderOffsetX = 0; + } + } + + @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 0c1751ad..1a00e86f 100644 --- a/src/main/java/jcs/ui/layout/tiles/Crossing.java +++ b/src/main/java/jcs/ui/layout/tiles/Crossing.java @@ -15,31 +15,54 @@ */ 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 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 implements Tile { +/** + * Representation of a (passive) Crossing the layout + */ +public class Crossing extends Straight { - Crossing(TileBean tileBean) { + public Crossing(TileBean tileBean) { super(tileBean); - this.width = DEFAULT_WIDTH; - this.height = DEFAULT_HEIGHT; + initUI(); } - 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; + 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 @@ -72,76 +95,56 @@ public Map getEdgePoints() { 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); - } - } - } - +// 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 b82d882b..124f4a44 100755 --- a/src/main/java/jcs/ui/layout/tiles/Curved.java +++ b/src/main/java/jcs/ui/layout/tiles/Curved.java @@ -15,32 +15,58 @@ */ 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 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; + +/** + * Representation of a Curved track on the layout + */ +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 class Curved extends AbstractTile implements Tile { + 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(); + } - Curved(TileBean tileBean) { - super(tileBean); - this.width = DEFAULT_WIDTH; - this.height = DEFAULT_HEIGHT; + private void initUI() { + updateUI(); } - Curved(Orientation orientation, int x, int y) { - this(orientation, new Point(x, y)); + @Override + public String getUIClassID() { + return CurvedUI.UI_CLASS_ID; } - Curved(Orientation orientation, Point center) { - super(orientation, center); - this.width = DEFAULT_WIDTH; - this.height = DEFAULT_HEIGHT; - this.type = TileType.CURVED.getTileType(); + @Override + public void updateUI() { + UIManager.put(TileUI.UI_CLASS_ID, "jcs.ui.layout.tiles.ui.CurvedUI"); + setUI((TileUI) UIManager.getUI(this)); + invalidate(); } @Override @@ -107,33 +133,4 @@ public Map getEdgePoints() { 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); - } - } 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..d904fcd5 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java @@ -0,0 +1,439 @@ +/* + * 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.event.ActionEvent; +import java.awt.event.ActionListener; +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; +import jcs.entities.BlockBean.BlockState; +import jcs.entities.LocomotiveBean; +import jcs.entities.TileBean.Orientation; + +/** + * + */ +public class DefaultTileModel implements TileModel { + + protected transient ChangeEvent changeEvent = null; + + protected EventListenerList listenerList = new EventListenerList(); + + protected boolean selected = false; + protected Color selectedColor; + 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; + protected boolean showAccessoryValue = false; + protected boolean showSignalValue = false; + protected boolean sensorActive = false; + protected AccessoryValue accessoryValue; + protected SignalValue signalValue; + + protected boolean showOutline = false; + + protected boolean reverseArrival; + protected String arrivalSuffix; + protected boolean overlayImage = false; + protected BlockState blockState; + protected LocomotiveBean locomotive; + protected LocomotiveBean.Direction logicalDirection; + + public DefaultTileModel() { + this(Orientation.EAST); + } + + public DefaultTileModel(Orientation orientation) { + this.tileOrienation = orientation; + this.selectedColor = Tile.DEFAULT_SELECTED_COLOR; + this.blockState = BlockState.FREE; + } + + @Override + public boolean isSelected() { + return selected; + } + + @Override + public void setSelected(boolean selected) { + this.selected = 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; + } + + @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 Orientation getTileOrienation() { + return tileOrienation; + } + + @Override + 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() { + return showRoute; + } + + @Override + public void setShowRoute(boolean showRoute) { + this.showRoute = showRoute; + fireStateChanged(); + } + + @Override + public boolean isShowBlockState() { + return showBlockState; + } + + //Set all block properties is one go + @Override + public void setBlockBean(BlockBean blockBean) { + if (blockBean != null) { + 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; + 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 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) { + blockState = BlockState.FREE; + } + return blockState; + } + + @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(); + } + + @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; + 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(); + } + + @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); + } + + /** + * {@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 + */ + public ChangeListener[] getChangeListeners() { + return listenerList.getListeners(ChangeListener.class); + } + + /** + * Notifies all listeners that have registered interest for notification on this event type.br> The event instance is created lazily. + */ + protected void fireStateChanged() { + 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) { + if (changeEvent == null) { + changeEvent = new ChangeEvent(this); + } + ((ChangeListener) listeners[i + 1]).stateChanged(changeEvent); + } + } + } + +// 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 + */ + protected void fireActionPerformed(ActionEvent e) { + 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) { + + // if (changeEvent == null) + // changeEvent = new ChangeEvent(this); + ((ActionListener) listeners[i + 1]).actionPerformed(e); + } + } + } + +} diff --git a/src/main/java/jcs/ui/layout/tiles/End.java b/src/main/java/jcs/ui/layout/tiles/End.java index 8e535bbc..a1c5e6aa 100644 --- a/src/main/java/jcs/ui/layout/tiles/End.java +++ b/src/main/java/jcs/ui/layout/tiles/End.java @@ -15,34 +15,58 @@ */ 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 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; + +/** + * Representation of a End track on the layout + */ +public class End extends Tile { -public class End extends AbstractTile implements Tile { - - End(TileBean tileBean) { - super(tileBean); - this.width = DEFAULT_WIDTH; - this.height = DEFAULT_HEIGHT; + public End(TileBean tileBean) { + super(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); + setModel(new DefaultTileModel(tileBean.getOrientation())); + initUI(); } - 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); + } + + 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(); } - End(Orientation orientation, int x, int y) { - super(orientation, x, y); - this.type = TileType.END.getTileType(); - this.width = DEFAULT_WIDTH; - this.height = DEFAULT_HEIGHT; + @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 @@ -65,13 +89,6 @@ public Map getNeighborPoints() { return neighbors; } - @Override - public Set getAllPoints() { - Set aps = new HashSet<>(); - aps.add(getCenter()); - return aps; - } - @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); @@ -91,36 +108,4 @@ public Map getEdgePoints() { } 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) { - } - } diff --git a/src/main/java/jcs/ui/layout/tiles/Sensor.java b/src/main/java/jcs/ui/layout/tiles/Sensor.java index dacc13a4..baedc593 100644 --- a/src/main/java/jcs/ui/layout/tiles/Sensor.java +++ b/src/main/java/jcs/ui/layout/tiles/Sensor.java @@ -15,90 +15,63 @@ */ 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; +/** + * Representation of a Sensor in a track on the layout + */ 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) { - 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 (this.active) { - 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 g2) { - Graphics2D g2d = (Graphics2D) g2.create(); - - renderStraight(g2d); - - if (drawRoute) { - renderTileRoute(g2); - } - - renderSensor(g2d); - - g2d.dispose(); + public void updateUI() { + UIManager.put(TileUI.UI_CLASS_ID, "jcs.ui.layout.tiles.ui.SensorUI"); + setUI((TileUI) UIManager.getUI(this)); + invalidate(); } @Override public void onSensorChange(SensorEvent event) { SensorBean sensor = event.getSensorBean(); if (sensor.equalsDeviceIdAndContactId(getSensorBean())) { - this.setActive(sensor.isActive()); - repaintTile(); + setActive(sensor.isActive()); } } + //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..f0c6eb69 100644 --- a/src/main/java/jcs/ui/layout/tiles/Signal.java +++ b/src/main/java/jcs/ui/layout/tiles/Signal.java @@ -15,37 +15,25 @@ */ 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; 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 static jcs.ui.layout.tiles.Tile.RENDER_GRID; +import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean.TileType; +import jcs.ui.layout.tiles.ui.SignalUI; +import jcs.ui.layout.tiles.ui.TileUI; -public class Signal extends Straight implements Tile, AccessoryEventListener { - - private SignalValue signalValue; - private SignalType signalType; +/** + * Representation of a Signal besides the track on the layout + */ +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,324 +46,28 @@ 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; + model.setSignalValue(SignalValue.OFF); } @Override - public SignalType getSignalType() { - return signalType; - } - - public void setSignalValue(SignalValue signalValue) { - this.signalValue = signalValue; + public String getUIClassID() { + return SignalUI.UI_CLASS_ID; } @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; - } - } - - /** - * 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); - } - - if (drawRoute) { - renderTileRoute(g2); - } - - g2d.dispose(); + public void updateUI() { + UIManager.put(TileUI.UI_CLASS_ID, "jcs.ui.layout.tiles.ui.SignalUI"); + setUI((TileUI) UIManager.getUI(this)); + invalidate(); } + //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..437c48ff 100755 --- a/src/main/java/jcs/ui/layout/tiles/Straight.java +++ b/src/main/java/jcs/ui/layout/tiles/Straight.java @@ -15,32 +15,55 @@ */ package jcs.ui.layout.tiles; -import java.awt.BasicStroke; -import java.awt.Graphics2D; +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.HashSet; import java.util.Map; -import java.util.Set; +import javax.swing.UIManager; import jcs.entities.TileBean; +import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean.TileType; -public class Straight extends AbstractTile implements Tile { +/** + * Representation of a Straight track on the layout + */ +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(tileBean.getOrientation())); + initUI(); } - 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(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 @@ -81,47 +104,4 @@ public Map getEdgePoints() { 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); - } - } diff --git a/src/main/java/jcs/ui/layout/tiles/StraightDirection.java b/src/main/java/jcs/ui/layout/tiles/StraightDirection.java index fc5cb964..a3ae761c 100644 --- a/src/main/java/jcs/ui/layout/tiles/StraightDirection.java +++ b/src/main/java/jcs/ui/layout/tiles/StraightDirection.java @@ -15,26 +15,44 @@ */ 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; +/** + * Representation of a Straight track where trans can only run in one direction on the layout + */ 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 + 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 @@ -59,30 +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 g2) { - Graphics2D g2d = (Graphics2D) g2.create(); - - 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..1ce2f43f 100644 --- a/src/main/java/jcs/ui/layout/tiles/Switch.java +++ b/src/main/java/jcs/ui/layout/tiles/Switch.java @@ -15,44 +15,72 @@ */ 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 javax.swing.UIManager; 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; +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 class Switch extends AbstractTile implements Tile, AccessoryEventListener { + public Switch(Orientation orientation, Direction direction, Point center) { + this(orientation, direction, center.x, center.y); + } - protected AccessoryValue accessoryValue; - protected AccessoryValue routeValue; - protected Color routeColor; + 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); + } - Switch(TileBean tileBean) { - super(tileBean); - this.width = DEFAULT_WIDTH; - this.height = DEFAULT_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(); } - Switch(Orientation orientation, Direction direction, int x, int y) { - this(orientation, direction, new Point(x, y)); + public Switch(TileBean tileBean) { + this(tileBean, 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(); + 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 @@ -155,138 +183,10 @@ public Map getEdgePoints() { return edgeConnections; } - @Override - public Set getAllPoints() { - Set aps = new HashSet<>(); - aps.add(getCenter()); - 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; - 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 (this.getAccessoryBean() != null && event.isEventFor(accessoryBean)) { - setValue(event.getAccessoryBean().getAccessoryValue()); - repaintTile(); + if (getAccessoryBean() != null && event.isEventFor(accessoryBean)) { + setAccessoryValue(event.getAccessoryBean().getAccessoryValue()); } } 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..4ba0ad50 --- 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. @@ -15,207 +15,973 @@ */ package jcs.ui.layout.tiles; +import jcs.ui.layout.tiles.ui.TileUI; import java.awt.Color; -import java.awt.Graphics2D; +import java.awt.Dimension; 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.image.AffineTransformOp; import java.awt.image.BufferedImage; 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 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.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.
+ * + *

+ * 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 interface Tile extends Shape { +public abstract class Tile extends JComponent { 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); + 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; - Color getBackgroundColor(); + public static final String MODEL_CHANGED_PROPERTY = "model"; +// public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled"; + private static final long serialVersionUID = -8117888635518142366L; - void setBackgroundColor(Color backgroundColor); - - String getId(); + /** + * The data model that determines the Tile state. + */ + protected TileModel model = null; - void setId(String id); + protected String id; + protected Integer tileX; + protected Integer tileY; - //String getImageKey(); - - BufferedImage getTileImage(); + protected Direction tileDirection; - void drawTile(Graphics2D g2d, boolean drawOutline); + protected TileType tileType; + protected String accessoryId; + protected Integer sensorId; - void renderTile(Graphics2D g2d); + protected AccessoryValue routeValue; - void renderTileRoute(Graphics2D g2d); + protected SignalType signalType; - void drawName(Graphics2D g2); + protected TileBean tileBean; + protected AccessoryBean accessoryBean; + protected SensorBean sensorBean; + protected BlockBean blockBean; - void drawCenterPoint(Graphics2D g2d); + protected List neighbours; - void drawCenterPoint(Graphics2D g2, Color color); + protected int renderOffsetX = 0; + protected int renderOffsetY = 0; - void drawCenterPoint(Graphics2D g2d, Color color, double size); + protected boolean drawName = true; - void drawBounds(Graphics2D g2d); + protected BufferedImage tileImage; - void rotate(); + protected PropertyChangeListener propertyChangeListener; - void flipHorizontal(); + protected ChangeListener changeListener = null; + protected ActionListener actionListener = null; - void flipVertical(); + protected transient ChangeEvent changeEvent; + private Handler handler; - void move(int newX, int newY); + 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; + 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) { + 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())); + } + if (accessoryBean != null) { + setAccessoryBean(accessoryBean); + } + if (sensorBean != null) { + setSensorBean(sensorBean); + } + + } + + 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.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); + tileBean.setSensorId(this.sensorId); + tileBean.setAccessoryBean(this.accessoryBean); + tileBean.setSensorBean(this.sensorBean); + tileBean.setBlockBean(this.blockBean); + } + return tileBean; + } - TileBean.Orientation getOrientation(); + /** + * + * @return true when the Tile is selected in the screen + */ + public boolean isSelected() { + return model.isSelected(); + } - void setOrientation(TileBean.Orientation orientation); + public void setSelected(boolean b) { + model.setSelected(b); + } - Direction getDirection(); + public String getId() { + return id; + } - void setDirection(Direction direction); + public void setId(String id) { + this.id = id; + } - Point getCenter(); + public SignalType getSignalType() { + return signalType; + } - void setCenter(Point center); + public void setSignalType(SignalType signalType) { + this.signalType = signalType; + } /** - * @return a Set of alternative points in case the tile is not a square + * + * @return the Tile X coordinate on the screen. */ - Set getAltPoints(); + public Integer getTileX() { + return tileX; + } /** - * @return All points relevant for the Object on the Canvas + * + * @return the Tile Y coordinate on the screen */ - Set getAllPoints(); - - int getOffsetX(); - - void setOffsetX(int offsetX); - - int getOffsetY(); - - void setOffsetY(int offsetY); - - int getHeight(); - - int getWidth(); + public Integer getTileY() { + return tileY; + } /** - * @return the X (pixel) coordinate of the center of the tile + * + * @return the Tile X and Y coordinates on the screen. */ - int getCenterX(); + 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); + } + } /** - * @return then Y (pixel) coordinate of the center of the tile + * + * @return The Tile Orientation. The default orientation is East or from left to right */ - int getCenterY(); - - TileBean getTileBean(); + 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 Integer getSensorId() { + return sensorId; + } + + public void setSensorId(Integer 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) { + model.setBlockState(blockState); + if (blockBean != null) { + blockBean.setBlockState(blockState); + } else { + Logger.warn("Blockbean for " + id + " is NOT set!"); + } + } + + public String getDepartureSuffix() { + return model.getDepartureSuffix(); + } + + public void setDepartureSuffix(String suffix) { + model.setDepartureSuffix(suffix); + if (blockBean != null) { + blockBean.setDepartureSuffix(suffix); + } else { + Logger.warn("Blockbean for " + id + " is NOT set!"); + } + } + + public boolean isReverseArrival() { + return model.isReverseArrival(); + } + + public void setReverseArrival(boolean reverseArrival) { + model.setReverseArrival(reverseArrival); + if (blockBean != null) { + blockBean.setReverseArrival(reverseArrival); + } else { + Logger.warn("Blockbean for " + id + " is NOT set!"); + } + } + + public LocomotiveBean.Direction getLogicalDirection() { + return model.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!"); + } + } + + public LocomotiveBean getLocomotive() { + return model.getLocomotive(); + } + + public void setLocomotive(LocomotiveBean locomotive) { + model.setLocomotive(locomotive); + if (blockBean != null) { + blockBean.setLocomotive(locomotive); + } else { + Logger.warn("Blockbean for " + id + " is NOT set!"); + } + } + + 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() { + return accessoryBean; + } + + public void setAccessoryBean(AccessoryBean accessoryBean) { + this.accessoryBean = accessoryBean; + if (accessoryBean != null) { + accessoryId = accessoryBean.getId(); + 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; + model.setAccessoryValue(AccessoryValue.OFF); + } + } + + public void setAccessoryValue(AccessoryValue value) { + model.setAccessoryValue(value); + if (accessoryBean != null) { + accessoryBean.setAccessoryValue(value); + } + } + + public AccessoryValue getRouteValue() { + if (routeValue == null) { + return AccessoryValue.OFF; + } else { + return routeValue; + } + } + + public void setRouteValue(AccessoryValue value) { + this.routeValue = value; + repaint(); + } + + public void setSignalValue(AccessoryBean.SignalValue signalValue) { + 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; + this.model.setBlockBean(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); + } - boolean isDrawOutline(); - - void setDrawOutline(boolean drawOutline); + /** + * + * @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(); - TileType getTileType(); + public abstract Map getEdgePoints(); - void setPropertyChangeListener(PropertyChangeListener listener); + Set getAltPoints(Point center) { + return Collections.emptySet(); + } - String xyToString(); + public Set getAllPoints() { + return getAllPoints(getCenter()); + } - /** - * @return the X number of the grid square (grid is 40 x 40 pix) - */ - int getGridX(); + Set getAllPoints(Point center) { + Set aps = new HashSet<>(); + aps.add(center); + return aps; + } /** - * @return the Y number of the grid square (grid is 40 x 40 pix) + * Rotate the tile clockwise 90 deg + * + * @return the new Orientation */ - int getGridY(); + 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(); + } + } + + public void moveTile(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.emptySet(); + } + + 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 { + 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() + + " {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 */ - boolean isHorizontal(); + 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 */ - boolean isVertical(); + 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 */ - boolean isDiagonal(); + public boolean isDiagonal() { + return TileType.CURVED == tileType; + } - boolean isJunction(); + public boolean isCrossing() { + return TileType.CROSSING == tileType; + } - boolean isBlock(); + public List getNeighbours() { + return 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; + + if (other != null) { + Collection thisEdgePoints = getEdgePoints().values(); + Collection otherEdgePoints = other.getEdgePoints().values(); + + for (Point p : thisEdgePoints) { + adjacent = otherEdgePoints.contains(p); + if (adjacent) { + break; + } + } + } - String getIdSuffix(Tile other); + 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; + } + + 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 { + + @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 + 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 { + int renderWidth = getUI().getRenderWidth(); + int renderHeight = getUI().getRenderHeight(); + + return new Rectangle(tileX - renderWidth / 2, tileY - renderHeight / 2, renderWidth, renderHeight); + } + } } 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..6ce2c7b0 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/TileActionEventHandler.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.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 jcs.entities.AccessoryBean; +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 accessoryEvent) { + switchChanged(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.getIdString() + " -> " + sensorEvent.isActive()); + List acl = JCS.getJcsCommandStation().getFeedbackControllers(); + for (FeedbackController fbc : acl) { + fbc.fireSensorEventListeners(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/TileCache.java b/src/main/java/jcs/ui/layout/tiles/TileCache.java new file mode 100644 index 00000000..83aa2d4e --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/TileCache.java @@ -0,0 +1,573 @@ +/* + * 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.Dimension; +import java.awt.Point; +import java.util.HashMap; +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.events.AccessoryEventListener; +import jcs.entities.TileBean; +import jcs.persistence.PersistenceFactory; +import org.tinylog.Logger; +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; +import jcs.commandStation.events.JCSActionEvent; +import static jcs.ui.layout.tiles.Tile.GRID; + +/** + * Factory object to create Tiles and cache pointMap + * + * @author frans + */ +public class TileCache { + + // 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); + + private static int maxX; + private static int maxY; + + static { + actionEventQueueHandler.start(); + } + + private TileCache() { + } + + public static int getIdSeq(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, getIdSeq(tileBean.getId())); + } + case CROSSING -> { + tile = new Crossing(tileBean); + crossingIdSeq = maxIdSeq(crossingIdSeq, getIdSeq(tileBean.getId())); + } + case CURVED -> { + tile = new Curved(tileBean); + curvedIdSeq = maxIdSeq(curvedIdSeq, getIdSeq(tileBean.getId())); + } + case SWITCH -> { + tile = new Switch(tileBean); + tile.setAccessoryBean(tileBean.getAccessoryBean()); + + switchIdSeq = maxIdSeq(switchIdSeq, getIdSeq(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, getIdSeq(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, getIdSeq(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, getIdSeq(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, getIdSeq(tileBean.getId())); + } + case STRAIGHT_DIR -> { + tile = new StraightDirection(tileBean); + straightDirectionIdSeq = maxIdSeq(straightDirectionIdSeq, getIdSeq(tileBean.getId())); + } + case END -> { + tile = new End(tileBean); + endIdSeq = maxIdSeq(endIdSeq, getIdSeq(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); + } + + 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 + if (!tile.getAltPoints().isEmpty()) { + Set alt = tile.getAltPoints(); + for (Point ap : alt) { + altPointMap.put(ap, tile); + } + } + } + + Logger.trace("Loaded " + idMap.size() + " Tiles. Max: (" + maxX + "," + maxY + ")"); + return idMap.values().stream().collect(Collectors.toList()); + } + + 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"); + } + + pointMap.put(tile.getCenter(), tile); + idMap.put(tile.getId(), tile); + + //Alternative point(s) to be able to find all pointIds + if (!tile.getAltPoints().isEmpty()) { + Set alt = tile.getAltPoints(); + for (Point ap : alt) { + altPointMap.put(ap, tile); + } + } + + persistTile(tile); + //Logger.trace("Added " + tile + " There are now " + pointMap.size() + " pointMap..."); + return tile; + } + + 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 persistAllTiles() { + for (Tile tile : idMap.values()) { + persistTile(tile); + } + } + + public static void deleteTile(final Tile tile) { + 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 " + tile.getId() + " not found in cache"); + } + } + + public static Tile findTile(Point cp) { + Tile result = pointMap.get(cp); + if (result == null) { + result = altPointMap.get(cp); + } + return result; + } + + public static Tile findTile(String id) { + Tile tile = idMap.get(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 + //Logger.trace("Checking " + tile.id + " New Point (" + p.x + "," + p.y + ")"); + 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 (altPointMap.containsKey(p) && !tile.getAltPoints().contains(p)) { + return false; + } + + //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 (pointMap.containsKey(ap) && !tile.getCenter().equals(ap) && !tile.getAltPoints().contains(ap)) { + return false; + } + if (altPointMap.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 (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 pointIds + for (Point ap : rps) { + altPointMap.remove(ap); + } + //pointIds.remove(tile.getId()); + idMap.remove(tile.id); + pointMap.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); + } + } + + public static Tile rotateTile(Tile tile) { + if (!pointMap.containsKey(tile.getCenter())) { + Logger.warn("Tile " + tile.getId() + " NOT in cache!"); + } + + //Remove the alternative or extra pointIds... + for (Point ep : tile.getAltPoints()) { + altPointMap.remove(ep); + } + + tile.rotate(); + + //update + pointMap.put(tile.getCenter(), tile); + for (Point ep : tile.getAltPoints()) { + altPointMap.put(ep, tile); + } + idMap.put(tile.id, tile); + + persistTile(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 (!pointMap.containsKey(tile.getCenter())) { + Logger.warn("Tile " + tile.getId() + " NOT in cache!"); + } + + //Remove the alternative or extra pointIds... + for (Point ep : tile.getAltPoints()) { + altPointMap.remove(ep); + } + + if (horizontal) { + tile.flipHorizontal(); + } else { + tile.flipVertical(); + } + //update + pointMap.put(tile.getCenter(), tile); + for (Point ep : tile.getAltPoints()) { + altPointMap.put(ep, tile); + } + idMap.put(tile.id, tile); + + persistTile(tile); + return tile; + } + + public static void enqueTileAction(JCSActionEvent jcsEvent) { + eventsQueue.offer(jcsEvent); + synchronized (TileCache.actionEventQueueHandler) { + actionEventQueueHandler.notifyAll(); + } + } + + 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/TileFactory.java b/src/main/java/jcs/ui/layout/tiles/TileFactory.java deleted file mode 100755 index 6baece4f..00000000 --- a/src/main/java/jcs/ui/layout/tiles/TileFactory.java +++ /dev/null @@ -1,657 +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.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; -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 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; - -/** - * 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, false); - } - - public static Tile createTile(TileBean tileBean, boolean drawOutline, boolean showValues) { - if (tileBean == null) { - return null; - } - - TileBean.TileType tileType = tileBean.getTileType(); - AbstractTile 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) { - ((Switch) tile).setValue((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) { - ((Switch) tile).setValue((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 - * @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); - } - - /** - * @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 - * @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, Point center, boolean drawOutline) { - 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.setDrawOutline(drawOutline); - tile.setId(nextTileId(tileType)); - } - - addTileEventListener((TileEventListener) tile); - 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, drawOutline, 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..84900940 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/TileModel.java @@ -0,0 +1,130 @@ +/* + * 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.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; + +/** + * + * @author fransjacobs + */ +public interface TileModel extends Serializable { + + boolean isSelected(); + + public void setSelected(boolean selected); + + Color getSelectedColor(); + + public void setSelectedColor(Color selectedColor); + + boolean isScaleImage(); + + public void setScaleImage(boolean scaleImage); + + boolean isShowCenter(); + + public void setShowCenter(boolean showCenter); + + public TileBean.Orientation getTileOrienation(); + + void setTileOrienation(TileBean.Orientation tileOrienation); + + public TileBean.Orientation getIncomingSide(); + + void setIncomingSide(TileBean.Orientation incomingSide); + + boolean isShowRoute(); + + public void setShowRoute(boolean showRoute); + + boolean isShowBlockState(); + + void setBlockBean(BlockBean blockBean); + + 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); + + 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); + + 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); + + boolean isOverlayImage(); + + public void setOverlayImage(boolean overlayImage); + + // + 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/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..44d9b3b5 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/ui/BlockUI.java @@ -0,0 +1,503 @@ +/* + * 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(); + } + + 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..62848973 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/ui/CrossUI.java @@ -0,0 +1,331 @@ +/* + * 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(); + } + + public static ComponentUI createUI(JComponent c) { + return new CrossUI(); + } + + 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; + TileModel model = tile.getModel(); + AccessoryBean.AccessoryValue accessoryValue = model.getAccessoryValue(); + + 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; + } + + 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..90eec11c --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/ui/CrossingUI.java @@ -0,0 +1,103 @@ +/* + * 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.TileBean.Orientation; +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) { + 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) { + 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); + + //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); + } + + @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 new file mode 100644 index 00000000..8ceb75f5 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/ui/CurvedUI.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.ui.layout.tiles.ui; + +import java.awt.BasicStroke; +import java.awt.Graphics2D; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; + +public class CurvedUI extends TileUI { + + public CurvedUI() { + } + + public static ComponentUI createUI(JComponent c) { + return new CurvedUI(); + } + + @Override + public void renderTile(Graphics2D g2, JComponent c) { + 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) { + 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..dd84ad21 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/ui/EndUI.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; + +public class EndUI extends TileUI { + + public EndUI() { + } + + public static ComponentUI createUI(JComponent c) { + return new EndUI(); + } + + protected void renderEnd(Graphics2D g2, JComponent c) { + 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..42223e8f --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java @@ -0,0 +1,154 @@ +/* + * 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.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.event.MouseMotionListener; +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; + +public class SensorUI extends StraightUI implements MouseListener, MouseMotionListener { + + public SensorUI() { + } + + public static ComponentUI createUI(JComponent c) { + return new SensorUI(); + } + + @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); + } + + 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); + } + + @Override + public void mousePressed(MouseEvent e) { + //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()); + 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.getIdString()+" Sensor "+sb.getIdString()+" to "+sb.isActive()+"..."); + } + } else { + redispatchToParent(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() + ","); + 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); + } + + @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 new file mode 100644 index 00000000..d15db642 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/ui/SignalUI.java @@ -0,0 +1,410 @@ +/* + * 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.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; +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; +import jcs.ui.layout.tiles.TileCache; +import jcs.ui.layout.tiles.TileModel; +import org.tinylog.Logger; + +public class SignalUI extends StraightUI implements MouseListener, MouseMotionListener { + + public SignalUI() { + } + + 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 + * + * @param g2d the graphics context + * @param c + */ + protected void renderSignal2(Graphics2D g2d, JComponent c) { + Tile tile = (Tile) c; + TileModel model = tile.getModel(); + SignalValue signalValue = model.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; + TileModel model = tile.getModel(); + SignalValue signalValue = model.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; + TileModel model = tile.getModel(); + SignalValue signalValue = model.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; + 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}; + + 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(); + } + + @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/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..712fc11f --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/ui/StraightUI.java @@ -0,0 +1,67 @@ +/* + * 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.Graphics2D; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; + +public class StraightUI extends TileUI { + + public StraightUI() { + } + + public static ComponentUI createUI(JComponent c) { + return new StraightUI(); + } + + protected void renderStraight(Graphics2D g2, 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(trackColor); + + g2.fillRect(xx, yy, w, h); + } + + protected void renderRouteStraight(Graphics2D g2, JComponent c) { + 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, 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..b12cb799 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/ui/SwitchUI.java @@ -0,0 +1,230 @@ +/* + * 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.Component; +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; +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 implements MouseListener, MouseMotionListener { + + public SwitchUI() { + } + + public static ComponentUI createUI(JComponent c) { + return new SwitchUI(); + } + + @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); + } + + 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; + TileModel model = tile.getModel(); + AccessoryValue accessoryValue = model.getAccessoryValue(); + + 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(); + + if (routeValue == null) { + routeValue = AccessoryBean.AccessoryValue.OFF; + } + switch (routeValue) { + case RED -> { + renderRouteDiagonal(g2, trackRouteColor, c); + } + case GREEN -> { + renderRouteStraight(g2, trackRouteColor, c); + } + default -> { + } + } + } + + @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.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 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) { + //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); + Tile tile = (Tile) e.getSource(); + tile.setToolTipText(null); + 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 new file mode 100644 index 00000000..aa438f1c --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java @@ -0,0 +1,291 @@ +/* + * 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.Component; +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; +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; +import static jcs.ui.layout.tiles.Tile.GRID; +import jcs.ui.layout.tiles.TileModel; +import org.imgscalr.Scalr; +import org.tinylog.Logger; + +/** + * The drawing functionality of a Tile. + */ +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 = 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() && 1 == 2) { + 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()); + } + } + + protected void redispatchToParent(MouseEvent e) { + Component source = (Component) e.getSource(); + 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) { + if (c.getParent() != null && c.getParent() instanceof LayoutCanvas) { + return ((LayoutCanvas) c.getParent()).isReadonly(); + } else { + return false; + } + } + +} 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/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 67% rename from src/main/java/jcs/ui/table/DispatcherTablePanel.java rename to src/main/java/jcs/ui/panel/DispatcherTablePanel.java index 93857a8c..4783f934 100644 --- a/src/main/java/jcs/ui/table/DispatcherTablePanel.java +++ b/src/main/java/jcs/ui/panel/DispatcherTablePanel.java @@ -13,20 +13,20 @@ * 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; 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; @@ -35,23 +35,25 @@ 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 { - /** - * Creates new form LocomotiveTablePanel - */ - public DispatcherTablePanel() { + private static final long serialVersionUID = -7052304625809395213L; + + private final List locomotiveSelectionChangedListeners; + 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 }); @@ -67,23 +69,26 @@ 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 { + 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); - - 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; } } @@ -99,7 +104,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); @@ -120,25 +125,44 @@ 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); if (aFlag) { - AutoPilot.addAutoPilotStatusListener(this); + //AutoPilot.addAutoPilotStatusListener(this); statusChanged(AutoPilot.isAutoModeActive()); } else { - AutoPilot.removeAutoPilotStatusListener(this); + //AutoPilot.removeAutoPilotStatusListener(this); } } @@ -165,47 +189,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.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 70% rename from src/main/java/jcs/ui/table/LocomotiveTablePanel.java rename to src/main/java/jcs/ui/panel/LocomotiveTablePanel.java index c9a3caf1..7d8725f6 100644 --- a/src/main/java/jcs/ui/table/LocomotiveTablePanel.java +++ b/src/main/java/jcs/ui/panel/LocomotiveTablePanel.java @@ -13,20 +13,20 @@ * 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; 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,25 +36,25 @@ 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 + * Panel to show locomotives in tabular format */ public class LocomotiveTablePanel extends JPanel implements RefreshEventListener { - /** - * Creates new form LocomotiveTablePanel - */ - public LocomotiveTablePanel() { - locomotiveBeanTableModel = new LocomotiveBeanTableModel(); + private static final long serialVersionUID = 1387464111237136414L; - initComponents(); + private final List locomotiveSelectionChangedListeners; - this.locomotiveTable.setDefaultRenderer(Image.class, new LocIconRenderer()); + public LocomotiveTablePanel() { + locomotiveSelectionChangedListeners = new ArrayList<>(); - this.locomotiveTable.getRowSorter().addRowSorterListener((RowSorterEvent e) -> { + 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,29 +63,25 @@ 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(); } } @Override public void onChange(RefreshEvent event) { if ("locomotives".equals(event.getSource())) { - locomotiveBeanTableModel.refresh(); + refresh(); } } + public void refresh() { + locomotiveBeanTableModel.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); @@ -114,7 +110,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); @@ -135,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; @@ -167,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/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..ee13e0a3 --- /dev/null +++ b/src/main/java/jcs/ui/panel/SmallDriverCabPanel.form @@ -0,0 +1,1834 @@ + + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..0dca20a5 --- /dev/null +++ b/src/main/java/jcs/ui/panel/SmallDriverCabPanel.java @@ -0,0 +1,1473 @@ +/* + * 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 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.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 JPanel implements LocomotiveSelectionChangedListener, + LocomotiveDirectionEventListener, LocomotiveFunctionEventListener, LocomotiveSpeedEventListener { + + private final Map buttons; + private LocomotiveBean locomotiveBean; + private boolean initButtons = false; + private boolean disableListener = false; + private boolean power; + + private boolean enableEvent = true; + //private final ExecutorService executor; + + 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); + } + buttonsTP.setEnabled(enabled); + } + + @Override + public void onFunctionChange(LocomotiveFunctionEvent event) { + if (locomotiveBean != null && locomotiveBean.getId().equals(event.getFunctionBean().getLocomotiveId())) { + FunctionBean fb = event.getFunctionBean(); + //this.buttons.get(fb.getNumber()).setSelected(fb.isOn()); + JToggleButton tbtn = 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 : 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 Color(204, 204, 204)); + btn.setBackground(new Color(204, 204, 204)); + + btn.setSelected(false); + } + } + + @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 (selectionChanged) { + 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; + if (PersistenceFactory.getService() != null) { + //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(); + } + 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); + } + + 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 locomotive + */ + public void setLocomotiveBean(LocomotiveBean locomotive) { + selectionChanged(locomotive.getId()); + } + + 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 = locomotiveBean.getFunctionBean(functionNumber); + + if (!initButtons && enableEvent) { + Logger.trace("Function " + fb.getNumber() + " Value: " + fb.isOn() + " Momentary: " + fb.isMomentary()); + //executor.execute(() -> changeFunction(value, functionNumber, locomotiveBean)); + changeFunction(value, functionNumber, locomotiveBean); + } + } + + private void changeFunction(boolean newValue, Integer functionNumber, LocomotiveBean locomotiveBean) { + 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 = 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() { + + directionBG = new javax.swing.ButtonGroup(); + 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(); + speed3Button = new javax.swing.JButton(); + speed4Button = new javax.swing.JButton(); + jPanel4 = new javax.swing.JPanel(); + speedSlider = new javax.swing.JSlider(); + centerPanel = 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(); + + 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)); + setLayout(new java.awt.BorderLayout()); + + 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); + rightPanel.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); + + rightPanel.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)); + speedSlider.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + speedSliderStateChanged(evt); + } + }); + jPanel4.add(speedSlider); + + rightPanel.add(jPanel4); + + add(rightPanel, java.awt.BorderLayout.EAST); + + 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); + 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); + + centerPanel.add(buttonsTP); + + southPanel.setMinimumSize(new java.awt.Dimension(300, 50)); + southPanel.setName("southPanel"); // NOI18N + 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 + 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); + + directionBG.add(forwardButton); + 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); + + centerPanel.add(southPanel); + + add(centerPanel, 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 (locomotiveBean != null) { + int tachoMax = locomotiveBean.getTachoMax(); + tachoMax = tachoMax / 5; // 20 % + 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 (locomotiveBean != null) { + int tachoMax = locomotiveBean.getTachoMax(); + tachoMax = (tachoMax / 5) * 2; // 40 % + 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 (locomotiveBean != null) { + int tachoMax = locomotiveBean.getTachoMax(); + tachoMax = (tachoMax / 5) * 3; // 60 % + 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 (locomotiveBean != null) { + int tachoMax = locomotiveBean.getTachoMax(); + tachoMax = (tachoMax / 5) * 4; // 80 % + 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 + 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()) { + Logger.trace("Change speed of "); + 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)); + Logger.trace("Changing speed to "+velocity+" for "+locomotiveBean.getId()); + + 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); + } + + 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); +// } + } + + /** + * Called when the direction is changed from external source + * + * @param event + */ + @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 " + locomotiveBean.getDirection() + " to " + lb.getDirection()); + + locomotiveBean.setDirection(lb.getDirection()); + + //Disable the direction buttons so that the change does not retrigger the commandstation + disableListener = true; + reverseButton.setSelected(LocomotiveBean.Direction.BACKWARDS == lb.getDirection()); + forwardButton.setSelected(LocomotiveBean.Direction.FORWARDS == lb.getDirection()); + disableListener = false; + } + } + + @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()); + + 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 = speedSlider.getChangeListeners(); + for (ChangeListener changeListener : changeListeners) { + speedSlider.removeChangeListener(changeListener); + } + + speedSlider.setValue(sliderValue); + + disableListener = false; + for (ChangeListener changeListener : changeListeners) { + speedSlider.addChangeListener(changeListener); + } + + } + } + + 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); + } + + 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); + } + }); + + SmallDriverCabPanel testPanel = new SmallDriverCabPanel(); + + testFrame.add(testPanel); + + if (JCS.getJcsCommandStation() != null) { + //LocomotiveBean loc = PersistenceFactory.getService().getLocomotive(16417L); + LocomotiveBean loc = PersistenceFactory.getService().getLocomotive(1000L); + Logger.debug(loc); + + testPanel.setLocomotiveBean(loc); + } + + testFrame.pack(); + testFrame.setLocationRelativeTo(null); + + testFrame.setVisible(true); + }); + } + + + // 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; + 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.Box.Filler filler2; + javax.swing.JToggleButton forwardButton; + 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; + 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/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/options/CommandStationDialog.java b/src/main/java/jcs/ui/settings/AccessoryDialog.java similarity index 55% rename from src/main/java/jcs/ui/options/CommandStationDialog.java rename to src/main/java/jcs/ui/settings/AccessoryDialog.java index 9f77230b..d10f786e 100644 --- a/src/main/java/jcs/ui/options/CommandStationDialog.java +++ b/src/main/java/jcs/ui/settings/AccessoryDialog.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 frans. + * 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,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; @@ -21,14 +21,16 @@ /** * - * @author frans + * @author fransjacobs */ -public class CommandStationDialog extends javax.swing.JDialog { +public class AccessoryDialog extends javax.swing.JDialog { + + private static final long serialVersionUID = 1666127249735678517L; /** - * Creates new form CommandStationDialog + * Creates new form AccessoryDialog */ - public CommandStationDialog(java.awt.Frame parent, boolean modal) { + public AccessoryDialog(java.awt.Frame parent, boolean modal) { super(parent, modal); initComponents(); } @@ -40,67 +42,45 @@ public CommandStationDialog(java.awt.Frame parent, boolean modal) { // //GEN-BEGIN:initComponents private void initComponents() { - commandStationPanel1 = new jcs.ui.options.CommandStationPanel(); - southPanel = new javax.swing.JPanel(); - exitBtn = new javax.swing.JButton(); + accessorySettingsPanel1 = new jcs.ui.settings.AccessorySettingsPanel(); 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); + getContentPane().add(accessorySettingsPanel1, java.awt.BorderLayout.CENTER); 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 - /** * @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(() -> { - CommandStationDialog dialog = new CommandStationDialog(new javax.swing.JFrame(), true); + 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.setLocationRelativeTo(null); + dialog.setTitle("Accessory Settings"); dialog.pack(); + dialog.setLocationRelativeTo(null); + dialog.setVisible(true); }); } // Variables declaration - do not modify//GEN-BEGIN:variables - private jcs.ui.options.CommandStationPanel commandStationPanel1; - private javax.swing.JButton exitBtn; - private javax.swing.JPanel southPanel; + 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 97% rename from src/main/java/jcs/ui/options/AccessoryPreferencesPanel.java rename to src/main/java/jcs/ui/settings/AccessorySettingsPanel.java index e471fe15..3f14e8ee 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; @@ -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; @@ -82,7 +79,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 +94,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 +165,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 +206,6 @@ private void setFieldValues() { selectedAccessory.setSource("Manual Inserted"); } - //String commandStationId = selectedAccessory.getCommandStationId(); boolean synch = selectedAccessory.isSynchronize(); synchronizeCB.setSelected(synch); } else { @@ -987,6 +984,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; @@ -1207,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(() -> { - - AccessoryPreferencesPanel testPanel = new AccessoryPreferencesPanel(); - 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/CommandStationDialog.form b/src/main/java/jcs/ui/settings/CommandStationDialog.form new file mode 100644 index 00000000..17426a57 --- /dev/null +++ b/src/main/java/jcs/ui/settings/CommandStationDialog.form @@ -0,0 +1,1164 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/jcs/ui/settings/CommandStationDialog.java b/src/main/java/jcs/ui/settings/CommandStationDialog.java new file mode 100644 index 00000000..8f93c6de --- /dev/null +++ b/src/main/java/jcs/ui/settings/CommandStationDialog.java @@ -0,0 +1,1148 @@ +/* + * 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.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 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; + +/** + * + * @author fransjacobs + */ +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 DecoderController controller; + + /** + * 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() { + + 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(CommandStationBean.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 (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) { + 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(() -> { + CommandStationDialog dialog = new CommandStationDialog(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.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/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 94% rename from src/main/java/jcs/ui/options/CommandStationPanel.java rename to src/main/java/jcs/ui/settings/CommandStationPanel.java index ed397e5a..74edc708 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; @@ -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; @@ -60,7 +56,7 @@ import jcs.entities.CommandStationBean; import jcs.entities.CommandStationBean.ConnectionType; import jcs.entities.CommandStationBean.Protocol; -import jcs.commandStation.entities.DeviceBean; +import jcs.commandStation.entities.FeedbackModule; import jcs.persistence.PersistenceFactory; import jcs.ui.swing.layout.VerticalFlowLayout; import jcs.util.Ping; @@ -93,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(); @@ -100,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); @@ -110,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(); @@ -1178,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 @@ -1284,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(); @@ -1372,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 (FeedbackModule fm : feedbackModules) { + PersistenceFactory.getService().persistSensorBeans(fm.getSensors()); + } + } } @Override @@ -1463,59 +1463,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.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); + 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) { @@ -1540,6 +1551,7 @@ public Void doInBackground() { setProgress(100); } } + case SERIAL -> { String commPort = selectedCommandStation.getSerialPort(); setProgress(10); @@ -1581,35 +1593,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/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 96% rename from src/main/java/jcs/ui/options/LocomotivePreferencesPanel.java rename to src/main/java/jcs/ui/settings/LocomotiveSettingsPanel.java index 512f11bf..fccb6019 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; @@ -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,16 +65,12 @@ 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; 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 +83,9 @@ /** * 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; private final LocomotiveBeanListModel locoListModel; private CommandStationBean commandStationBean; @@ -97,7 +94,7 @@ public class LocomotivePreferencesPanel extends JPanel implements PropertyChange private SynchronizationTask task; - public LocomotivePreferencesPanel() { + public LocomotiveSettingsPanel() { locoListModel = new LocomotiveBeanListModel(); decoderTypes = new DefaultComboBoxModel(DecoderType.values()); @@ -727,8 +724,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 @@ -940,6 +936,8 @@ public int compare(LocomotiveBean a, LocomotiveBean b) { class LocomotiveBeanListModel extends AbstractListModel { + private static final long serialVersionUID = -2632478289320377224L; + private final List model; public LocomotiveBeanListModel() { @@ -1148,8 +1146,7 @@ public Void doInBackground() { setProgress((int) progress); } - JCS.settingsChanged(new RefreshEvent("locomotives")); - + //JCS.settingsChanged(new RefreshEvent("locomotives")); firePropertyChange("done", "", "Locomotives Synchronized"); return null; @@ -1163,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(() -> { - - LocomotivePreferencesPanel testPanel = new LocomotivePreferencesPanel(); - 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 new file mode 100644 index 00000000..223f99ee --- /dev/null +++ b/src/main/java/jcs/ui/settings/PropertiesDialog.form @@ -0,0 +1,35 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..0f0d7bc5 --- /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() { + + propertySettingsPanel = new jcs.ui.settings.PropertySettingsPanel(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + setTitle("Properties"); + getContentPane().add(propertySettingsPanel, 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.pack(); + dialog.setLocationRelativeTo(null); + + dialog.setVisible(true); + }); + } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private jcs.ui.settings.PropertySettingsPanel propertySettingsPanel; + // 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..6d58db16 --- /dev/null +++ b/src/main/java/jcs/ui/settings/PropertySettingsPanel.java @@ -0,0 +1,249 @@ +/* + * 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.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.ListSelectionModel; +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 + + + // 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/OptionDialog.form b/src/main/java/jcs/ui/settings/SettingsDialog.form similarity index 63% rename from src/main/java/jcs/ui/options/OptionDialog.form rename to src/main/java/jcs/ui/settings/SettingsDialog.form index c35baaa1..929e22bb 100755 --- a/src/main/java/jcs/ui/options/OptionDialog.form +++ b/src/main/java/jcs/ui/settings/SettingsDialog.form @@ -3,15 +3,12 @@
- + - - - @@ -27,29 +24,11 @@ - + - - - - - - - - - - - - - - - - - - @@ -65,15 +44,15 @@ - + - + - + @@ -83,43 +62,43 @@ - + - + - - + + - + - + - - + + - + - + - - + + - + @@ -135,42 +114,5 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/main/java/jcs/ui/options/OptionDialog.java b/src/main/java/jcs/ui/settings/SettingsDialog.java similarity index 56% rename from src/main/java/jcs/ui/options/OptionDialog.java rename to src/main/java/jcs/ui/settings/SettingsDialog.java index 4970d092..bb7fd0e5 100755 --- a/src/main/java/jcs/ui/options/OptionDialog.java +++ b/src/main/java/jcs/ui/settings/SettingsDialog.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; @@ -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,129 +62,99 @@ private void init() { // //GEN-BEGIN:initComponents private void initComponents() { - topPanel = new JPanel(); centerPanel = new JPanel(); - prefsTP = new JTabbedPane(); + dialogTP = new JTabbedPane(); + locomotivePanel = new LocomotiveSettingsPanel(); + accessoryPreferencesPanel = new AccessorySettingsPanel(); commandStationPanel = new CommandStationPanel(); - locomotivePanel = new LocomotivePreferencesPanel(); - accessoryPreferencesPanel = new AccessoryPreferencesPanel(); - propertiesPanel = new PropertiesPanel(); - southPanel = new JPanel(); - closeBtn = new JButton(); + propertiesPanel = new PropertySettingsPanel(); 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 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(); } 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); }); } // 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 JTabbedPane prefsTP; - private PropertiesPanel propertiesPanel; - private JPanel southPanel; - private JPanel topPanel; + private JTabbedPane dialogTP; + private LocomotiveSettingsPanel locomotivePanel; + private PropertySettingsPanel propertiesPanel; // 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 95% rename from src/main/java/jcs/ui/options/table/SensorTableModel.java rename to src/main/java/jcs/ui/settings/table/SensorTableModel.java index af7aca97..231ae4d8 100644 --- a/src/main/java/jcs/ui/options/table/SensorTableModel.java +++ b/src/main/java/jcs/ui/settings/table/SensorTableModel.java @@ -13,9 +13,8 @@ * 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; 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/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; 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; - } - -} 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/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/FrameMonitor.java b/src/main/java/jcs/ui/util/FrameMonitor.java index 9d147899..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; @@ -49,10 +50,14 @@ 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)); - 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)); @@ -69,23 +74,85 @@ 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; + } + 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 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 getFrameSize(Preferences pref, int defaultW, int defaultH) { + 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/layout/events/TileEventListener.java b/src/main/java/jcs/ui/util/LocomotiveSelectionChangedListener.java similarity index 77% rename from src/main/java/jcs/ui/layout/events/TileEventListener.java rename to src/main/java/jcs/ui/util/LocomotiveSelectionChangedListener.java index 94480bb3..f3fb3033 100644 --- a/src/main/java/jcs/ui/layout/events/TileEventListener.java +++ b/src/main/java/jcs/ui/util/LocomotiveSelectionChangedListener.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. @@ -13,12 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package jcs.ui.layout.events; +package jcs.ui.util; -public interface TileEventListener { - - String getId(); +/** + * + */ +public interface LocomotiveSelectionChangedListener { - void onTileChange(TileEvent tileEvent); + void selectionChanged(Long locomotiveId); } 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); - } - } - -} 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++)); 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); 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 00000000..b850cfba Binary files /dev/null and b/src/main/resources/media/arrowhead-right-gn.png differ diff --git a/src/main/resources/media/branch-24.png b/src/main/resources/media/branch-24.png new file mode 100755 index 00000000..30433dbb Binary files /dev/null and b/src/main/resources/media/branch-24.png differ diff --git a/src/main/resources/media/chat-24.png b/src/main/resources/media/chat-24.png new file mode 100755 index 00000000..0896da08 Binary files /dev/null and b/src/main/resources/media/chat-24.png differ diff --git a/src/main/resources/media/controller-24.png b/src/main/resources/media/controller-24.png old mode 100755 new mode 100644 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 00000000..8a615889 Binary files /dev/null and b/src/main/resources/media/controller-console-24.png differ diff --git a/src/main/resources/media/pause-gr.png b/src/main/resources/media/pause-gr.png new file mode 100755 index 00000000..23677992 Binary files /dev/null and b/src/main/resources/media/pause-gr.png differ diff --git a/src/main/resources/media/reset-happy.png b/src/main/resources/media/reset-happy.png new file mode 100755 index 00000000..3ec82eea Binary files /dev/null and b/src/main/resources/media/reset-happy.png differ diff --git a/src/main/resources/media/spanner-24.png b/src/main/resources/media/spanner-24.png new file mode 100755 index 00000000..d89617df Binary files /dev/null and b/src/main/resources/media/spanner-24.png differ 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 00000000..c4f61f3a Binary files /dev/null and b/src/main/resources/media/train-controller-24.png differ diff --git a/src/main/resources/tinylog-dev.properties b/src/main/resources/tinylog-dev.properties index b34fb2d8..0766ee23 100755 --- a/src/main/resources/tinylog-dev.properties +++ b/src/main/resources/tinylog-dev.properties @@ -34,6 +34,7 @@ writer2.backups = 10 exception = strip: jdk.internal - -level@jcs.controller.cs3 = debug -#level@jcs.ui.layout.LayoutCanvas = debug \ No newline at end of file +level@jcs.util = info +#level@jcs.commandStation = debug +#level@jcs.ui.layout = info +level@jcs.commandStation.esu.ecos.EcosMessage = info \ No newline at end of file diff --git a/src/main/resources/tinylog.properties b/src/main/resources/tinylog.properties index 653e7f58..50d15434 100755 --- a/src/main/resources/tinylog.properties +++ b/src/main/resources/tinylog.properties @@ -33,5 +33,7 @@ writer2.backups = 10 exception = strip: jdk.internal -level@jcs.controller.cs3 = debug -#level@jcs.ui.layout.LayoutCanvas = debug \ No newline at end of file +level@jcs.util = info +#level@jcs.commandStation = debug +#level@jcs.ui.layout = info +level@jcs.commandStation.esu.ecos.EcosMessage = info \ No newline at end of file diff --git a/src/main/resources/update-jcs-db-002.sql b/src/main/resources/update-jcs-db-002.sql index 29818716..d05c1091 100644 --- a/src/main/resources/update-jcs-db-002.sql +++ b/src/main/resources/update-jcs-db-002.sql @@ -9,5 +9,27 @@ 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 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; +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 930856ec..ad4cd0a2 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; @@ -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(); @@ -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; @@ -199,7 +199,7 @@ public void testStartStopAutoModeDispatcherstNotRunning() { Logger.debug("Autopilot automode started in " + (now - start) + " ms."); - assertFalse(AutoPilot.areDispatchersRunning()); + assertFalse(AutoPilot.isADispatcherRunning()); //Lets create a dispatcher. A Loc must be on the track LocomotiveBean dhg = ps.getLocomotive(NS_DHG_6505); @@ -262,7 +262,7 @@ public void testStartStopAutoModeDispatcherRunning() { Logger.debug("Autopilot automode started in " + (now - start) + " ms."); - assertFalse(AutoPilot.areDispatchersRunning()); + assertFalse(AutoPilot.isADispatcherRunning()); //Lets create a dispatcher. A Loc must be on the track LocomotiveBean dhg = ps.getLocomotive(NS_DHG_6505); @@ -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()); @@ -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()); @@ -431,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()); @@ -479,7 +480,7 @@ public void testGetLocomotiveDispatchers() { List dispList = AutoPilot.getLocomotiveDispatchers(); assertEquals(1, dispList.size()); - assertFalse(AutoPilot.areDispatchersRunning()); + assertFalse(AutoPilot.isADispatcherRunning()); AutoPilot.stopAutoMode(); //let the autopilot finish... @@ -541,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."); } @@ -584,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.getSensorId())) { 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 1aa92a52..abde0114 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"); @@ -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; @@ -179,7 +179,7 @@ private void pause(int millis) { } } - //@Test + @Test @Order(1) public void testBk1ToBk4() { //StateMachine functionality test, runs in 1 single thread. @@ -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(); @@ -277,8 +277,8 @@ public void testBk1ToBk4() { assertEquals("StartState", stateMachine.getDispatcherStateName()); //Now lets Toggle the enter sensor - String enterSensorId = dispatcher.getEnterSensorId(); - assertEquals("0-0013", enterSensorId); + Integer enterSensorId = dispatcher.getEnterSensorId(); + assertEquals(13, enterSensorId); //Check if the enterSensor is registered a a "knownEvent" else we get a Ghost! assertTrue(AutoPilot.isSensorHandlerRegistered(enterSensorId)); @@ -311,8 +311,8 @@ public void testBk1ToBk4() { assertEquals("EnterBlockState", stateMachine.getDispatcherStateName()); //Now lets Toggle the in sensor - String inSensorId = dispatcher.getInSensorId(); - assertEquals("0-0012", inSensorId); + Integer inSensorId = dispatcher.getInSensorId(); + 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"); @@ -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(); @@ -443,20 +443,20 @@ 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); 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()); @@ -695,7 +695,7 @@ public void testFromBk1ToBk4andViceVersa() { //Automode OFF! stateMachine.setEnableAutomode(false); - assertFalse(stateMachine.isEnableAutomode()); + assertFalse(stateMachine.isAutomodeEnabled()); //Execute the WaitState stateMachine.handleState(); @@ -703,6 +703,7 @@ public void testFromBk1ToBk4andViceVersa() { assertEquals("IdleState", stateMachine.getDispatcherStateName()); } + //TODO !!!!!! //@Test @Order(3) public void testFromBk1ToBk4Gost() { @@ -722,7 +723,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 +733,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 +744,7 @@ public void testFromBk1ToBk4Gost() { //Departure //Automode should be enabled stateMachine.setEnableAutomode(true); - assertTrue(stateMachine.isEnableAutomode()); + assertTrue(stateMachine.isAutomodeEnabled()); //Execute IdleState again stateMachine.handleState(); @@ -800,8 +801,8 @@ public void testFromBk1ToBk4Gost() { //Now lets Toggle and 'unexpected' sensor, which should cause a Ghost! assertTrue(JCS.getJcsCommandStation().isPowerOn()); - String inSensorId = dispatcher.getInSensorId(); - assertNotEquals("0-0013", inSensorId); + Integer inSensorId = dispatcher.getInSensorId(); + assertNotEquals(13, inSensorId); //Check if the enterSensor is registered a a "knownEvent" else we get a Ghost! assertFalse(AutoPilot.isSensorHandlerRegistered(inSensorId)); @@ -839,7 +840,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 +850,7 @@ public void testReset() { assertNull(dispatcher.getRouteBean()); assertFalse(instance.isThreadRunning()); - assertFalse(instance.isEnableAutomode()); + assertFalse(instance.isAutomodeEnabled()); assertEquals("IdleState", instance.getDispatcherStateName()); //Execute IdleState @@ -872,7 +873,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 +966,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..3224e5fa 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; @@ -57,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"); @@ -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; @@ -187,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); } @@ -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; @@ -339,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); @@ -375,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 @@ -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) { @@ -651,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); @@ -675,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(); @@ -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; 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/entities/FeedbackModuleTest.java b/src/test/java/jcs/commandStation/entities/FeedbackModuleTest.java new file mode 100644 index 00000000..f6f68cfc --- /dev/null +++ b/src/test/java/jcs/commandStation/entities/FeedbackModuleTest.java @@ -0,0 +1,338 @@ +/* + * 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.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 FeedbackModuleTest { + + public FeedbackModuleTest() { + } + + @BeforeEach + public void setUp() { + } + + @AfterEach + public void tearDown() { + } + + @Test + public void testGetId() { + System.out.println("getId"); + FeedbackModule instance = new FeedbackModule(); + instance.setId(0); + Integer expResult = 0; + + Integer result = instance.getId(); + assertEquals(expResult, result); + } + + @Test + public void testGetModuleNumber() { + System.out.println("getModuleNumber"); + FeedbackModule instance = new FeedbackModule(); + instance.setId(0); + instance.setModuleNumber(1); + Integer expResult = 1; + Integer result = instance.getModuleNumber(); + assertEquals(expResult, result); + } + + @Test + public void testGetPortCount() { + System.out.println("getPortCount"); + FeedbackModule instance = new FeedbackModule(); + instance.setId(0); + instance.setModuleNumber(0); + instance.setPortCount(16); + Integer expResult = 16; + Integer result = instance.getPortCount(); + assertEquals(expResult, result); + } + + @Test + public void testGetAddressOffset() { + System.out.println("getAddressOffset"); + FeedbackModule instance = new FeedbackModule(); + instance.setId(0); + instance.setModuleNumber(0); + instance.setPortCount(16); + instance.setAddressOffset(1000); + Integer expResult = 1000; + Integer result = instance.getAddressOffset(); + assertEquals(expResult, result); + } + + @Test + public void testGetIdentifier() { + System.out.println("getIdentifier"); + FeedbackModule instance = new FeedbackModule(); + 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); + } + + @Test + public void testGetPorts() { + System.out.println("getPorts"); + FeedbackModule instance = new FeedbackModule(); + 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); + } + + @Test + public void testSetPortValue() { + System.out.println("setPortValue"); + int port = 3; + boolean active = true; + FeedbackModule instance = new FeedbackModule(); + instance.setId(0); + instance.setModuleNumber(0); + instance.setPortCount(16); + instance.setAddressOffset(1000); + instance.setIdentifier(65); + + instance.setPortValue(port, active); + + int[] expResult = new int[16]; + expResult[3] = 1; + + int[] result = instance.getPorts(); + assertArrayEquals(expResult, result); + } + + @Test + public void testIsPort() { + System.out.println("isPort"); + int port = 6; + FeedbackModule instance = new FeedbackModule(); + 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"); + FeedbackModule instance = new FeedbackModule(); + 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); + } + + @Test + public void testGetPrevPorts() { + System.out.println("getPrevPorts"); + FeedbackModule instance = new FeedbackModule(); + instance.setId(0); + instance.setModuleNumber(0); + instance.setPortCount(16); + instance.setAddressOffset(1000); + instance.setIdentifier(65); + + 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 + public void testGetSensorMarklin() { + System.out.println("getSensorMarklin"); + int port = 1; + FeedbackModule instance = new FeedbackModule(); + instance.setCommandStationId("marklin.cs"); + instance.setId(0); + instance.setModuleNumber(1); + instance.setPortCount(16); + instance.setAddressOffset(1000); + instance.setIdentifier(65); + instance.setBusNumber(1); + + SensorBean expResult = new SensorBean(); + expResult.setId(1001); + + expResult.setCommandStationId("marklin.cs"); + expResult.setContactId(2); + expResult.setDeviceId(1); + expResult.setNodeId(65); + expResult.setStatus(0); + expResult.setPreviousStatus(0); + expResult.setName("B1-M01-C02"); + expResult.setBusNr(1); + + SensorBean result = instance.getSensor(port); +//expected: +// but was: + + assertEquals(expResult, result); + } + + @Test + public void testGetSensorEsu() { + System.out.println("getSensorEsu"); + int port = 5; + FeedbackModule instance = new FeedbackModule(); + instance.setCommandStationId("esu-ecos"); + instance.setId(101); + instance.setModuleNumber(2); + instance.setPortCount(16); + instance.setAddressOffset(0); + instance.setIdentifier(null); + instance.setPortValue(5, true); + + SensorBean expResult = new SensorBean(); + expResult.setId(21); + expResult.setCommandStationId("esu-ecos"); + expResult.setContactId(6); + expResult.setDeviceId(2); + expResult.setNodeId(null); + expResult.setStatus(1); + expResult.setPreviousStatus(0); + expResult.setName("M02-C06"); + + SensorBean result = instance.getSensor(port); + assertEquals(expResult, result); + } + + @Test + public void testGetSensors() { + System.out.println("getSensors"); + FeedbackModule instance = new FeedbackModule(); + instance.setCommandStationId("esu-ecos"); + instance.setId(102); + instance.setIdentifier(0); + instance.setModuleNumber(2); + instance.setPortCount(FeedbackModule.DEFAULT_PORT_COUNT); + instance.setAddressOffset(0); + + List expResult = new ArrayList<>(); + + for (int i = 0; i < FeedbackModule.DEFAULT_PORT_COUNT; i++) { + SensorBean sb = new SensorBean(); + 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 + 1))); + expResult.add(sb); + } + + List result = instance.getSensors(); + + assertEquals(expResult, result); + } + + @Test + public void testGetChangedSensors() { + System.out.println("getChangedSensors"); + int port = 5; + + FeedbackModule instance = new FeedbackModule(); + instance.setCommandStationId("esu-ecos"); + instance.setId(100); + instance.setIdentifier(0); + instance.setModuleNumber(1); + instance.setPortCount(FeedbackModule.DEFAULT_PORT_COUNT); + instance.setAddressOffset(0); + + List expResult = new ArrayList<>(); + List result = instance.getChangedSensors(); + + assertEquals(expResult, result); + + instance.setPortValue(port, true); + + result = instance.getChangedSensors(); + + SensorBean expChangedResult = new SensorBean(); + + expChangedResult.setId(5); + expChangedResult.setCommandStationId("esu-ecos"); + expChangedResult.setContactId(6); + expChangedResult.setDeviceId(1); + expChangedResult.setNodeId(0); + expChangedResult.setStatus(1); + expChangedResult.setPreviousStatus(0); + 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/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 b66b492a..477952c9 100644 --- a/src/test/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImplTest.java +++ b/src/test/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImplTest.java @@ -15,20 +15,15 @@ */ package jcs.commandStation.esu.ecos; -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; -import jcs.entities.ChannelBean; 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; 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; @@ -48,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(); @@ -73,6 +68,7 @@ public void tearDown() { } private CommandStationBean getEcosAsDefaultCommandStationBean() { + CommandStationBean ecosCommandStationBean = PersistenceFactory.getService().getDefaultCommandStation(); if (ecosCommandStationBean == null) { @@ -140,53 +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(); - assertEquals(expResult, result); - } - } - - /** - * 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 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(); + +//expected: +// but was: + + assertEquals(expResult, result); } } @@ -325,12 +283,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."); } @@ -341,13 +301,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."); } @@ -387,32 +348,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. */ @@ -423,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 a5799bed..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; @@ -28,6 +28,7 @@ public class FeedbackManagerTest { public FeedbackManagerTest() { + System.setProperty("persistenceService", "jcs.persistence.TestH2PersistenceService"); } @BeforeEach @@ -150,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/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/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/MarklinCSTest.java b/src/test/java/jcs/commandStation/marklin/cs/MarklinCSTest.java index b9a7f20c..acbda537 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; @@ -35,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"); @@ -58,10 +59,11 @@ public MarklinCSTest() { csb.setProtocols("DCC,MFX,MM"); csb.setDefault(true); csb.setEnabled(true); + csb.setVirtual(true); instance = new MarklinCentralStationImpl(csb, false); - pause(500); - csAvailable = instance.connect(); + pause(200); + csAvailable = false; //instance.connect(); if (csAvailable) { instance.disconnect(); @@ -77,7 +79,7 @@ public MarklinCSTest() { @Before public void setUp() { if (csAvailable) { - pause(500); + pause(200); } else { Logger.warn("Skipping tests CS not available"); } @@ -166,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/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/AccessoryMessageTest.java b/src/test/java/jcs/commandStation/marklin/cs/can/parser/AccessoryMessageTest.java new file mode 100644 index 00000000..609c0d53 --- /dev/null +++ b/src/test/java/jcs/commandStation/marklin/cs/can/parser/AccessoryMessageTest.java @@ -0,0 +1,55 @@ +/* + * 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 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."); + } + +} 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..d13f466c --- /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); + } + +} 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 b338a8f6..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(); - 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(); - 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; - HTTPConnection expResult = null; - HTTPConnection 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."); - } - - /** - * Test of getHTTPConnection method, of class CSConnectionFactory. - */ - //@Test - public void testGetHTTPConnection() { - System.out.println("getHTTPConnection"); - HTTPConnection expResult = null; - HTTPConnection 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."); - } - - /** - * 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."); - } - -} diff --git a/src/test/java/jcs/commandStation/marklin/cs3/can/parser/ChannelDataParserTest.java b/src/test/java/jcs/commandStation/marklin/cs3/can/parser/ChannelDataParserTest.java deleted file mode 100644 index fe620698..00000000 --- a/src/test/java/jcs/commandStation/marklin/cs3/can/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.cs3.can.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/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/parser/CanDeviceParserTest.java b/src/test/java/jcs/commandStation/marklin/parser/CanDeviceParserTest.java new file mode 100644 index 00000000..5679b71a --- /dev/null +++ b/src/test/java/jcs/commandStation/marklin/parser/CanDeviceParserTest.java @@ -0,0 +1,320 @@ +/* + * 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.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 static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import org.junit.Test; + +/** + * + */ +public class CanDeviceParserTest { + + public CanDeviceParserTest() { + } + + private CanMessage getMemberPing() { + CanMessage ping = CanMessage.parse("0x00 0x30 0x07 0x69 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00"); + ping.addResponse(CanMessage.parse("0x00 0x31 0x37 0x7e 0x08 0x63 0x73 0x45 0x8d 0x02 0x05 0xff 0xff")); + ping.addResponse(CanMessage.parse("0x00 0x31 0x7b 0x79 0x08 0x53 0x38 0x5c 0x41 0x01 0x01 0x00 0x40")); + ping.addResponse(CanMessage.parse("0x00 0x31 0x03 0x26 0x08 0x63 0x73 0x45 0x8c 0x0c 0x71 0x00 0x50")); + return ping; + } + + @Test + public void testParseMemberPingMessage() { + System.out.println("parseMemberPingMessage"); + CanMessage memberPingmessage = getMemberPing(); + List expResult = new ArrayList<>(); + + CanDevice cs = new CanDevice(); + cs.setUid("0x6373458d"); + cs.setIdentifier("0xffff"); + cs.setVersion("2.5"); + expResult.add(cs); + + CanDevice linkS88 = new CanDevice(); + linkS88.setUid("0x53385c41"); + linkS88.setIdentifier("0x40"); + linkS88.setVersion("1.1"); + expResult.add(linkS88); + + CanDevice gfp = new CanDevice(); + gfp.setUid("0x6373458c"); + gfp.setIdentifier("0x50"); + gfp.setVersion("12.113"); + expResult.add(gfp); + + List result = CanDeviceParser.parse(memberPingmessage); + + assertEquals(expResult, result); + } + + private CanMessage getStatusDataConfigGFPIndex0() { + CanMessage statusDataConfig = CanMessage.parse("0x00 0x3a 0x37 0x7f 0x05 0x63 0x73 0x45 0x8c 0x00 0x00 0x00 0x00"); + statusDataConfig.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x01 0x08 0x04 0x02 0x00 0x00 0x00 0x00 0x09 0x46")); + statusDataConfig.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x02 0x08 0x36 0x30 0x32 0x32 0x36 0x00 0x00 0x00")); + statusDataConfig.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x03 0x08 0x43 0x65 0x6e 0x74 0x72 0x61 0x6c 0x20")); + statusDataConfig.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x04 0x08 0x53 0x74 0x61 0x74 0x69 0x6f 0x6e 0x20")); + statusDataConfig.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x05 0x08 0x33 0x00 0x00 0x00 0x00 0x00 0x00 0x00")); + statusDataConfig.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x26 0x06 0x63 0x73 0x45 0x8c 0x00 0x05 0x00 0x00")); + return statusDataConfig; + } + + @Test + public void testParseStatusDataConfigGFPIndex0() { + System.out.println("parseStatusDataConfigGFPIndex0"); + CanDevice canDevice = new CanDevice(); + canDevice.setUid("0x6373458c"); + canDevice.setIdentifier("0x50"); + canDevice.setVersion("12.113"); + + CanMessage statusConfigmessage = getStatusDataConfigGFPIndex0(); + CanDevice expResult = new CanDevice(); + expResult.setUid("0x6373458c"); + expResult.setIdentifier("0x50"); + expResult.setVersion("12.113"); + expResult.setName("Central Station 3"); + expResult.setArticleNumber("60226"); + expResult.setMeasureChannelCount(4); + expResult.setConfigChannelCount(2); + expResult.setSerial(2374); + + CanDeviceParser.parse(canDevice, statusConfigmessage); + CanDevice result = canDevice; + assertEquals(expResult, result); + } + + private CanMessage getStatusDataConfigGFPIndex1() { + CanMessage statusDataConfig = CanMessage.parse("0x00 0x3a 0x37 0x7f 0x05 0x63 0x73 0x45 0x8c 0x01 0x00 0x00 0x00"); + statusDataConfig.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x01 0x08 0x01 0xfd 0x30 0xf0 0xe0 0xc0 0x00 0x00")); + statusDataConfig.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x02 0x08 0x02 0x28 0x02 0x40 0x02 0x58 0x02 0x94")); + statusDataConfig.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x03 0x08 0x4d 0x41 0x49 0x4e 0x00 0x30 0x2e 0x30")); + statusDataConfig.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x04 0x08 0x30 0x00 0x35 0x2e 0x35 0x30 0x00 0x41")); + statusDataConfig.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x05 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00")); + statusDataConfig.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x26 0x06 0x63 0x73 0x45 0x8c 0x01 0x05 0x00 0x00")); + return statusDataConfig; + } + + @Test + public void testParseStatusDataConfigGFPIndex1() { + System.out.println("parseStatusDataConfigGFPIndex1"); + CanDevice canDevice = new CanDevice(); + canDevice.setUid("0x6373458c"); + canDevice.setIdentifier("0x50"); + canDevice.setVersion("12.113"); + canDevice.setName("Central Station 3"); + canDevice.setArticleNumber("60226"); + canDevice.setMeasureChannelCount(4); + canDevice.setConfigChannelCount(2); + + CanMessage statusConfigmessage = getStatusDataConfigGFPIndex1(); + CanDeviceParser.parse(canDevice, statusConfigmessage); + + CanDevice expDeviceResult = new CanDevice(); + expDeviceResult.setUid("0x6373458c"); + expDeviceResult.setIdentifier("0x50"); + expDeviceResult.setVersion("12.113"); + expDeviceResult.setName("Central Station 3"); + expDeviceResult.setArticleNumber("60226"); + expDeviceResult.setMeasureChannelCount(4); + expDeviceResult.setConfigChannelCount(2); + + MeasuringChannel result = canDevice.getMeasuringChannel(1); + assertNotNull(result); + + MeasuringChannel expResult = new MeasuringChannel(); + expResult.setNumber(1); + expResult.setName("MAIN"); + expResult.setScale(-3); + expResult.setColorGreen(48); + expResult.setColorYellow(240); + expResult.setColorRed(224); + expResult.setColorMax(192); + expResult.setZeroPoint(0); + expResult.setRangeGreen(552); + expResult.setRangeYellow(576); + expResult.setRangeRed(576); + expResult.setRangeMax(660); + expResult.setStartValue(0.0); + expResult.setEndValue(5.5); + expResult.setUnit("A"); + + expDeviceResult.addMeasuringChannel(expResult); + + assertEquals(expDeviceResult, canDevice); + assertEquals(expResult, result); + } + + private CanMessage getStatusDataConfigLinkS88Index0() { + CanMessage statusDataConfig = CanMessage.parse("0x00 0x3a 0x7b 0x79 0x05 0x53 0x38 0x5c 0x41 0x00 0x00 0x00 0x00"); + statusDataConfig.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x01 0x08 0x00 0x0c 0x00 0x00 0x00 0x00 0x24 0x41")); + statusDataConfig.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x02 0x08 0x36 0x30 0x38 0x38 0x33 0x00 0x00 0x00")); + statusDataConfig.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x03 0x08 0x4c 0x69 0x6e 0x6b 0x20 0x53 0x38 0x38")); + statusDataConfig.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x04 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00")); + statusDataConfig.addResponse(CanMessage.parse("0x00 0x3b 0x3f 0x3c 0x06 0x53 0x38 0x5c 0x41 0x00 0x04 0x00 0x00")); + return statusDataConfig; + } + + @Test + public void testParseStatusDataConfigLinkS88() { + System.out.println("parseStatusDataConfigLinkS88"); + CanDevice canDevice = new CanDevice(); + canDevice.setUid("0x53385c41"); + canDevice.setIdentifier("0x40"); + canDevice.setVersion("1.1"); + + CanMessage statusConfigmessage = getStatusDataConfigLinkS88Index0(); + CanDevice expResult = new CanDevice(); + expResult.setUid("0x53385c41"); + expResult.setName("Link S88"); + expResult.setIdentifier("0x40"); + expResult.setVersion("1.1"); + expResult.setArticleNumber("60883"); + expResult.setMeasureChannelCount(0); + expResult.setConfigChannelCount(12); + expResult.setVersion("1.1"); + expResult.setSerial(9281); + + CanDeviceParser.parse(canDevice, statusConfigmessage); + CanDevice result = canDevice; + assertEquals(expResult, result); + } + + private CanMessage getStatusDataConfigLinkS88Index1() { + CanMessage statusDataConfig = CanMessage.parse("0x00 0x3a 0x7b 0x79 0x05 0x53 0x38 0x5c 0x41 0x01 0x00 0x00 0x00"); + statusDataConfig.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x01 0x08 0x01 0x01 0x02 0x00 0x00 0x00 0x00 0x00")); + statusDataConfig.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x02 0x08 0x41 0x75 0x73 0x77 0x65 0x72 0x74 0x75")); + statusDataConfig.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x03 0x08 0x6e 0x67 0x20 0x31 0x20 0x2d 0x20 0x31")); + statusDataConfig.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x04 0x08 0x36 0x00 0x45 0x69 0x6e 0x7a 0x65 0x6c")); + statusDataConfig.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x05 0x08 0x6e 0x00 0x54 0x61 0x73 0x74 0x61 0x74")); + statusDataConfig.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x06 0x08 0x75 0x72 0x6d 0x61 0x74 0x72 0x69 0x78")); + statusDataConfig.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x07 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00")); + statusDataConfig.addResponse(CanMessage.parse("0x00 0x3b 0x3f 0x3c 0x06 0x53 0x38 0x5c 0x41 0x01 0x07 0x00 0x00")); + return statusDataConfig; + } + + @Test + public void testParseStatusDataConfigLinkS88Index1() { + System.out.println("parseStatusDataConfigLinkS88Index1"); + CanDevice canDevice = new CanDevice(); + canDevice.setUid("0x53385c41"); + canDevice.setIdentifier("0x40"); + canDevice.setVersion("1.1"); + canDevice.setName("Link S88"); + canDevice.setArticleNumber("60883"); + canDevice.setMeasureChannelCount(0); + canDevice.setConfigChannelCount(12); + + CanMessage statusConfigmessage = getStatusDataConfigLinkS88Index1(); + CanDevice expResultDev = new CanDevice(); + expResultDev.setUid("0x53385c41"); + expResultDev.setName("Link S88"); + expResultDev.setIdentifier("0x40"); + expResultDev.setVersion("1.1"); + expResultDev.setArticleNumber("60883"); + expResultDev.setMeasureChannelCount(0); + expResultDev.setConfigChannelCount(12); + expResultDev.setVersion("1.1"); + + ConfigChannel expResult = new ConfigChannel(); + expResult.setNumber(1); + expResult.setChoicesCount(2); + expResult.setValueId(0); + expResult.setChoiceDescription("Auswertung 1 - 16"); + expResult.addChoice("Einzeln"); + expResult.addChoice("Tastaturmatrix"); + + expResultDev.addConfigChannel(expResult); + CanDeviceParser.parse(canDevice, statusConfigmessage); + + CanDevice resultDev = canDevice; + +//expected: +// but was: + + assertEquals(expResultDev, resultDev); + + ConfigChannel result = canDevice.getConfigChannel(1); + assertNotNull(result); + + assertEquals(expResult, result); + } + + private CanMessage getStatusDataConfigLinkS88Index2() { + CanMessage statusDataConfig = CanMessage.parse("0x00 0x3a 0x7b 0x79 0x05 0x53 0x38 0x5c 0x41 0x02 0x00 0x00 0x00"); + statusDataConfig.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x01 0x08 0x02 0x02 0x00 0x00 0x00 0x1f 0x00 0x02")); + statusDataConfig.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x02 0x08 0x4c 0xc3 0xa4 0x6e 0x67 0x65 0x20 0x42")); + statusDataConfig.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x03 0x08 0x75 0x73 0x20 0x31 0x20 0x28 0x52 0x4a")); + statusDataConfig.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x04 0x08 0x34 0x35 0x2d 0x31 0x29 0x00 0x30 0x00")); + statusDataConfig.addResponse(CanMessage.parse("0x00 0x3b 0x03 0x05 0x08 0x33 0x31 0x00 0x00 0x00 0x00 0x00 0x00")); + statusDataConfig.addResponse(CanMessage.parse("0x00 0x3b 0x3f 0x3c 0x06 0x53 0x38 0x5c 0x41 0x02 0x05 0x00 0x00")); + return statusDataConfig; + } + + @Test + public void testParseStatusDataConfigLinkS88Index2() { + System.out.println("parseStatusDataConfigLinkS88Index1"); + CanDevice canDevice = new CanDevice(); + canDevice.setUid("0x53385c41"); + canDevice.setIdentifier("0x40"); + canDevice.setVersion("1.1"); + canDevice.setName("Link S88"); + canDevice.setArticleNumber("60883"); + canDevice.setMeasureChannelCount(0); + canDevice.setConfigChannelCount(12); + + CanMessage statusConfigmessage = getStatusDataConfigLinkS88Index2(); + CanDevice expResultDev = new CanDevice(); + expResultDev.setUid("0x53385c41"); + expResultDev.setName("Link S88"); + expResultDev.setIdentifier("0x40"); + expResultDev.setVersion("1.1"); + expResultDev.setArticleNumber("60883"); + expResultDev.setMeasureChannelCount(0); + expResultDev.setConfigChannelCount(12); + expResultDev.setVersion("1.1"); + + ConfigChannel expResult = new ConfigChannel(); + expResult.setNumber(2); + expResult.setValueId(2); + expResult.setChoiceDescription("Länge Bus 1 (RJ45-1)"); + expResult.setActualValue(2); + expResult.setLowValue(0); + expResult.setHighValue(0); + expResult.setStartName("0"); + expResult.setEndName("31"); + + expResultDev.addConfigChannel(expResult); + CanDeviceParser.parse(canDevice, statusConfigmessage); + + CanDevice resultDev = canDevice; + assertEquals(expResultDev, resultDev); + + ConfigChannel result = canDevice.getConfigChannel(2); + assertNotNull(result); + + assertEquals(expResult, result); + } + +} 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/parser/SystemStatusMessageTest.java b/src/test/java/jcs/commandStation/marklin/parser/SystemStatusMessageTest.java new file mode 100644 index 00000000..8096567a --- /dev/null +++ b/src/test/java/jcs/commandStation/marklin/parser/SystemStatusMessageTest.java @@ -0,0 +1,177 @@ +/* + * 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() { + } + + 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); + } + + @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 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); + } + +} 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()); - } - -} diff --git a/src/test/java/jcs/persistence/PersistenceServiceTest.java b/src/test/java/jcs/persistence/PersistenceServiceTest.java index 87635b2c..32f54509 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 { @@ -56,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(); @@ -73,10 +74,19 @@ public PersistenceServiceTest() { @BeforeClass public static void setUpClass() throws Exception { + 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...."); } @AfterClass public static void tearDownClass() throws Exception { + Logger.info("####### PersistenceService Test END...."); } @Before @@ -91,9 +101,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", 65, 1, null, 0, 0, 0,"marklin.cs", 1); + sensors.add(s1); - SensorBean s2 = new SensorBean("65-2", "M2", 65, 2, 1, 1, 0, null); + 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); @@ -200,9 +211,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); @@ -252,6 +263,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 +276,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 +290,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 +314,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,6 +333,7 @@ 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(); @@ -330,9 +346,10 @@ public void testGetSensors() { * Test of getSensor method, of class PersistenceService. */ @Test - public void testGetSensor_Long() { - System.out.println("getSensor"); - String id = "65-1"; + @Order(6) + public void testGetSensorString() { + System.out.println("getSensorString"); + Integer id = 1; PersistenceService instance = PersistenceFactory.getService(); SensorBean expResult = sensors.get(0); SensorBean result = instance.getSensor(id); @@ -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,23 +375,26 @@ public void testGetSensor_Integer_Integer() { * Test of persist method, of class PersistenceService. */ @Test - public void testPersist_SensorBean() { - System.out.println("persist"); - SensorBean sensor = new SensorBean("M1P3", 65, 3, 0, 1, 0, null); + @Order(8) + public void testPersistSensorBean() { + System.out.println("persistSensorBean"); + SensorBean sensor = new SensorBean(3, "M1P3", 0, 3, 65, 0, 1, 0, "marklin.cs", 2); + 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); result = instance.persist(sensor); assertEquals(sensor, result); - s3 = instance.getSensor("65-0003"); + s3 = instance.getSensor(3); assertEquals(sensor, s3); } @@ -381,16 +402,18 @@ public void testPersist_SensorBean() { * Test of remove method, of class PersistenceService. */ @Test - public void testRemove_SensorBean() { - System.out.println("remove"); - SensorBean sensor = new SensorBean("M1P4", 65, 4, 0, 1, 0, null); + @Order(9) + public void testRemoveSensorBean() { + System.out.println("removeSensorBean"); + SensorBean sensor = new SensorBean(4, "M1P4", 1, 4, 65, 0, 1, 0,"marklin.cs", 2); + PersistenceService instance = PersistenceFactory.getService(); SensorBean result = instance.persist(sensor); assertEquals(sensor, result); - SensorBean s3 = instance.getSensor(65, 4); + SensorBean s3 = instance.getSensor(1, 4); assertEquals(sensor, s3); instance.remove(sensor); @@ -403,6 +426,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 +458,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 +489,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 +526,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 +561,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 +575,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 +601,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 +618,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 +638,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 +652,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 +666,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 +696,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 +719,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 +734,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 +749,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 +770,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 +792,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 +819,7 @@ public void testPersist_List_TileBeans() { } @Test + @Order(26) public void testPersistLotsOfTileBeans() { System.out.println("persistLotsOfTileBeans"); PersistenceService instance = PersistenceFactory.getService(); @@ -810,6 +845,7 @@ public void testPersistLotsOfTileBeans() { } @Test + @Order(27) public void testGetRoutes() { System.out.println("getRoutes"); PersistenceService instance = PersistenceFactory.getService(); @@ -819,8 +855,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 +865,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 +880,7 @@ public void testGetRoute_String_String_String_String() { } @Test + @Order(30) public void testLockRoute() { System.out.println("LockRoute"); PersistenceService instance = PersistenceFactory.getService(); @@ -871,8 +910,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 +948,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 +968,7 @@ public void testRemove_RouteBean() { } @Test + @Order(33) public void testGetBlocks() { System.out.println("getBlocks"); PersistenceService instance = PersistenceFactory.getService(); @@ -936,16 +978,21 @@ public void testGetBlocks() { } @Test + @Order(34) public void testGetBlock() { System.out.println("getBlock"); String id = "bk-1"; PersistenceService instance = PersistenceFactory.getService(); BlockBean expResult = this.blocks.get(0); BlockBean result = instance.getBlock(id); + + //expected: + //but was: assertEquals(expResult, result); } @Test + @Order(35) public void testGetBlockByTileId() { System.out.println("getBlockByTileId"); String tileId = "bk-2"; @@ -956,8 +1003,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 +1026,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 +1051,7 @@ public void testRemove_BlockBean() { } @Test + @Order(38) public void testRemoveAllBlocks() { System.out.println("removeAllBlocks"); PersistenceService instance = PersistenceFactory.getService(); @@ -1018,6 +1068,7 @@ public void testRemoveAllBlocks() { } @Test + @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 6b634b1c..24a09f45 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; @@ -34,12 +34,13 @@ public class TileTest { public TileTest() { + System.setProperty("persistenceService", "jcs.persistence.TestH2PersistenceService"); } @Test public void testgetCenterX() { System.out.println("getCenterX"); - Tile instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 180, 100, false); + Tile instance = TileCache.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 180, 100); int expResult = 180; int result = instance.getCenterX(); assertEquals(expResult, result); @@ -48,9 +49,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, false); + Tile instance = TileCache.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 0, 0); int expResult = 20; int result = instance.getCenterX(); assertEquals(expResult, result); @@ -59,28 +58,23 @@ public void testgetCenterXZero() { @Test public void testGetGridX() { System.out.println("getGridX"); - Tile instance - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 100, 100, false); + Tile instance = TileCache.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 100, 100); 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 = TileCache.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 220, 220); 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 = TileCache.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 180, 100); int expResult = 100; int result = instance.getCenterY(); assertEquals(expResult, result); @@ -89,9 +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 = TileCache.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 0, 0); int expResult = 20; int result = instance.getCenterY(); assertEquals(expResult, result); @@ -100,20 +92,16 @@ 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 = TileCache.createTile(TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 100, 140); int expResult = 3; - int result = instance.getGridY(); + int result = (instance.getTileY() - Tile.GRID) / (Tile.GRID * 2); assertEquals(expResult, result); } @Test public void testGetAllPoints() { System.out.println("getAllPoints"); - Tile instance - = TileFactory.createTile( - TileBean.TileType.BLOCK, Orientation.WEST, Direction.CENTER, 220, 220, false); + 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)); @@ -127,9 +115,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, false); + 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)); @@ -140,18 +126,16 @@ public void testGetAltPointsBlock() { @Test public void testGetAltPointsCross() { System.out.println("getAltPointsCross"); - Tile instanceE - = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.EAST, Direction.CENTER, 220, 220, false); + Tile instanceE = TileCache.createTile(TileBean.TileType.CROSS, Orientation.EAST, Direction.CENTER, 220, 220); Tile instanceS - = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.SOUTH, Direction.CENTER, 220, 220, false); + = TileCache.createTile( + TileBean.TileType.CROSS, Orientation.SOUTH, Direction.CENTER, 220, 220); Tile instanceW - = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.WEST, Direction.CENTER, 220, 220, false); + = TileCache.createTile( + TileBean.TileType.CROSS, Orientation.WEST, Direction.CENTER, 220, 220); Tile instanceN - = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.NORTH, Direction.CENTER, 220, 220, false); + = TileCache.createTile( + TileBean.TileType.CROSS, Orientation.NORTH, Direction.CENTER, 220, 220); Set expResultE = new HashSet<>(); expResultE.add(new Point(260, 220)); @@ -187,32 +171,32 @@ public void testGetAltPointsCross() { public void testGetNeighborPointsCross() { System.out.println("getNeighborPointsCross"); Tile instanceEL - = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.EAST, Direction.LEFT, 220, 220, false); + = TileCache.createTile( + TileBean.TileType.CROSS, Orientation.EAST, Direction.LEFT, 220, 220); Tile instanceER - = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.EAST, Direction.RIGHT, 220, 220, false); + = TileCache.createTile( + TileBean.TileType.CROSS, Orientation.EAST, Direction.RIGHT, 220, 220); Tile instanceWL - = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.WEST, Direction.LEFT, 220, 220, false); + = TileCache.createTile( + TileBean.TileType.CROSS, Orientation.WEST, Direction.LEFT, 220, 220); Tile instanceWR - = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.WEST, Direction.RIGHT, 220, 220, false); + = TileCache.createTile( + TileBean.TileType.CROSS, Orientation.WEST, Direction.RIGHT, 220, 220); Tile instanceSL - = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.SOUTH, Direction.LEFT, 220, 220, false); + = TileCache.createTile( + TileBean.TileType.CROSS, Orientation.SOUTH, Direction.LEFT, 220, 220); Tile instanceSR - = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.SOUTH, Direction.RIGHT, 220, 220, false); + = TileCache.createTile( + TileBean.TileType.CROSS, Orientation.SOUTH, Direction.RIGHT, 220, 220); Tile instanceNL - = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.NORTH, Direction.LEFT, 220, 220, false); + = TileCache.createTile( + TileBean.TileType.CROSS, Orientation.NORTH, Direction.LEFT, 220, 220); Tile instanceNR - = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.NORTH, Direction.RIGHT, 220, 220, false); + = TileCache.createTile( + TileBean.TileType.CROSS, Orientation.NORTH, Direction.RIGHT, 220, 220); Map expResultEL = new HashMap<>(); expResultEL.put(Orientation.EAST, new Point(300, 220)); @@ -299,24 +283,24 @@ public void testGetNeighborPointsCross() { public void testIsAdjacentStraight() { System.out.println("isAdjacentStraight"); Tile instanceE - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 100, 100, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 100, 100); Tile instanceN - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 100, 100, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 100, 100); Tile west - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 60, 100, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 60, 100); Tile east - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 140, 100, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 140, 100); Tile north - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 100, 60, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 100, 60); Tile south - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 100, 140, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 100, 140); assertTrue(instanceE.isAdjacent(west)); assertTrue(instanceE.isAdjacent(east)); @@ -334,32 +318,32 @@ public void testIsAdjacentBlock() { System.out.println("isAdjacentBlock"); Tile instanceE - = TileFactory.createTile( - TileBean.TileType.BLOCK, Orientation.EAST, Direction.CENTER, 220, 220, false); + = TileCache.createTile( + TileBean.TileType.BLOCK, Orientation.EAST, Direction.CENTER, 220, 220); Tile instanceW - = TileFactory.createTile( - TileBean.TileType.BLOCK, Orientation.WEST, Direction.CENTER, 220, 220, false); + = TileCache.createTile( + TileBean.TileType.BLOCK, Orientation.WEST, Direction.CENTER, 220, 220); Tile instanceS - = TileFactory.createTile( - TileBean.TileType.BLOCK, Orientation.SOUTH, Direction.CENTER, 220, 220, false); + = TileCache.createTile( + TileBean.TileType.BLOCK, Orientation.SOUTH, Direction.CENTER, 220, 220); Tile instanceN - = TileFactory.createTile( - TileBean.TileType.BLOCK, Orientation.NORTH, Direction.CENTER, 220, 220, false); + = TileCache.createTile( + TileBean.TileType.BLOCK, Orientation.NORTH, Direction.CENTER, 220, 220); Tile west - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 140, 220, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 140, 220); Tile east - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 300, 220, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 300, 220); Tile north - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 220, 140, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 220, 140); Tile south - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 220, 300, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 220, 300); assertTrue(instanceE.isAdjacent(west)); assertTrue(instanceE.isAdjacent(east)); @@ -381,30 +365,30 @@ public void testIsAdjacentBlock() { public void testIsAdjacentCurved() { System.out.println("isAdjacentCurved"); Tile instanceE - = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 860, 140, false); + = TileCache.createTile( + TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 860, 140); Tile instanceN - = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 860, 140, false); + = TileCache.createTile( + TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 860, 140); Tile instanceW - = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 860, 140, false); + = TileCache.createTile( + TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 860, 140); Tile instanceS - = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 860, 140, false); + = TileCache.createTile( + TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 860, 140); Tile straightE - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 140, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 140); Tile straightN - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 100, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 100); Tile straightW - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 140, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 140); Tile straightS - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180); assertTrue(instanceE.isAdjacent(straightE)); assertFalse(instanceE.isAdjacent(straightN)); @@ -432,30 +416,30 @@ public void testIsAdjacentEnd() { System.out.println("isAdjacentEnd"); Tile instanceE - = TileFactory.createTile( - TileBean.TileType.END, Orientation.EAST, Direction.CENTER, 860, 140, false); + = TileCache.createTile( + TileBean.TileType.END, Orientation.EAST, Direction.CENTER, 860, 140); Tile instanceS - = TileFactory.createTile( - TileBean.TileType.END, Orientation.SOUTH, Direction.CENTER, 860, 140, false); + = TileCache.createTile( + TileBean.TileType.END, Orientation.SOUTH, Direction.CENTER, 860, 140); Tile instanceW - = TileFactory.createTile( - TileBean.TileType.END, Orientation.WEST, Direction.CENTER, 860, 140, false); + = TileCache.createTile( + TileBean.TileType.END, Orientation.WEST, Direction.CENTER, 860, 140); Tile instanceN - = TileFactory.createTile( - TileBean.TileType.END, Orientation.NORTH, Direction.CENTER, 860, 140, false); + = TileCache.createTile( + TileBean.TileType.END, Orientation.NORTH, Direction.CENTER, 860, 140); Tile straightE - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 140, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 140); Tile straightN - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 100, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 100); Tile straightW - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 140, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 140); Tile straightS - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180); assertFalse(instanceE.isAdjacent(straightE)); assertFalse(instanceE.isAdjacent(straightS)); @@ -482,31 +466,31 @@ public void testIsAdjacentEnd() { public void testgetIdSuffix() { System.out.println("getGetIdSuffix"); Tile instanceE - = TileFactory.createTile( - TileBean.TileType.BLOCK, Orientation.EAST, Direction.CENTER, 220, 220, false); + = TileCache.createTile( + TileBean.TileType.BLOCK, Orientation.EAST, Direction.CENTER, 220, 220); Tile instanceW - = TileFactory.createTile( - TileBean.TileType.BLOCK, Orientation.WEST, Direction.CENTER, 220, 220, false); + = TileCache.createTile( + TileBean.TileType.BLOCK, Orientation.WEST, Direction.CENTER, 220, 220); Tile instanceN - = TileFactory.createTile( - TileBean.TileType.BLOCK, Orientation.NORTH, Direction.CENTER, 220, 220, false); + = TileCache.createTile( + TileBean.TileType.BLOCK, Orientation.NORTH, Direction.CENTER, 220, 220); Tile instanceS - = TileFactory.createTile( - TileBean.TileType.BLOCK, Orientation.SOUTH, Direction.CENTER, 220, 220, false); + = TileCache.createTile( + TileBean.TileType.BLOCK, Orientation.SOUTH, Direction.CENTER, 220, 220); Tile west - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 140, 220, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 140, 220); Tile east - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 300, 220, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 300, 220); Tile north - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 220, 140, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 220, 140); Tile south - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 220, 300, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 220, 300); String expResult = "-"; String result = instanceE.getIdSuffix(west); @@ -536,56 +520,56 @@ public void testgetIdSuffix() { public void testIsAdjacentSwitchL() { System.out.println("isAdjacentSwitchL"); Tile instanceE - = TileFactory.createTile( - TileBean.TileType.SWITCH, Orientation.EAST, Direction.LEFT, 1060, 140, false); + = TileCache.createTile( + TileBean.TileType.SWITCH, Orientation.EAST, Direction.LEFT, 1060, 140); Tile instanceS - = TileFactory.createTile( - TileBean.TileType.SWITCH, Orientation.SOUTH, Direction.LEFT, 1060, 140, false); + = TileCache.createTile( + TileBean.TileType.SWITCH, Orientation.SOUTH, Direction.LEFT, 1060, 140); Tile instanceW - = TileFactory.createTile( - TileBean.TileType.SWITCH, Orientation.WEST, Direction.LEFT, 1060, 140, false); + = TileCache.createTile( + TileBean.TileType.SWITCH, Orientation.WEST, Direction.LEFT, 1060, 140); Tile instanceN - = TileFactory.createTile( - TileBean.TileType.SWITCH, Orientation.NORTH, Direction.LEFT, 1060, 140, false); + = TileCache.createTile( + TileBean.TileType.SWITCH, Orientation.NORTH, Direction.LEFT, 1060, 140); Tile north - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 1060, 100, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 1060, 100); Tile west - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 1020, 140, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 1020, 140); Tile east - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 1100, 140, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 1100, 140); Tile south - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 1060, 180, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 1060, 180); Tile westCS - = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 1020, 140, false); + = TileCache.createTile( + TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 1020, 140); Tile westCE - = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 1020, 140, false); + = TileCache.createTile( + TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 1020, 140); Tile westCW - = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 1020, 140, false); + = TileCache.createTile( + TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 1020, 140); Tile westCN - = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 1020, 140, false); + = TileCache.createTile( + TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 1020, 140); Tile southCS - = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 1060, 180, false); + = TileCache.createTile( + TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 1060, 180); Tile southCE - = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 1060, 180, false); + = TileCache.createTile( + TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 1060, 180); Tile southCW - = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 1060, 180, false); + = TileCache.createTile( + TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 1060, 180); Tile southCN - = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 1060, 180, false); + = TileCache.createTile( + TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 1060, 180); assertTrue(instanceE.isAdjacent(west)); assertTrue(instanceE.isAdjacent(east)); @@ -622,56 +606,56 @@ public void testIsAdjacentSwitchL() { public void testIsAdjacentSwitchR() { System.out.println("isAdjacentSwitchR"); Tile instanceE - = TileFactory.createTile( - TileBean.TileType.SWITCH, Orientation.EAST, Direction.RIGHT, 1060, 140, false); + = TileCache.createTile( + TileBean.TileType.SWITCH, Orientation.EAST, Direction.RIGHT, 1060, 140); Tile instanceS - = TileFactory.createTile( - TileBean.TileType.SWITCH, Orientation.SOUTH, Direction.RIGHT, 1060, 140, false); + = TileCache.createTile( + TileBean.TileType.SWITCH, Orientation.SOUTH, Direction.RIGHT, 1060, 140); Tile instanceW - = TileFactory.createTile( - TileBean.TileType.SWITCH, Orientation.WEST, Direction.RIGHT, 1060, 140, false); + = TileCache.createTile( + TileBean.TileType.SWITCH, Orientation.WEST, Direction.RIGHT, 1060, 140); Tile instanceN - = TileFactory.createTile( - TileBean.TileType.SWITCH, Orientation.NORTH, Direction.RIGHT, 1060, 140, false); + = TileCache.createTile( + TileBean.TileType.SWITCH, Orientation.NORTH, Direction.RIGHT, 1060, 140); Tile north - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 1060, 100, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 1060, 100); Tile west - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 1020, 140, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 1020, 140); Tile east - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 1100, 140, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 1100, 140); Tile south - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 1060, 180, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 1060, 180); Tile eastCS - = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 1100, 140, false); + = TileCache.createTile( + TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 1100, 140); Tile eastCE - = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 1100, 140, false); + = TileCache.createTile( + TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 1100, 140); Tile eastCW - = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 1100, 140, false); + = TileCache.createTile( + TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 1100, 140); Tile eastCN - = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 1100, 140, false); + = TileCache.createTile( + TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 1100, 140); Tile northCS - = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 1060, 100, false); + = TileCache.createTile( + TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 1060, 100); Tile northCE - = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 1060, 100, false); + = TileCache.createTile( + TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 1060, 100); Tile northCW - = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 1060, 100, false); + = TileCache.createTile( + TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 1060, 100); Tile northCN - = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 1060, 100, false); + = TileCache.createTile( + TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 1060, 100); assertTrue(instanceE.isAdjacent(west)); assertTrue(instanceE.isAdjacent(east)); @@ -708,30 +692,30 @@ public void testIsAdjacentSwitchR() { public void testIsArrowSwitchSide() { System.out.println("isArrowSwitchSide"); Tile instanceE - = TileFactory.createTile( - TileBean.TileType.STRAIGHT_DIR, Orientation.EAST, Direction.RIGHT, 860, 140, false); + = TileCache.createTile( + 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); + = TileCache.createTile( + 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); + = TileCache.createTile( + 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); + = TileCache.createTile( + TileBean.TileType.STRAIGHT_DIR, Orientation.NORTH, Direction.RIGHT, 860, 140); Tile straighE - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 140, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 140); Tile straighS - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180); Tile straighW - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 140, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 140); Tile straighN - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 100, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 100); assertTrue(instanceE.isArrowDirection(straighE)); assertFalse(instanceE.isArrowDirection(straighW)); @@ -750,54 +734,54 @@ public void testIsArrowSwitchSide() { public void testIsAdjacentCrossL() { System.out.println("iIsAdjacentCrossL"); Tile instanceE - = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.EAST, Direction.LEFT, 860, 100, false); + = TileCache.createTile( + TileBean.TileType.CROSS, Orientation.EAST, Direction.LEFT, 860, 100); Tile instanceS - = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.SOUTH, Direction.LEFT, 860, 100, false); + = TileCache.createTile( + TileBean.TileType.CROSS, Orientation.SOUTH, Direction.LEFT, 860, 100); Tile instanceW - = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.WEST, Direction.LEFT, 860, 100, false); + = TileCache.createTile( + TileBean.TileType.CROSS, Orientation.WEST, Direction.LEFT, 860, 100); Tile instanceN - = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.NORTH, Direction.LEFT, 860, 100, false); + = TileCache.createTile( + TileBean.TileType.CROSS, Orientation.NORTH, Direction.LEFT, 860, 100); Tile north - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 900, 60, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 900, 60); Tile north2 - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 60, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 60); Tile north3 - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 20, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 20); Tile west - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 100, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 100); Tile west2 - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 780, 100, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 780, 100); Tile west3 - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 60, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 60); Tile east - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 940, 100, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 940, 100); Tile east2 - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 100, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 100); Tile east3 - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 140, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 140); Tile south - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 140, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 140); Tile south2 - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 820, 140, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 820, 140); Tile south3 - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180); assertTrue(instanceE.isAdjacent(west)); assertTrue(instanceE.isAdjacent(east)); @@ -824,61 +808,61 @@ public void testIsAdjacentCrossL() { public void testIsAdjacentCrossR() { System.out.println("iIsAdjacentCrossR"); Tile instanceE - = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.EAST, Direction.RIGHT, 860, 100, false); + = TileCache.createTile( + TileBean.TileType.CROSS, Orientation.EAST, Direction.RIGHT, 860, 100); Tile instanceS - = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.SOUTH, Direction.RIGHT, 860, 100, false); + = TileCache.createTile( + TileBean.TileType.CROSS, Orientation.SOUTH, Direction.RIGHT, 860, 100); Tile instanceW - = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.WEST, Direction.RIGHT, 860, 100, false); + = TileCache.createTile( + TileBean.TileType.CROSS, Orientation.WEST, Direction.RIGHT, 860, 100); Tile instanceN - = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.NORTH, Direction.RIGHT, 860, 100, false); + = TileCache.createTile( + TileBean.TileType.CROSS, Orientation.NORTH, Direction.RIGHT, 860, 100); Tile north - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 60, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 60); Tile north2 - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 60, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 60); Tile north3 - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 20, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 20); Tile north4 - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 820, 60, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 820, 60); Tile west - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 140, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 140); Tile west2 - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 100, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 100); Tile west3 - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 860, 100, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 860, 100); Tile west4 - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 780, 100, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 780, 100); Tile east - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 940, 100, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 940, 100); Tile east2 - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 60, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 60); Tile east3 - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 100, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 100); Tile south - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 140, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 140); Tile south2 - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 900, 140, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 900, 140); Tile south3 - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180, false); + = TileCache.createTile( + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180); assertTrue(instanceE.isAdjacent(west2)); assertTrue(instanceE.isAdjacent(east)); @@ -904,14 +888,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 = TileCache.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 = TileCache.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 = 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..5b1bfed4 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; @@ -35,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(); } @@ -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..0733722e 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; @@ -35,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(); } @@ -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..630d360d 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; @@ -35,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(); } @@ -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..326fc061 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; @@ -35,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(); } @@ -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..3ec3ee44 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; @@ -35,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(); } @@ -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..ed4cfd57 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; @@ -35,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(); } @@ -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..131af219 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; @@ -35,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(); } @@ -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..fd4af1b1 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; @@ -35,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(); } @@ -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..92823c15 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; @@ -35,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(); } @@ -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..7ed0f5de 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; @@ -36,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(); } @@ -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..dda4c26e 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; @@ -36,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(); } @@ -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/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..620fef4b 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, 220, 60); + 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, 180, 140); + 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, 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); + } + + 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.setShowRoute(this.northTileBtn.isSelected()); + }//GEN-LAST:event_northTileBtnActionPerformed + + private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed + blockEast.setShowRoute(this.eastTileBtn.isSelected()); + }//GEN-LAST:event_eastTileBtnActionPerformed + + private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed + blockWest.setShowRoute(this.westTileBtn.isSelected()); + }//GEN-LAST:event_westTileBtnActionPerformed + + private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed + blockSouth.setShowRoute(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.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 fc62c582..7a15ae65 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).setValue(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).setValue(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).setValue(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).setValue(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.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.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.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.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 + 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/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..11ee9511 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.setShowRoute(this.northTileBtn.isSelected()); + }//GEN-LAST:event_northTileBtnActionPerformed + + private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed + this.trackEast.setShowRoute(this.eastTileBtn.isSelected()); + }//GEN-LAST:event_eastTileBtnActionPerformed + + private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed + this.trackWest.setShowRoute(this.westTileBtn.isSelected()); + }//GEN-LAST:event_westTileBtnActionPerformed + + private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed + this.trackSouth.setShowRoute(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..32b0b76f 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.setShowRoute(this.northTileBtn.isSelected()); + }//GEN-LAST:event_northTileBtnActionPerformed + + private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed + this.trackEast.setShowRoute(this.eastTileBtn.isSelected()); + }//GEN-LAST:event_eastTileBtnActionPerformed + + private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed + this.trackWest.setShowRoute(this.westTileBtn.isSelected()); + }//GEN-LAST:event_westTileBtnActionPerformed + + private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed + this.trackSouth.setShowRoute(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..d9b5d190 --- /dev/null +++ b/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java @@ -0,0 +1,91 @@ +/* + * 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.Component; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Paint; +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); + } + + @Override + public void paint(Graphics g) { + long started = System.currentTimeMillis(); + 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 grid; + if (expanded) { + grid = 20; + } else { + grid = 20; + } + + 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 * 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/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..15b3ed3c 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.setShowRoute(this.northTileBtn.isSelected()); + }//GEN-LAST:event_northTileBtnActionPerformed + + private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed + this.trackEast.setShowRoute(this.eastTileBtn.isSelected()); + }//GEN-LAST:event_eastTileBtnActionPerformed + + private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed + this.trackWest.setShowRoute(this.westTileBtn.isSelected()); + }//GEN-LAST:event_westTileBtnActionPerformed + + private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed + this.trackSouth.setShowRoute(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..d0987c8d 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.setShowRoute(this.northTileBtn.isSelected()); + }//GEN-LAST:event_northTileBtnActionPerformed + + private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed + sensorEast.setShowRoute(this.eastTileBtn.isSelected()); + }//GEN-LAST:event_eastTileBtnActionPerformed + + private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed + sensorWest.setShowRoute(this.westTileBtn.isSelected()); + }//GEN-LAST:event_westTileBtnActionPerformed + + private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed + sensorSouth.setShowRoute(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..a1e62419 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.setShowRoute(this.northTileBtn.isSelected()); + }//GEN-LAST:event_northTileBtnActionPerformed + + private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed + this.signal2East.setShowRoute(this.eastTileBtn.isSelected()); + }//GEN-LAST:event_eastTileBtnActionPerformed + + private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed + this.signal2West.setShowRoute(this.westTileBtn.isSelected()); + }//GEN-LAST:event_westTileBtnActionPerformed + + private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed + this.signal2South.setShowRoute(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..30ad25da 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.setShowRoute(this.northTileBtn.isSelected()); + }//GEN-LAST:event_northTileBtnActionPerformed + + private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed + this.trackEast.setShowRoute(this.eastTileBtn.isSelected()); + }//GEN-LAST:event_eastTileBtnActionPerformed + + private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed + this.trackWest.setShowRoute(this.westTileBtn.isSelected()); + }//GEN-LAST:event_westTileBtnActionPerformed + + private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed + this.trackSouth.setShowRoute(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..ea006b17 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,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 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.setShowRoute(this.northTileBtn.isSelected()); + }//GEN-LAST:event_northTileBtnActionPerformed + + private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed + this.trackEast.setShowRoute(this.eastTileBtn.isSelected()); + }//GEN-LAST:event_eastTileBtnActionPerformed + + private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed + this.trackWest.setShowRoute(this.westTileBtn.isSelected()); + }//GEN-LAST:event_westTileBtnActionPerformed + + private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed + this.trackSouth.setShowRoute(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..584d6df0 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.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.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.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.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 + 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/main/java/jcs/ui/options/CommandStationDialog.form b/src/test/java/jcs/ui/layout/tiles/TileTester.form similarity index 54% rename from src/main/java/jcs/ui/options/CommandStationDialog.form rename to src/test/java/jcs/ui/layout/tiles/TileTester.form index 5db9cbf7..2d98e3fa 100644 --- a/src/main/java/jcs/ui/options/CommandStationDialog.form +++ b/src/test/java/jcs/ui/layout/tiles/TileTester.form @@ -1,11 +1,8 @@ -
+ - - - - + @@ -21,44 +18,71 @@ - + - + - - - - - - - - - - - - - + - + - - - - - - - + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -71,7 +95,7 @@ - + @@ -98,11 +122,11 @@ - - + + - + @@ -114,16 +138,16 @@ - + - - + + - + @@ -131,5 +155,21 @@ + + + + + + + + + + + + + + + + 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/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 b59a2535..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,10 +434,10 @@
- + - + diff --git a/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java b/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java new file mode 100644 index 00000000..2f35c035 --- /dev/null +++ b/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java @@ -0,0 +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 = 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 diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java index 92b2c3cc..486d1b0d 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java @@ -16,182 +16,75 @@ package jcs.ui.layout.tiles; import java.awt.Color; -import java.awt.Dimension; +import java.awt.Component; 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 { - private boolean showCenter; - - private final List tiles; + private boolean expanded; public UnscaledBlockCanvas() { - tiles = new ArrayList<>(); - } - - public void addTile(Tile block) { - this.tiles.add(block); - } - - public boolean isShowCenter() { - return showCenter; - } - - public void setShowCenter(boolean showCenter) { - this.showCenter = showCenter; + setLayout(null); + setOpaque(true); + setDoubleBuffered(true); } - 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 = !((AbstractTile) 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; + @Override + public Component add(Component component) { + super.add(component); + if (component instanceof Tile tile) { + tile.setBounds(tile.getTileBounds()); } - - //Logger.trace("MinX: " + minX + " maxX: " + maxX + " minY: " + minY + " maxY: " + maxY + " Width: " + totalWidth + " Height: " + totalHeight); - return new Dimension(Math.abs(totalWidth), Math.abs(totalHeight)); + return component; } - 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; + @Override + protected void paintComponent(Graphics g) { + long started = System.currentTimeMillis(); + super.paintComponent(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 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(); + private void paintGrid(Graphics g) { + int width = this.getWidth(); + int height = this.getHeight(); - g2d.setBackground(Color.white); - g2d.clearRect(0, 0, canvasSize.width, canvasSize.height); + int xOffset = 0; + int yOffset = 0; - for (Tile tile : tiles) { - tile.setDrawOutline(showCenter); + //Logger.trace("W: " + width + " H: " + height + " X: " + this.getX() + " Y: " + this.getY()); + Graphics2D gc = (Graphics2D) g; + Paint p = gc.getPaint(); + gc.setPaint(Color.black); - tile.drawTile(g2d, true); - - if (showCenter) { - tile.drawCenterPoint(g2d, Color.red); - } + int grid; + if (expanded) { + grid = 20; + } else { + grid = 20; } - 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; + 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); + } } - - 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); + gc.setPaint(p); } - @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; + this.repaint(); } - } diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.form b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.form similarity index 94% rename from src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.form rename to src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.form index 2f7f61a7..7855dc53 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.form +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.form @@ -52,6 +52,14 @@
+ + + + + + + + @@ -73,6 +81,22 @@ + + + + + + + + + + + + + + + + @@ -98,22 +122,6 @@ - - - - - - - - - - - - - - - - @@ -122,21 +130,21 @@ - + - + - + - + - + + + + - - - @@ -182,7 +190,7 @@
- + @@ -196,15 +204,15 @@ - + - + - + @@ -215,7 +223,7 @@ - + diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.java b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.java similarity index 64% rename from src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.java rename to src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.java index 54529517..2cc8ea92 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.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,43 +15,55 @@ */ 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.JLabel; 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; import jcs.entities.TileBean.Orientation; import jcs.ui.util.ImageUtil; import org.tinylog.Logger; -/** - * - * @author FJA - */ -public class UnscaledBlockTileFrame extends javax.swing.JFrame implements PropertyChangeListener { +public class UnscaledBlockTester extends JFrame { //implements PropertyChangeListener { - private Tile blockTile; + private final Tile blockTile; /** * Creates new form UnscaledBlockTileFrame */ - public UnscaledBlockTileFrame() { + public UnscaledBlockTester() { initComponents(); + this.orientationCB.setModel(createOrientationComboBoxModel()); this.departureSideCB.setSelectedItem(""); this.stateCB.setModel(createStateComboBoxModel()); - initTile(); + 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(); + setVisible(true); } private ComboBoxModel createOrientationComboBoxModel() { @@ -73,86 +85,57 @@ private ComboBoxModel createStateComboBoxModel() { blockStateModel.addElement(BlockState.LOCKED); blockStateModel.addElement(BlockState.OUT_OF_ORDER); + blockStateModel.setSelectedItem(BlockState.FREE); return blockStateModel; } 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); Image locImage = ImageUtil.readImage(imgPath); - //Image is sized by default so 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; } - private void initTile() { - Dimension vps = this.blockTileCanvas.getPreferredSize(); - 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"); + private Block createBlock() { + Block block = new Block(Orientation.EAST, 640, 280); - //bbe.setArrivalSuffix((String) this.incomingSideCB.getSelectedItem()); - bbe.setDepartureSuffix(null); + block.setId("bk-1"); + block.setBlockState((BlockState) stateCB.getSelectedItem()); + block.setScaleImage(!scaleCB.isSelected()); + //canvas.setExpanded(scaleCB.isSelected()); - bbe.setBlockState((BlockState) this.stateCB.getSelectedItem()); - bbe.setReverseArrival(this.reverseArrivalCB.isSelected()); + BlockBean blockBean = new BlockBean(); + blockBean.setId(block.getId()); + blockBean.setTileId(block.getId()); + blockBean.setDescription("Blok 1"); + blockBean.setDepartureSuffix(null); + blockBean.setDepartureSuffix((String) this.departureSideCB.getSelectedItem()); - if (this.showLocCB.isSelected()) { - bbe.setLocomotive(createLocomotiveBean()); + if (showLocCB.isSelected()) { + blockBean.setLocomotive(createLocomotiveBean()); } else { - bbe.setLocomotive(null); + blockBean.setLocomotive(null); } - ((Block) blockTile).setBlockBean(bbe); - - if (this.scaleCB.isSelected()) { - ((AbstractTile) blockTile).setScaleImage(false); - } else { - ((AbstractTile) blockTile).setScaleImage(true); - } - - blockTileCanvas.addTile(blockTile); - centerSP.getViewport().validate(); + block.setBlockBean(blockBean); + 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.blockTileCanvas.getPreferredSize(); - - Point cc = new Point(Math.abs(vps.width / 2), Math.abs(vps.height / 2)); - blockTile.setCenter(cc); - - this.centerSP.getViewport().revalidate(); - repaint(); } /** @@ -165,19 +148,20 @@ 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(); + jLabel1 = new javax.swing.JLabel(); 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)); @@ -192,6 +176,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); @@ -203,6 +195,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); @@ -215,14 +215,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) { @@ -231,15 +223,7 @@ 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.setText(""); showLocCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { showLocCBActionPerformed(evt); @@ -247,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() { @@ -280,33 +268,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(new java.awt.Dimension(1220, 410)); + 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) - .addGap(0, 498, Short.MAX_VALUE) + canvasLayout.setVerticalGroup( + canvasLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 445, Short.MAX_VALUE) ); - centerSP.setViewportView(blockTileCanvas); + centerSP.setViewportView(canvas); getContentPane().add(centerSP, java.awt.BorderLayout.CENTER); @@ -314,21 +302,17 @@ 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("\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()); + if (showLocCB.isSelected()) { + 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 @@ -336,71 +320,47 @@ 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); + if (blockTile != null) { + if ("".equals(departureSideCB.getSelectedItem())) { + blockTile.setDepartureSuffix(null); } else { - ((Block) blockTile).getBlockBean().setDepartureSuffix((String) this.departureSideCB.getSelectedItem()); + blockTile.setDepartureSuffix(departureSideCB.getSelectedItem().toString()); } - repaint(); } }//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 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()) { - ((AbstractTile) blockTile).setScaleImage(false); - } else { - ((AbstractTile) 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 @@ -409,7 +369,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(); @@ -435,8 +395,9 @@ private void blockTileCanvasComponentResized(java.awt.event.ComponentEvent evt) //JViewport vp = scrollpane.getViewport(); //vp.setViewSize(newsize); // revalidate(); +//jcs.ui.layout.tiles.UnscaledBlockTester.GridCanvas - }//GEN-LAST:event_blockTileCanvasComponentResized + }//GEN-LAST:event_canvasComponentResized /** * @param args the command line arguments @@ -450,31 +411,22 @@ 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.setVisible(true); - }); - } - @Override - public void propertyChange(PropertyChangeEvent evt) { - if ("repaintTile".equals(evt.getPropertyName())) { - Tile t = (Tile) evt.getNewValue(); - Logger.trace("Tile: " + t); - this.repaint(); - } + //app.pack(); + }); } - // 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; 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; diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.java b/src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.java deleted file mode 100644 index cf3a9f5b..00000000 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.java +++ /dev/null @@ -1,536 +0,0 @@ -/* - * Copyright 2024 FJA. - * - * 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.Point; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -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.events.TileEvent; -import org.tinylog.Logger; - -/** - * - * @author FJA - */ -public class UnscaledTileFrame extends javax.swing.JFrame implements PropertyChangeListener { - - private Tile tile; - - /** - * Creates new form UnscaledBlockTileFrame - */ - public UnscaledTileFrame() { - initComponents(); - this.tileCB.setModel(createTileTypeComboBoxModel()); - this.orientationCB.setModel(createOrientationComboBoxModel()); - this.incomingSideCB.setModel(createOrientationComboBoxModel()); - this.directionCB.setModel(createDirectionComboBoxModel(true)); - drawTile(); - } - - 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 drawTile() { - TileType tileType = (TileType) this.tileCB.getSelectedItem(); - Orientation orientation = (Orientation) this.orientationCB.getSelectedItem(); - - if (TileType.SWITCH == tileType || TileType.CROSS == tileType) { - this.directionCB.setModel(createDirectionComboBoxModel(false)); - } else { - this.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; - y = h / 2 + 50; - } - - Point center; - if (TileType.CROSS.equals(tileType)) { - center = new Point(x - 200, y); - } else { - center = new Point(x, y); - } - - tile = TileFactory.createTile(tileType, orientation, direction, center, showOutline); - tile.setPropertyChangeListener(this); - - Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); - tile.setIncomingSide(incomingSide); - - tile.setDrawRoute(this.displayRouteCB.isSelected()); - tile.setTrackRouteColor(Color.blue); - - ((AbstractTile) tile).setScaleImage(false); - - this.repaint(); - } - - 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 Switch aSwitch) { - if (this.displayRouteCB.isSelected()) { - aSwitch.setRouteValue(getAccessoryState()); - } else { - aSwitch.setValue(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); - } - } - - 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); - } - } - - 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() { - 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(); - } - - 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() { - 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); - } - TileFactory.fireTileEventListener(tileEvent); - - //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(); - drawOutlineCB = new javax.swing.JCheckBox(); - cPanel = new javax.swing.JPanel(); - - setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); - - 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); - - drawOutlineCB.setText("Outline"); - drawOutlineCB.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - drawOutlineCBActionPerformed(evt); - } - }); - nPanel.add(drawOutlineCB); - - getContentPane().add(nPanel, java.awt.BorderLayout.NORTH); - - cPanel.setPreferredSize(new java.awt.Dimension(1000, 1000)); - cPanel.setLayout(null); - getContentPane().add(cPanel, 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 - drawTile(); - }//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 drawOutlineCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_drawOutlineCBActionPerformed - showOutline(); - }//GEN-LAST:event_drawOutlineCBActionPerformed - - private void incomingSideCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_incomingSideCBActionPerformed - changeIncomingSide(); - }//GEN-LAST:event_incomingSideCBActionPerformed - - /** - * @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(() -> { - UnscaledTileFrame app = new UnscaledTileFrame(); - app.setTitle("Unscaled Tile Tester"); - app.pack(); - 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 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; - 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.JComboBox tileCB; - // End of variables declaration//GEN-END:variables -} diff --git a/src/test/resources/autopilot_test_layout.sql b/src/test/resources/autopilot_test_layout.sql index 4e5f7acb..e82660d2 100644 --- a/src/test/resources/autopilot_test_layout.sql +++ b/src/test/resources/autopilot_test_layout.sql @@ -47,68 +47,67 @@ 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 ('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); -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); +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 - ('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; - 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 0c126644..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) 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, 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/images/DHG 6505.png b/src/test/resources/images/DHG 6505.png new file mode 100644 index 00000000..1d577744 Binary files /dev/null and b/src/test/resources/images/DHG 6505.png differ diff --git a/src/test/resources/jcs-test-data-h2.sql b/src/test/resources/jcs-test-data-h2.sql index 56250c30..2b5a4bef 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; @@ -20,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 - ('65-1', 'M1',65,1,0,0,0,NULL), - ('65-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, 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; @@ -76,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),