getKnownActiveBands() {
+ return knownActiveBands;
+ }
+
+
+ /**
+ * If a sked fails and the user tells this to the client, this counter will be increased to give the station a
+ * lower score
+ */
+ public void incrementFailedAttempts() {
+ this.failedQSOAttempts++;
+ }
+
+ public void resetFailedAttempts() {
+ this.failedQSOAttempts = 0;
+ }
+
+ public int getFailedQSOAttempts() {
+ return failedQSOAttempts;
+ }
+
+ /**
+ * Sets the working-priority score of a chatmember for the "Todo-List"
+ * @param score
+ */
+ public void setCurrentPriorityScore(double score) {
+ this.currentPriorityScore = score;
+ }
+
+ /**
+ * Gets the working-priority score of a chatmember for the "Todo-List"
+ *
+ */
+ public double getCurrentPriorityScore() {
+ return currentPriorityScore;
+ }
+
+
}
\ No newline at end of file
diff --git a/src/main/java/kst4contest/model/ChatPreferences.java b/src/main/java/kst4contest/model/ChatPreferences.java
index 59bc8fa..f162bf7 100644
--- a/src/main/java/kst4contest/model/ChatPreferences.java
+++ b/src/main/java/kst4contest/model/ChatPreferences.java
@@ -18,6 +18,7 @@ import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
+import javafx.beans.property.*;
import kst4contest.ApplicationConstants;
import kst4contest.utils.ApplicationFileUtils;
import org.w3c.dom.Document;
@@ -26,15 +27,34 @@ import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
-import javafx.beans.property.IntegerProperty;
-import javafx.beans.property.SimpleIntegerProperty;
-import javafx.beans.property.SimpleStringProperty;
-import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
+/**
+ * refactored version if ChatPreferences
+ */
public class ChatPreferences {
+
+ // Main window: right split pane (ChatMember table / Priority list / FurtherInfo)
+ // 3 items => 2 dividers => 2 positions.
+ private double[] GUImainWindowRightSplitPane_dividerposition = new double[] { 0.53, 0.78 };
+
+ // Defaults used for config upgrades / first start.
+ private final double[] GUImainWindowRightSplitPane_dividerpositionDefault = new double[] { 0.53, 0.78 };
+
+
+ /**
+ * Bump this when you change the XML schema written by {@link #writePreferencesToXmlFile()}.
+ *
+ * Reading must stay backwards compatible: missing/unknown tags should fall back to defaults.
+ */
+// private static final int CONFIG_VERSION = 2;
+ public static final int CONFIG_VERSION = 3;
+
+ // Prefer writing tag names that mirror variable names (human readable). Keep legacy tags for compatibility.
+ private static final String TAG_CONFIG_VERSION = "configVersion";
+
/**
* Name of file to store preferences in.
*/
@@ -50,12 +70,14 @@ public class ChatPreferences {
/**
* Default constructor will set the default values (also for predefined texts
* and shorts) automatically at initialization
- *
+ *
* TODO: delete this from the kst4contest.view/Main.java!
*/
public ChatPreferences() {
ApplicationFileUtils.copyResourceIfRequired(ApplicationConstants.APPLICATION_NAME, PREFERENCE_RESOURCE, PREFERENCES_FILE);
+// lstNotify_QSOSniffer_sniffedCallSignList.add("DF0GEB");
+
// shortcuts[2] = "pse";
// shortcuts[3] = "turn";
// shortcuts[4] = "ant";
@@ -91,7 +113,7 @@ public class ChatPreferences {
// shortcuts[34] = "!";
// shortcuts[35] = ",";
// shortcuts[36] = "MYQRG";
-//
+//
// textSnippets[0] = "Hi OM, try sked?";
// textSnippets[1] = "I am calling cq ur dir, pse lsn to me at ";
// textSnippets[2] = "pse ur qrg?";
@@ -99,15 +121,15 @@ public class ChatPreferences {
// textSnippets[4] = "Hrd you but many qrm here, pse agn";
//
// textSnippets[5] = "I turn my ant to you";
-//
-// textSnippets[6] = "Sry, strong qrm by local station there, may try ";
+//
+// textSnippets[6] = "Sry, strong qrm by local station there, may try ";
// textSnippets[7] = "Sry, in qso nw, pse qrx, I will meep you";
-//
+//
// textSnippets[8] = "Ur ant my dir nw?";
// textSnippets[9] = "nil?";
// textSnippets[10] = "No cw op here, could we use ssb?";
-// textSnippets[11] = "No chance in ssb, could we use cw?";
-//
+// textSnippets[11] = "No chance in ssb, could we use cw?";
+//
// textSnippets[12] = "Nil till now, are you calling?";
// textSnippets[13] = "Nil, I will look for an ap";
// textSnippets[14] = "Tnx try, maybe later!";
@@ -118,7 +140,7 @@ public class ChatPreferences {
* Preferences for the preferences
* kst4contest@googlegroups.com
* praktimarc+kst4contest@gmail.com
- *
+ *
*/
String programVersion = "Chat is powered by ON4KST \n\nUsage is free. You are welcome to support: \n\n- my project (donations, bugreports, good ideas are welcome), \n- ON4KST Servers, \n- AirScout developers and \n- OV3T (best AS-data provider of the world). \n\n73 de DO5AMF, Marc (DM5M / DARC X08)";
@@ -131,8 +153,16 @@ public class ChatPreferences {
* Station preferences
*/
+
+
+ String stn_on4kstServersDns = "www.on4kst.org";
+ int stn_on4kstServersPort = 23001;
+
+ boolean stn_pstRotatorEnabled = false;
+
boolean stn_loginAFKState = false; //always start as here
String stn_loginCallSign = "do5amf";
+ String stn_loginCallSignRaw = "do5amf"; //for example: do5amf instead of logincallsign do5amf-2
String stn_loginPassword = "";
String stn_loginNameMainCat = "KST4Contest";
String stn_loginNameSecondCat = "KST4ContestSHF";
@@ -146,7 +176,7 @@ public class ChatPreferences {
ChatCategory loginChatCategoryMain = new ChatCategory(2);
ChatCategory loginChatCategorySecond = new ChatCategory(3);
boolean loginToSecondChatEnabled;
- IntegerProperty actualQTF = new SimpleIntegerProperty(360); // will be updated by user at runtime!
+ DoubleProperty actualQTF = new SimpleDoubleProperty(360); // will be updated by user at runtime!
boolean stn_bandActive144;
boolean stn_bandActive432;
@@ -165,11 +195,20 @@ public class ChatPreferences {
int logsynch_ucxUDPWkdCallListenerPort = 12060;
boolean logsynch_ucxUDPWkdCallListenerEnabled = true;
+ String logsynch_wintestNetworkStationNameOfKST = "KST4Contest";
+ String logsynch_wintestNetworkStationNameOfWintestClient1 = "STN1";
+ boolean logsynch_wintestNetworkSimulationEnabled = false;
+ int logsynch_wintestNetworkStationIDOfKST = 55555;
+ int logsynch_wintestNetworkPort = 9871;
+ boolean logsynch_wintestNetworkListenerEnabled = true; // default true = bisheriges Verhalten
+
+
+
/**
* TRX Synch prefs
*/
StringProperty MYQRGFirstCat = new SimpleStringProperty(); // own qrg will be set by user entry or ucxlog if trx Synch is
- // activated
+ // activated
StringProperty MYQRGSecondCat = new SimpleStringProperty(); // own qrg will be set by user entry or ucxlog if trx Synch is activated
boolean trxSynch_ucxLogUDPListenerEnabled = false;
@@ -185,6 +224,8 @@ public class ChatPreferences {
* Notification prefs
*/
+
+
//Audio section
boolean notify_playSimpleSounds = true;
boolean notify_playCWCallsignsOnRxedPMs = true;
@@ -200,6 +241,18 @@ public class ChatPreferences {
boolean notify_DXClusterServerTriggerBearing;
boolean notify_DXClusterServerTriggerOnQRGDetect;
+ // ObservableList lstNotify_QSOSniffer_sniffedCallSignList = FXCollections.observableArrayList();
+ ObservableList lstNotify_QSOSniffer_sniffedWordsList = FXCollections.observableArrayList();
+ ObservableList lstNotify_QSOSniffer_sniffedPrefixLocList = FXCollections.observableArrayList();
+
+ // Scoring / interaction metrics
+ int notify_noReplyPenaltyMinutes = 13; // if we ping via /cq and no response arrives within X minutes => penalty strike
+ int notify_momentumWindowSeconds = 180; // momentum window size (count inbound lines)
+ String notify_positiveSignalsPatterns = "QRV;READY;RX;RGR;RR;OK;YES;TNX;TU;HEARD;LSN"; //TODO: to be continued
+
+ boolean notify_bandUpgradeHintOnLogEnabled = true; // show hint after log entry if station QRV on other unworked enabled band
+ boolean notify_bandUpgradePriorityBoostEnabled = false; // optional score boost to make it stand out in toplists
+
/**
* Shortcuts and Textsnippets prefs
@@ -258,15 +311,18 @@ public class ChatPreferences {
*
*********************************************************************************/
+ private boolean GUI_darkModeActive = false;
+ private boolean GUI_darkModeActiveByDefault = false;
+
private double[] GUIscn_ChatwindowMainSceneSizeHW = new double[] {768, 1234};
private double[] GUIclusterAndQSOMonStage_SceneSizeHW = new double[] {700, 500};
- private double[] GUIstage_updateStage_SceneSizeHW = new double[] {640, 480};
+ private double[] GUIstage_updateStage_SceneSizeHW = new double[] {580, 480};
private double[] GUIsettingsStageSceneSizeHW = new double[] {720, 768};
private double[] GUIselectedCallSignSplitPane_dividerposition = {0.55};
private double[] GUImainWindowLeftSplitPane_dividerposition = {0.51};
- private double[] GUImessageSectionSplitpane_dividerposition = {0.62, 0.7, 0.75}; //3 deviders now //TODO: more should be possible?
- private double[] GUImainWindowRightSplitPane_dividerposition = {0.72};
+ private double[] GUImessageSectionSplitpane_dividerposition = {0.62, 0.7, 0.75, 0.9}; //3 deviders now //TODO: more should be possible?
+// private double[] GUImainWindowRightSplitPane_dividerposition = {0.72};
private double[] GUIpnl_directedMSGWin_dividerpositionDefault = {0.8};
@@ -318,6 +374,86 @@ public class ChatPreferences {
this.stn_loginNameSecondCat = stn_loginNameSecondCat;
}
+ public int getStn_on4kstServersPort() {
+ return stn_on4kstServersPort;
+ }
+
+ public void setStn_on4kstServersPort(int stn_on4kstServersPort) {
+ this.stn_on4kstServersPort = stn_on4kstServersPort;
+ }
+
+ public String getStn_on4kstServersDns() {
+ return stn_on4kstServersDns;
+ }
+
+ public void setStn_on4kstServersDns(String stn_on4kstServersDns) {
+ this.stn_on4kstServersDns = stn_on4kstServersDns;
+ }
+
+ public ObservableList getLstNotify_QSOSniffer_sniffedWordsList() {
+ return lstNotify_QSOSniffer_sniffedWordsList;
+ }
+
+ public void setLstNotify_QSOSniffer_sniffedWordsList(ObservableList lstNotify_QSOSniffer_sniffedWordsList) {
+ this.lstNotify_QSOSniffer_sniffedWordsList = lstNotify_QSOSniffer_sniffedWordsList;
+ }
+
+ public ObservableList getLstNotify_QSOSniffer_sniffedPrefixLocList() {
+ return lstNotify_QSOSniffer_sniffedPrefixLocList;
+ }
+
+ public void setLstNotify_QSOSniffer_sniffedPrefixLocList(ObservableList lstNotify_QSOSniffer_sniffedPrefixLocList) {
+ this.lstNotify_QSOSniffer_sniffedPrefixLocList = lstNotify_QSOSniffer_sniffedPrefixLocList;
+ }
+
+ public String getLogsynch_wintestNetworkStationNameOfKST() {
+ return logsynch_wintestNetworkStationNameOfKST;
+ }
+
+ public void setLogsynch_wintestNetworkStationNameOfKST(String logsynch_wintestNetworkStationNameOfKST) {
+ this.logsynch_wintestNetworkStationNameOfKST = logsynch_wintestNetworkStationNameOfKST;
+ }
+
+ public String getLogsynch_wintestNetworkStationNameOfWintestClient1() {
+ return logsynch_wintestNetworkStationNameOfWintestClient1;
+ }
+
+ public void setLogsynch_wintestNetworkStationNameOfWintestClient1(String logsynch_wintestNetworkStationNameOfWintestClient1) {
+ this.logsynch_wintestNetworkStationNameOfWintestClient1 = logsynch_wintestNetworkStationNameOfWintestClient1;
+ }
+
+ public boolean isLogsynch_wintestNetworkSimulationEnabled() {
+ return logsynch_wintestNetworkSimulationEnabled;
+ }
+
+ public void setLogsynch_wintestNetworkSimulationEnabled(boolean logsynch_wintestNetworkSimulationEnabled) {
+ this.logsynch_wintestNetworkSimulationEnabled = logsynch_wintestNetworkSimulationEnabled;
+ }
+
+ public int getLogsynch_wintestNetworkStationIDOfKST() {
+ return logsynch_wintestNetworkStationIDOfKST;
+ }
+
+ public void setLogsynch_wintestNetworkStationIDOfKST(int logsynch_wintestNetworkStationIDOfKST) {
+ this.logsynch_wintestNetworkStationIDOfKST = logsynch_wintestNetworkStationIDOfKST;
+ }
+
+ public int getLogsynch_wintestNetworkPort() {
+ return logsynch_wintestNetworkPort;
+ }
+
+ public void setLogsynch_wintestNetworkPort(int logsynch_wintestNetworkPort) {
+ this.logsynch_wintestNetworkPort = logsynch_wintestNetworkPort;
+ }
+
+ public boolean isLogsynch_wintestNetworkListenerEnabled() {
+ return logsynch_wintestNetworkListenerEnabled;
+ }
+
+ public void setLogsynch_wintestNetworkListenerEnabled(boolean logsynch_wintestNetworkListenerEnabled) {
+ this.logsynch_wintestNetworkListenerEnabled = logsynch_wintestNetworkListenerEnabled;
+ }
+
public String getStn_loginLocatorSecondCat() {
return stn_loginLocatorSecondCat;
}
@@ -458,6 +594,56 @@ public class ChatPreferences {
this.notify_dxClusterServerEnabled = notify_dxClusterServerEnabled;
}
+
+ public int getNotify_noReplyPenaltyMinutes() {
+ return notify_noReplyPenaltyMinutes;
+ }
+
+ public void setNotify_noReplyPenaltyMinutes(int notify_noReplyPenaltyMinutes) {
+ this.notify_noReplyPenaltyMinutes = notify_noReplyPenaltyMinutes;
+ }
+
+ public int getNotify_momentumWindowSeconds() {
+ return notify_momentumWindowSeconds;
+ }
+
+ public void setNotify_momentumWindowSeconds(int notify_momentumWindowSeconds) {
+ this.notify_momentumWindowSeconds = notify_momentumWindowSeconds;
+ }
+
+ public String getNotify_positiveSignalsPatterns() {
+ return notify_positiveSignalsPatterns;
+ }
+
+ public void setNotify_positiveSignalsPatterns(String notify_positiveSignalsPatterns) {
+ this.notify_positiveSignalsPatterns = notify_positiveSignalsPatterns;
+ }
+
+
+ public boolean isNotify_bandUpgradePriorityBoostEnabled() {
+ return notify_bandUpgradePriorityBoostEnabled;
+ }
+
+ public void setNotify_bandUpgradePriorityBoostEnabled(boolean notify_bandUpgradePriorityBoostEnabled) {
+ this.notify_bandUpgradePriorityBoostEnabled = notify_bandUpgradePriorityBoostEnabled;
+ }
+
+ public boolean isNotify_bandUpgradeHintOnLogEnabled() {
+ return notify_bandUpgradeHintOnLogEnabled;
+ }
+
+ public void setNotify_bandUpgradeHintOnLogEnabled(boolean notify_bandUpgradeHintOnLogEnabled) {
+ this.notify_bandUpgradeHintOnLogEnabled = notify_bandUpgradeHintOnLogEnabled;
+ }
+
+ public boolean isStn_pstRotatorEnabled() {
+ return stn_pstRotatorEnabled;
+ }
+
+ public void setStn_pstRotatorEnabled(boolean stn_pstRotatorEnabled) {
+ this.stn_pstRotatorEnabled = stn_pstRotatorEnabled;
+ }
+
public SimpleStringProperty getNotify_optionalFrequencyPrefix() {
return notify_optionalFrequencyPrefix;
}
@@ -526,18 +712,24 @@ public class ChatPreferences {
return GUImessageSectionSplitpane_dividerposition;
}
- public void setGUImessageSectionSplitpane_dividerposition(double[] GUImessageSectionSplitpane_dividerposition) {
- this.GUImessageSectionSplitpane_dividerposition = GUImessageSectionSplitpane_dividerposition;
- }
-
public double[] getGUImainWindowRightSplitPane_dividerposition() {
return GUImainWindowRightSplitPane_dividerposition;
}
- public void setGUImainWindowRightSplitPane_dividerposition(double[] GUImainWindowRightSplitPane_dividerposition) {
- this.GUImainWindowRightSplitPane_dividerposition = GUImainWindowRightSplitPane_dividerposition;
+ public void setGUImessageSectionSplitpane_dividerposition(double[] GUImessageSectionSplitpane_dividerposition) {
+ this.GUImessageSectionSplitpane_dividerposition = GUImessageSectionSplitpane_dividerposition;
}
+
+
+ public void setGUImainWindowRightSplitPane_dividerposition(double[] positions) {
+ this.GUImainWindowRightSplitPane_dividerposition = positions;
+ }
+
+// public void setGUImainWindowRightSplitPane_dividerposition(double[] GUImainWindowRightSplitPane_dividerposition) {
+// this.GUImainWindowRightSplitPane_dividerposition = GUImainWindowRightSplitPane_dividerposition;
+// }
+
public double[] getGUIpnl_directedMSGWin_dividerpositionDefault() {
return GUIpnl_directedMSGWin_dividerpositionDefault;
}
@@ -582,6 +774,10 @@ public class ChatPreferences {
return stn_loginCallSign;
}
+ public String getStn_loginCallSignRaw() {
+ return stn_loginCallSignRaw;
+ }
+
public String getAirScout_asBandString() {
return AirScout_asBandString;
}
@@ -680,11 +876,11 @@ public class ChatPreferences {
return MYQRGFirstCat;
}
- public IntegerProperty getActualQTF() {
+ public DoubleProperty getActualQTF() {
return actualQTF;
}
- public void setActualQTF(IntegerProperty actualQTF) {
+ public void setActualQTF(DoubleProperty actualQTF) {
this.actualQTF = actualQTF;
}
@@ -693,7 +889,24 @@ public class ChatPreferences {
}
public void setStn_loginCallSign(String stn_loginCallSign) {
+
this.stn_loginCallSign = stn_loginCallSign;
+ this.stn_loginCallSignRaw = stn_loginCallSign;
+
+ if (stn_loginCallSign.contains("-")) {
+
+ this.stn_loginCallSignRaw = stn_loginCallSign.split("-")[0];
+
+ } else if (stn_loginCallSign.contains("/")) {
+
+ this.stn_loginCallSignRaw = stn_loginCallSign.split("/")[0];
+
+ }
+
+ if ((stn_loginCallSign.split("-").length > 2 ) || stn_loginCallSign.split("/").length > 2) {
+ System.out.println("ChatPreferences, WARNING! Logincallsign is not plausible"); //strange login like do5-amf-2
+ }
+
}
public String getStn_loginPassword() {
@@ -846,8 +1059,8 @@ public class ChatPreferences {
this.bcn_beaconTextMainCat = bcn_beaconTextMainCat;
}
-
-
+
+
public String messageHandling_beaconUnworkedstationsPrefix() {
return messageHandling_beaconUnworkedstationsPrefix;
}
@@ -900,48 +1113,72 @@ public class ChatPreferences {
/**
- *
+ *
* @return true if the file writing was successful, else false
*/
public boolean writePreferencesToXmlFile() {
-
+
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
try {
- // root elements
- DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
- Document doc = docBuilder.newDocument();
- Element rootElement = doc.createElement("praktiKST");
- doc.appendChild(rootElement);
- Element station = doc.createElement("station");
- rootElement.appendChild(station);
-
- Element LoginCallSign = doc.createElement("LoginCallSign");
- LoginCallSign.setTextContent(this.getStn_loginCallSign());
- station.appendChild(LoginCallSign);
-
+ // root elements
+ DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
+ Document doc = docBuilder.newDocument();
+ Element rootElement = doc.createElement("praktiKST");
+ doc.appendChild(rootElement);
- Element LoginPassword = doc.createElement("LoginPassword");
- LoginPassword.setTextContent(this.getStn_loginPassword());
- station.appendChild(LoginPassword);
+ // Schema version
+ Element configVersion = doc.createElement("configVersion");
+ configVersion.setTextContent(String.valueOf(CONFIG_VERSION));
+ rootElement.appendChild(configVersion);
- Element LoginDisplayedName = doc.createElement("LoginDisplayedName");
- LoginDisplayedName.setTextContent(this.getStn_loginNameMainCat());
- station.appendChild(LoginDisplayedName);
+
+ Element station = doc.createElement("station");
+ rootElement.appendChild(station);
+
+ Element LoginCallSign = doc.createElement("LoginCallSign");
+ LoginCallSign.setTextContent(this.getStn_loginCallSign());
+ station.appendChild(LoginCallSign);
+
+ // New preferred tag names (closer to variable names). Keep legacy tags above for old versions.
+ Element stn_loginCallSign = doc.createElement("stn_loginCallSign");
+ stn_loginCallSign.setTextContent(this.getStn_loginCallSign());
+ station.appendChild(stn_loginCallSign);
+
+
+ Element LoginPassword = doc.createElement("LoginPassword");
+ LoginPassword.setTextContent(this.getStn_loginPassword());
+ station.appendChild(LoginPassword);
+
+ Element stn_loginPassword = doc.createElement("stn_loginPassword");
+ stn_loginPassword.setTextContent(this.getStn_loginPassword());
+ station.appendChild(stn_loginPassword);
+
+ Element LoginDisplayedName = doc.createElement("LoginDisplayedName");
+ LoginDisplayedName.setTextContent(this.getStn_loginNameMainCat());
+ station.appendChild(LoginDisplayedName);
+
+ Element stn_loginNameMainCat = doc.createElement("stn_loginNameMainCat");
+ stn_loginNameMainCat.setTextContent(this.getStn_loginNameMainCat());
+ station.appendChild(stn_loginNameMainCat);
Element stn_loginNameSecondCat = doc.createElement("stn_loginNameSecondCat");
stn_loginNameSecondCat.setTextContent(this.getStn_loginNameSecondCat());
station.appendChild(stn_loginNameSecondCat);
- Element LoginLocator = doc.createElement("LoginLocator");
- LoginLocator.setTextContent(this.getStn_loginLocatorMainCat());
- station.appendChild(LoginLocator);
+ Element LoginLocator = doc.createElement("LoginLocator");
+ LoginLocator.setTextContent(this.getStn_loginLocatorMainCat());
+ station.appendChild(LoginLocator);
- Element ChatCategory = doc.createElement("ChatCategory");
- ChatCategory.setTextContent(this.getLoginChatCategoryMain().getCategoryNumber()+"");
- station.appendChild(ChatCategory);
+ Element stn_loginLocatorMainCat = doc.createElement("stn_loginLocatorMainCat");
+ stn_loginLocatorMainCat.setTextContent(this.getStn_loginLocatorMainCat());
+ station.appendChild(stn_loginLocatorMainCat);
+
+ Element ChatCategory = doc.createElement("ChatCategory");
+ ChatCategory.setTextContent(this.getLoginChatCategoryMain().getCategoryNumber()+"");
+ station.appendChild(ChatCategory);
Element ChatCategorySecond = doc.createElement("ChatCategorySecond");
ChatCategorySecond.setTextContent(this.getLoginChatCategorySecond().getCategoryNumber()+"");
@@ -991,79 +1228,126 @@ public class ChatPreferences {
stn_bandActive10G.setTextContent(this.stn_bandActive10G+"");
station.appendChild(stn_bandActive10G);
- /**
- * LOGSYNCH
- */
+ Element stn_on4kstServersDns = doc.createElement("stn_on4kstServersDns");
+ stn_on4kstServersDns.setTextContent(this.stn_on4kstServersDns);
+ station.appendChild(stn_on4kstServersDns);
- Element logsynch = doc.createElement("logsynch");
- rootElement.appendChild(logsynch);
+ Element stn_on4kstServersPort = doc.createElement("stn_on4kstServersPort");
+ stn_on4kstServersPort.setTextContent(this.stn_on4kstServersPort + "");
+ station.appendChild(stn_on4kstServersPort);
- Element logsynch_fileBasedWkdCallInterpreterFileNameReadOnly = doc.createElement("logsynch_fileBasedWkdCallInterpreterFileNameReadOnly");
- logsynch_fileBasedWkdCallInterpreterFileNameReadOnly.setTextContent(this.getLogsynch_fileBasedWkdCallInterpreterFileNameReadOnly());
- logsynch.appendChild(logsynch_fileBasedWkdCallInterpreterFileNameReadOnly);
+ Element stn_loginAFKState = doc.createElement("stn_loginAFKState");
+ stn_loginAFKState.setTextContent(this.stn_loginAFKState + "");
+ station.appendChild(stn_loginAFKState);
- Element logsynch_storeWorkedCallSignsFileNameUDPMessageBackup = doc.createElement("logsynch_storeWorkedCallSignsFileNameUDPMessageBackup");
- logsynch_storeWorkedCallSignsFileNameUDPMessageBackup.setTextContent(this.getLogsynch_storeWorkedCallSignsFileNameUDPMessageBackup());
- logsynch.appendChild(logsynch_storeWorkedCallSignsFileNameUDPMessageBackup);
+ Element stn_pstRotatorEnabled = doc.createElement("stn_pstRotatorEnabled");
+ stn_pstRotatorEnabled.setTextContent(this.stn_pstRotatorEnabled + "");
+ station.appendChild(stn_pstRotatorEnabled);
- Element logsynch_fileBasedWkdCallInterpreterEnabled = doc.createElement("logsynch_fileBasedWkdCallInterpreterEnabled");
- logsynch_fileBasedWkdCallInterpreterEnabled.setTextContent(this.isLogsynch_fileBasedWkdCallInterpreterEnabled()+"");
- logsynch.appendChild(logsynch_fileBasedWkdCallInterpreterEnabled);
- Element logsynch_ucxUDPWkdCallListenerPort = doc.createElement("logsynch_ucxUDPWkdCallListenerPort");
- logsynch_ucxUDPWkdCallListenerPort.setTextContent(this.getLogsynch_ucxUDPWkdCallListenerPort()+"");
- logsynch.appendChild(logsynch_ucxUDPWkdCallListenerPort);
- Element logsynch_ucxUDPWkdCallListenerEnabled = doc.createElement("logsynch_ucxUDPWkdCallListenerEnabled");
- logsynch_ucxUDPWkdCallListenerEnabled.setTextContent(this.isTrxSynch_ucxLogUDPListenerEnabled()+"");
- logsynch.appendChild(logsynch_ucxUDPWkdCallListenerEnabled);
-
-
- /**
- * trxSynchUCX
- */
+ /**
+ * LOGSYNCH
+ */
- Element trxSynchUCX = doc.createElement("trxSynchUCX");
- rootElement.appendChild(trxSynchUCX);
-
- Element trxSynch_ucxLogUDPListenerEnabled = doc.createElement("trxSynch_ucxLogUDPListenerEnabled");
- trxSynch_ucxLogUDPListenerEnabled.setTextContent(this.isTrxSynch_ucxLogUDPListenerEnabled()+"");
- trxSynchUCX.appendChild(trxSynch_ucxLogUDPListenerEnabled);
-
- Element trxSynch_defaultMYQRGValue = doc.createElement("trxSynch_defaultMYQRGValue");
- trxSynch_defaultMYQRGValue.setTextContent(this.getMYQRGFirstCat().getValue());
- trxSynchUCX.appendChild(trxSynch_defaultMYQRGValue);
+ Element logsynch = doc.createElement("logsynch");
+ rootElement.appendChild(logsynch);
-
-
-
- /**
- * AirScout
- */
+ Element logsynch_fileBasedWkdCallInterpreterFileNameReadOnly = doc.createElement("logsynch_fileBasedWkdCallInterpreterFileNameReadOnly");
+ logsynch_fileBasedWkdCallInterpreterFileNameReadOnly.setTextContent(this.getLogsynch_fileBasedWkdCallInterpreterFileNameReadOnly());
+ logsynch.appendChild(logsynch_fileBasedWkdCallInterpreterFileNameReadOnly);
- Element AirScoutQuerier = doc.createElement("AirScoutQuerier");
- rootElement.appendChild(AirScoutQuerier);
-
-
- Element asQry_airScoutCommunicationEnabled = doc.createElement("asQry_airScoutCommunicationEnabled");
- asQry_airScoutCommunicationEnabled.setTextContent(this.isAirScout_asUDPListenerEnabled()+"");
- AirScoutQuerier.appendChild(asQry_airScoutCommunicationEnabled);
+ Element logsynch_storeWorkedCallSignsFileNameUDPMessageBackup = doc.createElement("logsynch_storeWorkedCallSignsFileNameUDPMessageBackup");
+ logsynch_storeWorkedCallSignsFileNameUDPMessageBackup.setTextContent(this.getLogsynch_storeWorkedCallSignsFileNameUDPMessageBackup());
+ logsynch.appendChild(logsynch_storeWorkedCallSignsFileNameUDPMessageBackup);
- Element asQry_airScoutServerName = doc.createElement("asQry_airScoutServerName");
- asQry_airScoutServerName.setTextContent(this.getAirScout_asServerNameString());
- AirScoutQuerier.appendChild(asQry_airScoutServerName);
-
- Element asQry_airScoutClientName = doc.createElement("asQry_airScoutClientName");
- asQry_airScoutClientName.setTextContent(this.getAirScout_asClientNameString());
- AirScoutQuerier.appendChild(asQry_airScoutClientName);
-
- Element asQry_airScoutUDPPort = doc.createElement("asQry_airScoutUDPPort");
- asQry_airScoutUDPPort.setTextContent(this.getAirScout_asCommunicationPort()+"");
- AirScoutQuerier.appendChild(asQry_airScoutUDPPort);
-
- Element asQry_airScoutBandValue = doc.createElement("asQry_airScoutBandValue");
- asQry_airScoutBandValue.setTextContent(this.getAirScout_asBandString());
- AirScoutQuerier.appendChild(asQry_airScoutBandValue);
+ Element logsynch_fileBasedWkdCallInterpreterEnabled = doc.createElement("logsynch_fileBasedWkdCallInterpreterEnabled");
+ logsynch_fileBasedWkdCallInterpreterEnabled.setTextContent(this.isLogsynch_fileBasedWkdCallInterpreterEnabled()+"");
+ logsynch.appendChild(logsynch_fileBasedWkdCallInterpreterEnabled);
+
+ Element logsynch_ucxUDPWkdCallListenerPort = doc.createElement("logsynch_ucxUDPWkdCallListenerPort");
+ logsynch_ucxUDPWkdCallListenerPort.setTextContent(this.getLogsynch_ucxUDPWkdCallListenerPort()+"");
+ logsynch.appendChild(logsynch_ucxUDPWkdCallListenerPort);
+
+ Element logsynch_ucxUDPWkdCallListenerEnabled = doc.createElement("logsynch_ucxUDPWkdCallListenerEnabled");
+ // BUGFIX: this is the log-synch listener flag, not the TRX-synch flag (copy&paste error in older versions)
+ logsynch_ucxUDPWkdCallListenerEnabled.setTextContent(this.isLogsynch_ucxUDPWkdCallListenerEnabled()+"");
+ logsynch.appendChild(logsynch_ucxUDPWkdCallListenerEnabled);
+
+ // WinTest Settings
+ Element logsynch_wintestNetworkStationNameOfKST = doc.createElement("logsynch_wintestNetworkStationNameOfKST");
+ logsynch_wintestNetworkStationNameOfKST.setTextContent(this.logsynch_wintestNetworkStationNameOfKST);
+ logsynch.appendChild(logsynch_wintestNetworkStationNameOfKST);
+
+ Element logsynch_wintestNetworkStationNameOfWintestClient1 = doc.createElement("logsynch_wintestNetworkStationNameOfWintestClient1");
+ logsynch_wintestNetworkStationNameOfWintestClient1.setTextContent(this.logsynch_wintestNetworkStationNameOfWintestClient1);
+ logsynch.appendChild(logsynch_wintestNetworkStationNameOfWintestClient1);
+
+ Element logsynch_wintestNetworkSimulationEnabled = doc.createElement("logsynch_wintestNetworkSimulationEnabled");
+ logsynch_wintestNetworkSimulationEnabled.setTextContent(this.logsynch_wintestNetworkSimulationEnabled + "");
+ logsynch.appendChild(logsynch_wintestNetworkSimulationEnabled);
+
+ Element logsynch_wintestNetworkStationIDOfKST = doc.createElement("logsynch_wintestNetworkStationIDOfKST");
+ logsynch_wintestNetworkStationIDOfKST.setTextContent(this.logsynch_wintestNetworkStationIDOfKST + "");
+ logsynch.appendChild(logsynch_wintestNetworkStationIDOfKST);
+
+ Element logsynch_wintestNetworkPort = doc.createElement("logsynch_wintestNetworkPort");
+ logsynch_wintestNetworkPort.setTextContent(this.logsynch_wintestNetworkPort + "");
+ logsynch.appendChild(logsynch_wintestNetworkPort);
+
+ Element logsynch_wintestNetworkListenerEnabled = doc.createElement("logsynch_wintestNetworkListenerEnabled");
+ logsynch_wintestNetworkListenerEnabled.setTextContent(this.logsynch_wintestNetworkListenerEnabled + "");
+ logsynch.appendChild(logsynch_wintestNetworkListenerEnabled);
+
+
+ /**
+ * trxSynchUCX
+ */
+
+ Element trxSynchUCX = doc.createElement("trxSynchUCX");
+ rootElement.appendChild(trxSynchUCX);
+
+ Element trxSynch_ucxLogUDPListenerEnabled = doc.createElement("trxSynch_ucxLogUDPListenerEnabled");
+ trxSynch_ucxLogUDPListenerEnabled.setTextContent(this.isTrxSynch_ucxLogUDPListenerEnabled()+"");
+ trxSynchUCX.appendChild(trxSynch_ucxLogUDPListenerEnabled);
+
+ Element trxSynch_defaultMYQRGValue = doc.createElement("trxSynch_defaultMYQRGValue");
+ trxSynch_defaultMYQRGValue.setTextContent(this.getMYQRGFirstCat().getValue());
+ trxSynchUCX.appendChild(trxSynch_defaultMYQRGValue);
+
+ Element trxSynch_defaultMYQRG2Value = doc.createElement("trxSynch_defaultMYQRG2Value");
+ // Safe null check falls Property noch nicht initialisiert ist
+ trxSynch_defaultMYQRG2Value.setTextContent(this.getMYQRGSecondCat().getValue() != null ? this.getMYQRGSecondCat().getValue() : "1296.200.00");
+ trxSynchUCX.appendChild(trxSynch_defaultMYQRG2Value);
+
+
+ /**
+ * AirScout
+ */
+
+ Element AirScoutQuerier = doc.createElement("AirScoutQuerier");
+ rootElement.appendChild(AirScoutQuerier);
+
+
+ Element asQry_airScoutCommunicationEnabled = doc.createElement("asQry_airScoutCommunicationEnabled");
+ asQry_airScoutCommunicationEnabled.setTextContent(this.isAirScout_asUDPListenerEnabled()+"");
+ AirScoutQuerier.appendChild(asQry_airScoutCommunicationEnabled);
+
+ Element asQry_airScoutServerName = doc.createElement("asQry_airScoutServerName");
+ asQry_airScoutServerName.setTextContent(this.getAirScout_asServerNameString());
+ AirScoutQuerier.appendChild(asQry_airScoutServerName);
+
+ Element asQry_airScoutClientName = doc.createElement("asQry_airScoutClientName");
+ asQry_airScoutClientName.setTextContent(this.getAirScout_asClientNameString());
+ AirScoutQuerier.appendChild(asQry_airScoutClientName);
+
+ Element asQry_airScoutUDPPort = doc.createElement("asQry_airScoutUDPPort");
+ asQry_airScoutUDPPort.setTextContent(this.getAirScout_asCommunicationPort()+"");
+ AirScoutQuerier.appendChild(asQry_airScoutUDPPort);
+
+ Element asQry_airScoutBandValue = doc.createElement("asQry_airScoutBandValue");
+ asQry_airScoutBandValue.setTextContent(this.getAirScout_asBandString());
+ AirScoutQuerier.appendChild(asQry_airScoutBandValue);
/**
@@ -1071,13 +1355,13 @@ public class ChatPreferences {
*/
Element notifications = doc.createElement("notifications");
- rootElement.appendChild(notifications);
+ rootElement.appendChild(notifications);
- Element notify_SimpleAudioNotificationsEnabled = doc.createElement("notify_SimpleAudioNotificationsEnabled");
+ Element notify_SimpleAudioNotificationsEnabled = doc.createElement("notify_SimpleAudioNotificationsEnabled");
notify_SimpleAudioNotificationsEnabled.setTextContent(this.isNotify_playSimpleSounds()+"");
notifications.appendChild(notify_SimpleAudioNotificationsEnabled);
- Element notify_CWCallSignAudioNotificationsEnabled = doc.createElement("notify_CWCallsignAudioNotificationsEnabled");
+ Element notify_CWCallSignAudioNotificationsEnabled = doc.createElement("notify_CWCallsignAudioNotificationsEnabled");
notify_CWCallSignAudioNotificationsEnabled.setTextContent(this.isNotify_playCWCallsignsOnRxedPMs()+"");
notifications.appendChild(notify_CWCallSignAudioNotificationsEnabled);
@@ -1109,89 +1393,172 @@ public class ChatPreferences {
notify_DXCSrv_SpottersCallSignToFile.setTextContent(this.getNotify_DXCSrv_SpottersCallSign().get());
notifications.appendChild(notify_DXCSrv_SpottersCallSignToFile);
- /**
- * Shortcuts
- */
-
- Element shortCuts = doc.createElement("shortCuts");
- rootElement.appendChild(shortCuts);
-
- for (Iterator iterator = lst_txtShortCutBtnList.iterator(); iterator.hasNext();) {
+ Element notify_noReplyPenaltyMinutes = doc.createElement("notify_noReplyPenaltyMinutes");
+ notify_noReplyPenaltyMinutes.setTextContent(this.getNotify_noReplyPenaltyMinutes() + "");
+ notifications.appendChild(notify_noReplyPenaltyMinutes);
+
+ Element notify_momentumWindowSeconds = doc.createElement("notify_momentumWindowSeconds");
+ notify_momentumWindowSeconds.setTextContent(this.getNotify_momentumWindowSeconds() + "");
+ notifications.appendChild(notify_momentumWindowSeconds);
+
+ Element notify_positiveSignalsPatterns = doc.createElement("notify_positiveSignalsPatterns");
+ notify_positiveSignalsPatterns.setTextContent(this.getNotify_positiveSignalsPatterns());
+ notifications.appendChild(notify_positiveSignalsPatterns);
+
+ Element notify_bandUpgradeHintOnLogEnabled = doc.createElement("notify_bandUpgradeHintOnLogEnabled");
+ notify_bandUpgradeHintOnLogEnabled.setTextContent(this.notify_bandUpgradeHintOnLogEnabled + "");
+ notifications.appendChild(notify_bandUpgradeHintOnLogEnabled);
+
+ Element notify_bandUpgradePriorityBoostEnabled = doc.createElement("notify_bandUpgradePriorityBoostEnabled");
+ notify_bandUpgradePriorityBoostEnabled.setTextContent(this.notify_bandUpgradePriorityBoostEnabled + "");
+ notifications.appendChild(notify_bandUpgradePriorityBoostEnabled);
+
+
+ /**
+ * Shortcuts
+ */
+
+ Element shortCuts = doc.createElement("shortCuts");
+ rootElement.appendChild(shortCuts);
+
+ for (Iterator iterator = lst_txtShortCutBtnList.iterator(); iterator.hasNext();) {
String string = (String) iterator.next();
Element temp = doc.createElement("t");
temp.setTextContent(string);
shortCuts.appendChild(temp);
- }
-
- /**
- * Textsnippets (right click menu)
- */
-
- Element textSnippets = doc.createElement("textSnippets");
- rootElement.appendChild(textSnippets);
-
- for (Iterator iterator = lst_txtSnipList.iterator(); iterator.hasNext();) {
+ }
+
+ /**
+ * QSO Sniffer Lists
+ */
+ Element snifferWords = doc.createElement("snifferWords");
+ rootElement.appendChild(snifferWords);
+
+ for (String word : lstNotify_QSOSniffer_sniffedWordsList) {
+ Element temp = doc.createElement("w");
+ temp.setTextContent(word);
+ snifferWords.appendChild(temp);
+ }
+
+ Element snifferPrefixes = doc.createElement("snifferPrefixes");
+ rootElement.appendChild(snifferPrefixes);
+
+ for (String prefix : lstNotify_QSOSniffer_sniffedPrefixLocList) {
+ Element temp = doc.createElement("p");
+ temp.setTextContent(prefix);
+ snifferPrefixes.appendChild(temp);
+ }
+
+ /**
+ * Textsnippets (right click menu)
+ */
+
+ Element textSnippets = doc.createElement("textSnippets");
+ rootElement.appendChild(textSnippets);
+
+ for (Iterator iterator = lst_txtSnipList.iterator(); iterator.hasNext();) {
String string = (String) iterator.next();
Element temp = doc.createElement("t");
temp.setTextContent(string);
textSnippets.appendChild(temp);
- }
-
+ }
- /**
- * BeaconCQ
- */
- Element beaconCQ = doc.createElement("beaconCQ");
- rootElement.appendChild(beaconCQ);
+ /**
+ * BeaconCQ
+ */
- Element beaconCQText = doc.createElement("beaconCQText");
- beaconCQText.setTextContent(this.getBcn_beaconTextMainCat());
- beaconCQ.appendChild(beaconCQText);
-
- Element beaconCQIntervalMinutes = doc.createElement("beaconCQIntervalMinutes");
- beaconCQIntervalMinutes.setTextContent(this.getBcn_beaconIntervalInMinutesMainCat()+"");
- beaconCQ.appendChild(beaconCQIntervalMinutes);
-
- Element beaconCQEnabled = doc.createElement("beaconCQEnabled");
- beaconCQEnabled.setTextContent(this.isBcn_beaconsEnabledMainCat()+"");
- beaconCQ.appendChild(beaconCQEnabled);
+ Element beaconCQ = doc.createElement("beaconCQ");
+ rootElement.appendChild(beaconCQ);
+
+ Element beaconCQText = doc.createElement("beaconCQText");
+ beaconCQText.setTextContent(this.getBcn_beaconTextMainCat());
+ beaconCQ.appendChild(beaconCQText);
+
+ // Preferred tag name (close to variable name)
+ Element bcn_beaconTextMainCat = doc.createElement("bcn_beaconTextMainCat");
+ bcn_beaconTextMainCat.setTextContent(this.getBcn_beaconTextMainCat());
+ beaconCQ.appendChild(bcn_beaconTextMainCat);
+
+ Element beaconCQIntervalMinutes = doc.createElement("beaconCQIntervalMinutes");
+ beaconCQIntervalMinutes.setTextContent(this.getBcn_beaconIntervalInMinutesMainCat()+"");
+ beaconCQ.appendChild(beaconCQIntervalMinutes);
+
+ Element bcn_beaconIntervalInMinutesMainCat = doc.createElement("bcn_beaconIntervalInMinutesMainCat");
+ bcn_beaconIntervalInMinutesMainCat.setTextContent(this.getBcn_beaconIntervalInMinutesMainCat()+"");
+ beaconCQ.appendChild(bcn_beaconIntervalInMinutesMainCat);
+
+ Element beaconCQEnabled = doc.createElement("beaconCQEnabled");
+ beaconCQEnabled.setTextContent(this.isBcn_beaconsEnabledMainCat()+"");
+ beaconCQ.appendChild(beaconCQEnabled);
+
+ Element bcn_beaconsEnabledMainCat = doc.createElement("bcn_beaconsEnabledMainCat");
+ bcn_beaconsEnabledMainCat.setTextContent(this.isBcn_beaconsEnabledMainCat()+"");
+ beaconCQ.appendChild(bcn_beaconsEnabledMainCat);
Element beaconCQTextSecondText = doc.createElement("beaconCQTextSecondText");
beaconCQTextSecondText.setTextContent(this.getBcn_beaconTextSecondCat());
beaconCQ.appendChild(beaconCQTextSecondText);
+ Element bcn_beaconTextSecondCat = doc.createElement("bcn_beaconTextSecondCat");
+ bcn_beaconTextSecondCat.setTextContent(this.getBcn_beaconTextSecondCat());
+ beaconCQ.appendChild(bcn_beaconTextSecondCat);
+
Element beaconCQIntervalMinutesSecondCat = doc.createElement("beaconCQIntervalMinutesSecondCat");
beaconCQIntervalMinutesSecondCat.setTextContent(this.getBcn_beaconIntervalInMinutesSecondCat()+"");
beaconCQ.appendChild(beaconCQIntervalMinutesSecondCat);
+ Element bcn_beaconIntervalInMinutesSecondCat = doc.createElement("bcn_beaconIntervalInMinutesSecondCat");
+ bcn_beaconIntervalInMinutesSecondCat.setTextContent(this.getBcn_beaconIntervalInMinutesSecondCat()+"");
+ beaconCQ.appendChild(bcn_beaconIntervalInMinutesSecondCat);
+
Element beaconCQEnabledSecondCat = doc.createElement("beaconCQEnabledSecondCat");
beaconCQEnabledSecondCat.setTextContent(this.isBcn_beaconsEnabledSecondCat()+"");
beaconCQ.appendChild(beaconCQEnabledSecondCat);
- /**
- * Messagehandling section / ex Beacon Unworked Stations
- */
+ Element bcn_beaconsEnabledSecondCat = doc.createElement("bcn_beaconsEnabledSecondCat");
+ bcn_beaconsEnabledSecondCat.setTextContent(this.isBcn_beaconsEnabledSecondCat()+"");
+ beaconCQ.appendChild(bcn_beaconsEnabledSecondCat);
- Element beaconUnworkedstations = doc.createElement("beaconUnworkedstations");
- rootElement.appendChild(beaconUnworkedstations);
+ /**
+ * Messagehandling section / ex Beacon Unworked Stations
+ */
- Element beaconUnworkedstationsText = doc.createElement("beaconUnworkedstationsText");
- beaconUnworkedstationsText.setTextContent(this.getMessageHandling_unworkedStnRequesterBeaconsText());
- beaconUnworkedstations.appendChild(beaconUnworkedstationsText);
-
- Element beaconUnworkedstationsIntervalMinutes = doc.createElement("beaconUnworkedstationsIntervalMinutes");
- beaconUnworkedstationsIntervalMinutes.setTextContent(this.getMessageHandling_unworkedStnRequesterBeaconsInterval()+"");
- beaconUnworkedstations.appendChild(beaconUnworkedstationsIntervalMinutes);
+ Element beaconUnworkedstations = doc.createElement("beaconUnworkedstations");
+ rootElement.appendChild(beaconUnworkedstations);
- Element beaconUnworkedstationsEnabled = doc.createElement("beaconUnworkedstationsEnabled");
- beaconUnworkedstationsEnabled.setTextContent(this.isMessageHandling_unworkedStnRequesterBeaconsEnabled()+"");
- beaconUnworkedstations.appendChild(beaconUnworkedstationsEnabled);
-
- Element beaconUnworkedstationsPrefix = doc.createElement("beaconUnworkedstationsPrefix");
- beaconUnworkedstationsPrefix.setTextContent(this.messageHandling_beaconUnworkedstationsPrefix());
- beaconUnworkedstations.appendChild(beaconUnworkedstationsPrefix);
+ Element beaconUnworkedstationsText = doc.createElement("beaconUnworkedstationsText");
+ beaconUnworkedstationsText.setTextContent(this.getMessageHandling_unworkedStnRequesterBeaconsText());
+ beaconUnworkedstations.appendChild(beaconUnworkedstationsText);
+
+ Element messageHandling_unworkedStnRequesterBeaconsText = doc.createElement("messageHandling_unworkedStnRequesterBeaconsText");
+ messageHandling_unworkedStnRequesterBeaconsText.setTextContent(this.getMessageHandling_unworkedStnRequesterBeaconsText());
+ beaconUnworkedstations.appendChild(messageHandling_unworkedStnRequesterBeaconsText);
+
+ Element beaconUnworkedstationsIntervalMinutes = doc.createElement("beaconUnworkedstationsIntervalMinutes");
+ beaconUnworkedstationsIntervalMinutes.setTextContent(this.getMessageHandling_unworkedStnRequesterBeaconsInterval()+"");
+ beaconUnworkedstations.appendChild(beaconUnworkedstationsIntervalMinutes);
+
+ Element messageHandling_unworkedStnRequesterBeaconsInterval = doc.createElement("messageHandling_unworkedStnRequesterBeaconsInterval");
+ messageHandling_unworkedStnRequesterBeaconsInterval.setTextContent(this.getMessageHandling_unworkedStnRequesterBeaconsInterval()+"");
+ beaconUnworkedstations.appendChild(messageHandling_unworkedStnRequesterBeaconsInterval);
+
+ Element beaconUnworkedstationsEnabled = doc.createElement("beaconUnworkedstationsEnabled");
+ beaconUnworkedstationsEnabled.setTextContent(this.isMessageHandling_unworkedStnRequesterBeaconsEnabled()+"");
+ beaconUnworkedstations.appendChild(beaconUnworkedstationsEnabled);
+
+ Element messageHandling_unworkedStnRequesterBeaconsEnabled = doc.createElement("messageHandling_unworkedStnRequesterBeaconsEnabled");
+ messageHandling_unworkedStnRequesterBeaconsEnabled.setTextContent(this.isMessageHandling_unworkedStnRequesterBeaconsEnabled()+"");
+ beaconUnworkedstations.appendChild(messageHandling_unworkedStnRequesterBeaconsEnabled);
+
+ Element beaconUnworkedstationsPrefix = doc.createElement("beaconUnworkedstationsPrefix");
+ beaconUnworkedstationsPrefix.setTextContent(this.messageHandling_beaconUnworkedstationsPrefix());
+ beaconUnworkedstations.appendChild(beaconUnworkedstationsPrefix);
+
+ Element messageHandling_beaconUnworkedstationsPrefix = doc.createElement("messageHandling_beaconUnworkedstationsPrefix");
+ messageHandling_beaconUnworkedstationsPrefix.setTextContent(this.messageHandling_beaconUnworkedstationsPrefix());
+ beaconUnworkedstations.appendChild(messageHandling_beaconUnworkedstationsPrefix);
/*****************************************************************
* MESSAGEHANDLING NEW .... BEACONUNWORKED HAVE TO BE REPLACED
@@ -1243,6 +1610,25 @@ public class ChatPreferences {
guiOptions_defaultFilterPublicMsgs.setTextContent(this.isGuiOptions_defaultFilterPublicMsgs()+"");
guiSaveableOptions.appendChild(guiOptions_defaultFilterPublicMsgs);
+ Element guiOptions_darkModeActive = doc.createElement("guiOptions_darkModeActive");
+ guiOptions_darkModeActive.setTextContent(this.GUI_darkModeActive + "");
+ guiSaveableOptions.appendChild(guiOptions_darkModeActive);
+
+ Element guiOptions_darkModeActiveByDefault = doc.createElement("guiOptions_darkModeActiveByDefault");
+ guiOptions_darkModeActiveByDefault.setTextContent(this.GUI_darkModeActiveByDefault + "");
+ guiSaveableOptions.appendChild(guiOptions_darkModeActiveByDefault);
+
+ // --- GUImainWindowRightSplitPane_dividerposition (2 dividers => 2 values) --- NEW
+ ensureMainWindowRightSplitPaneDividerPositions(2);
+
+ Element eDiv0 = doc.createElement("GUImainWindowRightSplitPane_dividerposition0");
+ eDiv0.setTextContent(String.valueOf(GUImainWindowRightSplitPane_dividerposition[0]));
+ guiSaveableOptions.appendChild(eDiv0);
+
+ Element eDiv1 = doc.createElement("GUImainWindowRightSplitPane_dividerposition1");
+ eDiv1.setTextContent(String.valueOf(GUImainWindowRightSplitPane_dividerposition[1]));
+ guiSaveableOptions.appendChild(eDiv1);
+
/**
* window sizes
*/
@@ -1294,32 +1680,32 @@ public class ChatPreferences {
****************************************************************************************/
writeXml(doc, System.out);
-
+
// write dom document to a file
- try (FileOutputStream output =
- new FileOutputStream(storeAndRestorePreferencesFileName)) {
- writeXml(doc, output);
- } catch (IOException e) {
- e.printStackTrace();
- } catch (TransformerException e) {
+ try (FileOutputStream output =
+ new FileOutputStream(storeAndRestorePreferencesFileName)) {
+ writeXml(doc, output);
+ } catch (IOException e) {
+ e.printStackTrace();
+ } catch (TransformerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
-
-
+
+
} catch (ParserConfigurationException | TransformerException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
return true;
- // root elements
+ // root elements
- //...create XML elements, and others...
+ //...create XML elements, and others...
- // write dom document to a file
+ // write dom document to a file
- }
+ }
// write doc to output stream
private static void writeXml(Document doc, OutputStream output) throws TransformerException {
@@ -1336,7 +1722,7 @@ public class ChatPreferences {
}
/**
- *
+ *
* @return true if the file reading was successful, else false
*/
public boolean readPreferencesFromXmlFile() {
@@ -1357,405 +1743,207 @@ public class ChatPreferences {
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(xmlConfigFile);
+ NodeList list;
+
+ // --- Schema version (optional) ---
+ // Missing in older files -> assume version 1.
+ int xmlVersion = getIntFromDoc(doc, CONFIG_VERSION, "configVersion", "ConfigVersion");
+ // Currently we only need the version for debugging / future migrations.
+ if (xmlVersion > CONFIG_VERSION) {
+ System.out.println("[ChatPreferences, Info]: preferences.xml version (" + xmlVersion + ") is newer than this application (" + CONFIG_VERSION + "). Trying best-effort load.");
+ }
/**
* case station settings
- *
+ *
*/
- NodeList list = doc.getElementsByTagName("station");
- if (list.getLength() != 0) {
+ Element stationEl = getFirstElement(doc, "station");
+ if (stationEl != null) {
+ // Prefer tag names close to variable names, but accept legacy tags for backwards compatibility.
+ stn_loginCallSign = getText(stationEl, stn_loginCallSign, "stn_loginCallSign", "LoginCallSign");
+ stn_loginPassword = getText(stationEl, stn_loginPassword, "stn_loginPassword", "LoginPassword");
+ stn_loginNameMainCat = getText(stationEl, stn_loginNameMainCat, "stn_loginNameMainCat", "LoginDisplayedName");
+ stn_loginNameSecondCat = getText(stationEl, stn_loginNameSecondCat, "stn_loginNameSecondCat");
+ stn_loginLocatorMainCat = getText(stationEl, stn_loginLocatorMainCat, "stn_loginLocatorMainCat", "LoginLocator");
- for (int temp = 0; temp < list.getLength(); temp++) {
+ stn_on4kstServersDns = getText(stationEl, stn_on4kstServersDns, "stn_on4kstServersDns");
+ stn_on4kstServersPort = getInt(stationEl, stn_on4kstServersPort, "stn_on4kstServersPort");
+ stn_loginAFKState = getBoolean(stationEl, stn_loginAFKState, "stn_loginAFKState");
- Node node = list.item(temp);
-
- if (node.getNodeType() == Node.ELEMENT_NODE) {
-
- Element element = (Element) node;
-
- String call = element.getElementsByTagName("LoginCallSign").item(0).getTextContent();
- stn_loginCallSign = call;
-
-// call = call.toLowerCase();
- String password = element.getElementsByTagName("LoginPassword").item(0).getTextContent();
- stn_loginPassword = password;
-
- String loginDisplayedName = element.getElementsByTagName("LoginDisplayedName").item(0)
- .getTextContent();
- stn_loginNameMainCat = loginDisplayedName;
-
- try {
- String loginDisplayedNameSecondCat = element.getElementsByTagName("stn_loginNameSecondCat").item(0)
- .getTextContent();
- stn_loginNameSecondCat = loginDisplayedNameSecondCat;
- } catch (Exception previousVersionExc) {
- stn_loginNameSecondCat = "KST4Contest2nd";
- }
-
- String qra = element.getElementsByTagName("LoginLocator").item(0).getTextContent();
- stn_loginLocatorMainCat = qra;
-
- String category = element.getElementsByTagName("ChatCategory").item(0).getTextContent();
-
- if (isNumeric(category)) {
- ChatCategory chatCategory = new ChatCategory(Integer.parseInt(category));
- loginChatCategoryMain = chatCategory;
- } else {
-
- loginChatCategoryMain = new ChatCategory(2); // TODO: Set this default at another place
- }
-
- try {
-
- String ChatCategorySecond = element.getElementsByTagName("ChatCategorySecond").item(0).getTextContent();
- if (isNumeric(ChatCategorySecond)) {
- ChatCategory chatCategory2 = new ChatCategory(Integer.parseInt(ChatCategorySecond));
- loginChatCategorySecond = chatCategory2;
- } else {
- loginChatCategorySecond = new ChatCategory(3); // TODO: Set this default at another place
- }
-
- String secondCatEnabledOrNot = element
- .getElementsByTagName("stn_secondCatEnabled").item(0)
- .getTextContent();
-
- if (secondCatEnabledOrNot.equals("true")) {
-
- loginToSecondChatEnabled = true;
- } else {
- loginToSecondChatEnabled = false;
- }
- } catch (Exception prevVersionExc){
- loginToSecondChatEnabled = false; //default if setting not found
- }
-
-
-
- double antennaBeamWidthDeg = Double.parseDouble(element.getElementsByTagName("stn_antennaBeamWidthDeg").item(0).getTextContent());
- stn_antennaBeamWidthDeg = antennaBeamWidthDeg;
- double maxQRBDefault = Double.parseDouble(element.getElementsByTagName("stn_maxQRBDefault").item(0).getTextContent());
- stn_maxQRBDefault = maxQRBDefault;
- double qtfDefault = Double.parseDouble(element.getElementsByTagName("stn_qtfDefault").item(0).getTextContent());
- stn_qtfDefault = qtfDefault;
-
- try {
-
- String stnUses144 = element
- .getElementsByTagName("stn_bandActive144").item(0)
- .getTextContent();
-
- if (stnUses144.equals("true")) {
-
- stn_bandActive144 = true;
- } else {
- stn_bandActive144 = false;
- }
-
- String stnUses432 = element
- .getElementsByTagName("stn_bandActive432").item(0)
- .getTextContent();
-
- if (stnUses432.equals("true")) {
-
- stn_bandActive432 = true;
- } else {
- stn_bandActive432 = false;
- }
-
- String stnUses1240 = element
- .getElementsByTagName("stn_bandActive1240").item(0)
- .getTextContent();
-
- if (stnUses1240.equals("true")) {
-
- stn_bandActive1240 = true;
- } else {
- stn_bandActive1240 = false;
- }
-
- String stnUses2300 = element
- .getElementsByTagName("stn_bandActive2300").item(0)
- .getTextContent();
-
- if (stnUses2300.equals("true")) {
-
- stn_bandActive2300 = true;
- } else {
- stn_bandActive2300 = false;
- }
-
- String stnUses3400 = element
- .getElementsByTagName("stn_bandActive3400").item(0)
- .getTextContent();
-
- if (stnUses3400.equals("true")) {
-
- stn_bandActive3400 = true;
- } else {
- stn_bandActive3400 = false;
- }
-
- String stnUses5600 = element
- .getElementsByTagName("stn_bandActive5600").item(0)
- .getTextContent();
-
- if (stnUses5600.equals("true")) {
-
- stn_bandActive5600 = true;
- } else {
- stn_bandActive5600 = false;
- }
-
- String stnUses10G = element
- .getElementsByTagName("stn_bandActive10G").item(0)
- .getTextContent();
-
- if (stnUses10G.equals("true")) {
-
- stn_bandActive10G = true;
- } else {
- stn_bandActive10G = false;
- }
-
- } catch (NullPointerException tooOldConfigFileOrFormatError) {
- /**
- * In program version 1 there had not been these settings in the xml and not founding em
- * would cause an exception and dumb values for the preferences. So we have to initialize
- * these variables and later write a proper configfile which can be used correctly then.
- */
- stn_bandActive144 = true;
- stn_bandActive432 = true;
- stn_bandActive1240 = true;
- stn_bandActive2300 = true;
- stn_bandActive3400 = true;
- stn_bandActive5600 = true;
- stn_bandActive10G = true;
- }
-
-
- System.out.println("[ChatPreferences, info]: Current Element: " + node.getNodeName()
- + " --> call: " + call + " / " + password + " / " + loginDisplayedName + " / " + qra
- + " / " + category + " / " + antennaBeamWidthDeg + " / " + maxQRBDefault + " / " + qtfDefault + " qrv144: " + stn_bandActive144);
-
- }
+ String category = getText(stationEl, null, "loginChatCategoryMain", "ChatCategory");
+ if (isNumeric(category)) {
+ loginChatCategoryMain = new ChatCategory(Integer.parseInt(category));
+ } else {
+ loginChatCategoryMain = new ChatCategory(2);
}
+
+ String categorySecond = getText(stationEl, null, "loginChatCategorySecond", "ChatCategorySecond");
+ if (isNumeric(categorySecond)) {
+ loginChatCategorySecond = new ChatCategory(Integer.parseInt(categorySecond));
+ } else {
+ loginChatCategorySecond = new ChatCategory(3);
+ }
+
+ loginToSecondChatEnabled = getBoolean(stationEl, loginToSecondChatEnabled, "stn_secondCatEnabled");
+
+ stn_antennaBeamWidthDeg = getDouble(stationEl, stn_antennaBeamWidthDeg, "stn_antennaBeamWidthDeg");
+ stn_maxQRBDefault = getDouble(stationEl, stn_maxQRBDefault, "stn_maxQRBDefault");
+ stn_qtfDefault = getDouble(stationEl, stn_qtfDefault, "stn_qtfDefault");
+
+ // Band activity flags (introduced later; if missing -> keep defaults)
+ stn_bandActive144 = getBoolean(stationEl, stn_bandActive144, "stn_bandActive144");
+ stn_bandActive432 = getBoolean(stationEl, stn_bandActive432, "stn_bandActive432");
+ stn_bandActive1240 = getBoolean(stationEl, stn_bandActive1240, "stn_bandActive1240");
+ stn_bandActive2300 = getBoolean(stationEl, stn_bandActive2300, "stn_bandActive2300");
+ stn_bandActive3400 = getBoolean(stationEl, stn_bandActive3400, "stn_bandActive3400");
+ stn_bandActive5600 = getBoolean(stationEl, stn_bandActive5600, "stn_bandActive5600");
+ stn_bandActive10G = getBoolean(stationEl, stn_bandActive10G, "stn_bandActive10G");
+
+ stn_pstRotatorEnabled = getBoolean(stationEl, stn_pstRotatorEnabled, "stn_pstRotatorEnabled");
+
}
/**
* Case log synchronizatrion
*/
- list = doc.getElementsByTagName("logsynch");
- if (list.getLength() != 0) {
+ Element logsynchEl = getFirstElement(doc, "logsynch");
+ if (logsynchEl != null) {
+ logsynch_fileBasedWkdCallInterpreterFileNameReadOnly = getText(
+ logsynchEl,
+ logsynch_fileBasedWkdCallInterpreterFileNameReadOnly,
+ "logsynch_fileBasedWkdCallInterpreterFileNameReadOnly");
+ logsynch_storeWorkedCallSignsFileNameUDPMessageBackup = getText(
+ logsynchEl,
+ logsynch_storeWorkedCallSignsFileNameUDPMessageBackup,
+ "logsynch_storeWorkedCallSignsFileNameUDPMessageBackup");
+ logsynch_fileBasedWkdCallInterpreterEnabled = getBoolean(
+ logsynchEl,
+ logsynch_fileBasedWkdCallInterpreterEnabled,
+ "logsynch_fileBasedWkdCallInterpreterEnabled");
+ logsynch_ucxUDPWkdCallListenerPort = getInt(
+ logsynchEl,
+ logsynch_ucxUDPWkdCallListenerPort,
+ "logsynch_ucxUDPWkdCallListenerPort");
+ logsynch_ucxUDPWkdCallListenerEnabled = getBoolean(
+ logsynchEl,
+ logsynch_ucxUDPWkdCallListenerEnabled,
+ "logsynch_ucxUDPWkdCallListenerEnabled");
- for (int temp = 0; temp < list.getLength(); temp++) {
+ // Optional Win-Test network settings
+ logsynch_wintestNetworkStationNameOfKST = getText(
+ logsynchEl,
+ logsynch_wintestNetworkStationNameOfKST,
+ "logsynch_wintestNetworkStationNameOfKST");
+ logsynch_wintestNetworkStationNameOfWintestClient1 = getText(
+ logsynchEl,
+ logsynch_wintestNetworkStationNameOfWintestClient1,
+ "logsynch_wintestNetworkStationNameOfWintestClient1");
+ logsynch_wintestNetworkSimulationEnabled = getBoolean(
+ logsynchEl,
+ logsynch_wintestNetworkSimulationEnabled,
+ "logsynch_wintestNetworkSimulationEnabled");
+ logsynch_wintestNetworkStationIDOfKST = getInt(
+ logsynchEl,
+ logsynch_wintestNetworkStationIDOfKST,
+ "logsynch_wintestNetworkStationIDOfKST");
+ logsynch_wintestNetworkPort = getInt(
+ logsynchEl,
+ logsynch_wintestNetworkPort,
+ "logsynch_wintestNetworkPort");
- Node node = list.item(temp);
+ logsynch_wintestNetworkListenerEnabled = getBoolean(
+ logsynchEl,
+ logsynch_wintestNetworkListenerEnabled,
+ "logsynch_wintestNetworkListenerEnabled");
- if (node.getNodeType() == Node.ELEMENT_NODE) {
- Element element = (Element) node;
-
- String logsynchReadFile = element
- .getElementsByTagName("logsynch_fileBasedWkdCallInterpreterFileNameReadOnly").item(0)
- .getTextContent();
-
- logsynch_fileBasedWkdCallInterpreterFileNameReadOnly = logsynchReadFile;
-
- String UDPMessageBackupFileName = element
- .getElementsByTagName("logsynch_storeWorkedCallSignsFileNameUDPMessageBackup").item(0)
- .getTextContent();
-
- logsynch_storeWorkedCallSignsFileNameUDPMessageBackup = UDPMessageBackupFileName;
-
-// call = call.toLowerCase();
- String fileBasedLogSynchEnabled = element
- .getElementsByTagName("logsynch_fileBasedWkdCallInterpreterEnabled").item(0)
- .getTextContent();
-
- if (fileBasedLogSynchEnabled.equals("true")) {
-
- logsynch_fileBasedWkdCallInterpreterEnabled = true;
- } else {
- logsynch_fileBasedWkdCallInterpreterEnabled = false;
- }
-
- String ucxUDPLogSynchListenerPort = element
- .getElementsByTagName("logsynch_ucxUDPWkdCallListenerPort").item(0).getTextContent();
-
- if (isNumeric(ucxUDPLogSynchListenerPort)) {
- logsynch_ucxUDPWkdCallListenerPort = Integer.parseInt(ucxUDPLogSynchListenerPort);
- } else {
- logsynch_ucxUDPWkdCallListenerPort = 12060; // TODO: Set default at another place or with
- // STATIC VAR
- }
-
- String ucxUDPLogSynchListenerEnabled = element
- .getElementsByTagName("logsynch_ucxUDPWkdCallListenerEnabled").item(0).getTextContent();
-
- if (ucxUDPLogSynchListenerEnabled.equals("true")) {
- logsynch_ucxUDPWkdCallListenerEnabled = true;
- } else {
- logsynch_ucxUDPWkdCallListenerEnabled = false;
- }
-
- System.out.println(
- "[ChatPreferences, info]: Set the Universal file based worked-Call Interpreter to : "
- + logsynch_fileBasedWkdCallInterpreterEnabled);
-
- System.out.println("[ChatPreferences, info]: Set the UCX UDP Worked Call Listener to : "
- + logsynch_ucxUDPWkdCallListenerEnabled);
-
- }
- }
+ System.out.println(
+ "[ChatPreferences, info]: file based worked-call interpreter: " + logsynch_fileBasedWkdCallInterpreterEnabled);
+ System.out.println(
+ "[ChatPreferences, info]: UCX UDP worked-call listener: " + logsynch_ucxUDPWkdCallListenerEnabled);
}
/**
* Case trx synchronizatrion
*/
- list = doc.getElementsByTagName("trxSynchUCX");
- if (list.getLength() != 0) {
+ Element trxSynchEl = getFirstElement(doc, "trxSynchUCX");
+ if (trxSynchEl != null) {
+ trxSynch_ucxLogUDPListenerEnabled = getBoolean(
+ trxSynchEl,
+ trxSynch_ucxLogUDPListenerEnabled,
+ "trxSynch_ucxLogUDPListenerEnabled");
- for (int temp = 0; temp < list.getLength(); temp++) {
-
- Node node = list.item(temp);
-
- if (node.getNodeType() == Node.ELEMENT_NODE) {
-
- Element element = (Element) node;
-
- String trxSynchUCX = element.getElementsByTagName("trxSynch_ucxLogUDPListenerEnabled").item(0)
- .getTextContent();
-
- if (trxSynchUCX.equals("true")) {
- trxSynch_ucxLogUDPListenerEnabled = true;
- } else {
- trxSynch_ucxLogUDPListenerEnabled = false;
- }
-
- String trxSynch_defaultMYQRGValue = element.getElementsByTagName("trxSynch_defaultMYQRGValue")
- .item(0).getTextContent();
-
- this.getMYQRGFirstCat().setValue(trxSynch_defaultMYQRGValue);
-
- String trxSynch_defaultMYQRG2Value;
- try{
- trxSynch_defaultMYQRG2Value = element.getElementsByTagName("trxSynch_defaultMYQRG2Value")
- .item(0).getTextContent();
-
- } catch (Exception notFoundExc) {
- trxSynch_defaultMYQRG2Value = "1296.123.00"; //v1.26, new setting
- }
-
- this.getMYQRGSecondCat().setValue(trxSynch_defaultMYQRG2Value);
-
- System.out.println(
- "[ChatPreferences, info]: Set the trx qrg synch to " + trxSynch_ucxLogUDPListenerEnabled
- + " and default value to " + this.getMYQRGFirstCat().getValue() + " // " + this.getMYQRGSecondCat().getValue());
-
- }
+ String qrg1 = getText(trxSynchEl, null, "trxSynch_defaultMYQRGValue");
+ if (qrg1 != null) {
+ this.getMYQRGFirstCat().setValue(qrg1);
}
+ String qrg2 = getText(trxSynchEl, "1296.123.00", "trxSynch_defaultMYQRG2Value");
+ this.getMYQRGSecondCat().setValue(qrg2);
+
+ System.out.println(
+ "[ChatPreferences, info]: trx qrg synch=" + trxSynch_ucxLogUDPListenerEnabled
+ + ", default=" + this.getMYQRGFirstCat().getValue() + " // " + this.getMYQRGSecondCat().getValue());
}
/**
* Case notifications
*/
- list = doc.getElementsByTagName("notifications");
- if (list.getLength() != 0) {
+ Element notificationsEl = getFirstElement(doc, "notifications");
+ if (notificationsEl != null) {
+ notify_playSimpleSounds = getBoolean(notificationsEl, notify_playSimpleSounds, "notify_SimpleAudioNotificationsEnabled");
+ notify_playCWCallsignsOnRxedPMs = getBoolean(notificationsEl, notify_playCWCallsignsOnRxedPMs, "notify_CWCallsignAudioNotificationsEnabled");
+ notify_playVoiceCallsignsOnRxedPMs = getBoolean(notificationsEl, notify_playVoiceCallsignsOnRxedPMs, "notify_VoiceCallsignAudioNotificationsEnabled");
- for (int temp = 0; temp < list.getLength(); temp++) {
+ // DXCluster / Monitoring (introduced later) -> keep defaults if absent
+ notify_dxClusterServerEnabled = getBoolean(notificationsEl, notify_dxClusterServerEnabled, "notify_dxClusterServerEnabled");
+ notify_DXClusterServerTriggerBearing = getBoolean(notificationsEl, notify_DXClusterServerTriggerBearing, "notify_DXClusterServerTriggerBearing");
+ notify_DXClusterServerTriggerOnQRGDetect = getBoolean(notificationsEl, notify_DXClusterServerTriggerOnQRGDetect, "notify_DXClusterServerTriggerOnQRGDetect");
+ notify_dxclusterServerPort = getInt(notificationsEl, notify_dxclusterServerPort, "notify_dxclusterServerPort");
- Node node = list.item(temp);
-
- if (node.getNodeType() == Node.ELEMENT_NODE) {
-
- Element element = (Element) node;
-
- String notify_simpleAudioNotificationsEnabled = element.getElementsByTagName("notify_SimpleAudioNotificationsEnabled").item(0)
- .getTextContent();
-
- if (notify_simpleAudioNotificationsEnabled.equals("true")) {
- notify_playSimpleSounds = true;
- } else {
- notify_playSimpleSounds = false;
- }
-
- String notify_cwAudioNotificationsEnabled = element.getElementsByTagName("notify_CWCallsignAudioNotificationsEnabled").item(0)
- .getTextContent();
-
- if (notify_cwAudioNotificationsEnabled.equals("true")) {
- notify_playCWCallsignsOnRxedPMs = true;
- } else {
- notify_playCWCallsignsOnRxedPMs = false;
- }
-
- String notify_voiceAudioNotificationsEnabled = element.getElementsByTagName("notify_VoiceCallsignAudioNotificationsEnabled").item(0)
- .getTextContent();
-
- if (notify_voiceAudioNotificationsEnabled.equals("true")) {
- notify_playVoiceCallsignsOnRxedPMs = true;
- } else {
- notify_playVoiceCallsignsOnRxedPMs = false;
- }
-
- try { //try catch block since Version 1.23 due to new prefs to save and read
-
- String notify_dxClusterServerEnabledFromFile = element.getElementsByTagName("notify_dxClusterServerEnabled").item(0)
- .getTextContent();
-
- if (notify_dxClusterServerEnabledFromFile.equals("true")) {
- notify_dxClusterServerEnabled = true;
- } else {
- notify_dxClusterServerEnabled = false;
- }
-
- String notify_DXClusterServerTriggerBearingFromFile = element.getElementsByTagName("notify_DXClusterServerTriggerBearing").item(0)
- .getTextContent();
-
- if (notify_DXClusterServerTriggerBearingFromFile.equals("true")) {
- notify_DXClusterServerTriggerBearing = true;
- } else {
- notify_DXClusterServerTriggerBearing = false;
- }
-
- String notify_DXClusterServerTriggerOnQRGDetectFromFile = element.getElementsByTagName("notify_DXClusterServerTriggerOnQRGDetect").item(0)
- .getTextContent();
-
- if (notify_DXClusterServerTriggerOnQRGDetectFromFile.equals("true")) {
- notify_DXClusterServerTriggerOnQRGDetect = true;
- } else {
- notify_DXClusterServerTriggerOnQRGDetect = false;
- }
-
- String notify_dxclusterServerPortFromFile = element
- .getElementsByTagName("notify_dxclusterServerPort").item(0).getTextContent();
-
- if (isNumeric(notify_dxclusterServerPortFromFile)) {
- notify_dxclusterServerPort = Integer.parseInt(notify_dxclusterServerPortFromFile);
- } else {
-// notify_dxclusterServerPort = 8000; Default setted on very top of file
- }
-
- String notify_DXCSrv_SpottersCallSignFromFile = element.getElementsByTagName("notify_DXCSrv_SpottersCallSign").item(0).getTextContent();
- notify_DXCSrv_SpottersCallSign.set(notify_DXCSrv_SpottersCallSignFromFile);
-
- String notify_optionalFrequencyPrefixFromFile = element.getElementsByTagName("notify_optionalFrequencyPrefix").item(0).getTextContent();
- notify_optionalFrequencyPrefix.set(notify_optionalFrequencyPrefixFromFile);
-
-
- } catch (NullPointerException e) {
- e.printStackTrace();
- System.out.println("[ChatPreferences, Warning:] some monitoring preferences could not be found in "+ storeAndRestorePreferencesFileName +". Using defaults.");
- }
-
- System.out.println(
- "[ChatPreferences, info]: Set the audionotifications simple: " + notify_playSimpleSounds + ", CW: " + notify_playCWCallsignsOnRxedPMs + ", Voice: " + notify_playVoiceCallsignsOnRxedPMs);
-
- }
+ String spotter = getText(notificationsEl, null, "notify_DXCSrv_SpottersCallSign");
+ if (spotter != null) {
+ notify_DXCSrv_SpottersCallSign.set(spotter);
}
+ String prefix = getText(notificationsEl, null, "notify_optionalFrequencyPrefix");
+ if (prefix != null) {
+ notify_optionalFrequencyPrefix.set(prefix);
+ }
+
+ Integer noReply = getInt(notificationsEl, 13, "notify_noReplyPenaltyMinutes");
+ if (noReply != null) {
+ notify_noReplyPenaltyMinutes = noReply;
+ }
+
+ Integer momentum = getInt(notificationsEl, 666, "notify_momentumWindowSeconds");
+ if (momentum != null) {
+ notify_momentumWindowSeconds = momentum;
+ }
+
+ String pos = getText(notificationsEl, null, "notify_positiveSignalsPatterns");
+ if (pos != null) {
+ notify_positiveSignalsPatterns = pos;
+ }
+
+ notify_bandUpgradeHintOnLogEnabled = getBoolean(
+ notificationsEl,
+ notify_bandUpgradeHintOnLogEnabled,
+ "notify_bandUpgradeHintOnLogEnabled"
+ );
+ notify_bandUpgradePriorityBoostEnabled = getBoolean(
+ notificationsEl,
+ notify_bandUpgradePriorityBoostEnabled,
+ "notify_bandUpgradePriorityBoostEnabled"
+ );
+
+
+ System.out.println(
+ "[ChatPreferences, info]: audio notifications simple=" + notify_playSimpleSounds
+ + ", CW=" + notify_playCWCallsignsOnRxedPMs
+ + ", Voice=" + notify_playVoiceCallsignsOnRxedPMs);
}
@@ -1763,84 +1951,38 @@ public class ChatPreferences {
* Case AirScout querier
*/
- list = doc.getElementsByTagName("AirScoutQuerier");
- if (list.getLength() != 0) {
+ Element airScoutEl = getFirstElement(doc, "AirScoutQuerier");
+ if (airScoutEl != null) {
+ AirScout_asUDPListenerEnabled = getBoolean(airScoutEl, AirScout_asUDPListenerEnabled, "asQry_airScoutCommunicationEnabled");
+ AirScout_asServerNameString = getText(airScoutEl, AirScout_asServerNameString, "asQry_airScoutServerName");
+ AirScout_asClientNameString = getText(airScoutEl, AirScout_asClientNameString, "asQry_airScoutClientName");
+ AirScout_asCommunicationPort = getInt(airScoutEl, AirScout_asCommunicationPort, "asQry_airScoutUDPPort");
+ AirScout_asBandString = getText(airScoutEl, AirScout_asBandString, "asQry_airScoutBandValue");
- for (int temp = 0; temp < list.getLength(); temp++) {
-
- Node node = list.item(temp);
-
- if (node.getNodeType() == Node.ELEMENT_NODE) {
-
- Element element = (Element) node;
-
- String asQuerierUDPEnabled = element.getElementsByTagName("asQry_airScoutCommunicationEnabled")
- .item(0).getTextContent();
-
- if (asQuerierUDPEnabled.equals("true")) {
- AirScout_asUDPListenerEnabled = true;
- } else {
- AirScout_asUDPListenerEnabled = false;
- }
-
- this.setAirScout_asServerNameString(
- element.getElementsByTagName("asQry_airScoutServerName").item(0).getTextContent());
- this.setAirScout_asClientNameString(
- element.getElementsByTagName("asQry_airScoutClientName").item(0).getTextContent());
- this.setAirScout_asCommunicationPort(Integer.parseInt(
- element.getElementsByTagName("asQry_airScoutUDPPort").item(0).getTextContent()));
- this.setAirScout_asBandString(
- element.getElementsByTagName("asQry_airScoutBandValue").item(0).getTextContent());
-// this.getMYQRG().addListener((observable, oldValue, newValue) -> {
-// System.out.println("[Chatprefs.java, Info]: MYQRG changed from " + oldValue + " to " + newValue);
-//// this.getMYQRG().
-//// txt_ownqrg.setText(newValue);
-// });
-
-//
- System.out.println("[ChatPreferences, info]: Set the Airscout Querier to " + asQuerierUDPEnabled
- + " for qrg " + AirScout_asBandString);
-
- }
- }
+ System.out.println(
+ "[ChatPreferences, info]: AirScout querier enabled=" + AirScout_asUDPListenerEnabled
+ + ", band=" + AirScout_asBandString);
}
/**
* Case shortCuts
*/
- list = doc.getElementsByTagName("shortCuts");
- String[] shortCutsExtractedOutOfXML = new String[0];
-
- if (list.getLength() != 0) {
-
- ArrayList textShorts = new ArrayList();
-
- for (int temp = 0; temp < list.getLength(); temp++) {
-
- Node node = list.item(temp);
-
- Element element = (Element) node;
-
- for (int i = 0; i < element.getChildNodes().getLength(); i++) {
- if (element.getChildNodes().item(i).getNodeType() == Node.ELEMENT_NODE) {
- textShorts.add(element.getChildNodes().item(i).getTextContent());
- shortCutsExtractedOutOfXML = textShorts.toArray(String[]::new); // String[]::new = API
- // Collection.toArray(IntFunction
- // generator)
-// System.out.println(element.getChildNodes().item(i).getNodeType() + ": " + element.getChildNodes().item(i).getNodeName() + " - " + element.getChildNodes().item(i).getTextContent());
+ Element shortCutsEl = getFirstElement(doc, "shortCuts");
+ if (shortCutsEl != null) {
+ lst_txtShortCutBtnList.clear();
+ NodeList children = shortCutsEl.getChildNodes();
+ for (int i = 0; i < children.getLength(); i++) {
+ Node child = children.item(i);
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ String v = child.getTextContent();
+ if (v != null) {
+ v = v.trim();
+ }
+ if (v != null && !v.isEmpty()) {
+ lst_txtShortCutBtnList.add(v);
}
}
-
- }
-
- // if praktiKST found Shortcuts in the configfile, set it to the preferences
-// shortcuts = shortCutsExtractedOutOfXML;
- // else use defaults (as the initialization vars had been)
- for (int i = 0; i < shortCutsExtractedOutOfXML.length; i++) {
- lst_txtShortCutBtnList.add(shortCutsExtractedOutOfXML[i]);
- System.out.println("[Chatpreferences, Info]: Setting Short " + i + " \""
- + shortCutsExtractedOutOfXML[i] + "\"");
}
}
@@ -1848,38 +1990,73 @@ public class ChatPreferences {
* Case textSnippets
*/
- list = doc.getElementsByTagName("textSnippets");
- String[] textSnippetsExtractedOutOfXML = new String[0];
-
- if (list.getLength() != 0) {
-
- ArrayList textShorts = new ArrayList();
-
- for (int temp = 0; temp < list.getLength(); temp++) {
-
- Node node = list.item(temp);
-
- Element element = (Element) node;
-
- for (int i = 0; i < element.getChildNodes().getLength(); i++) {
- if (element.getChildNodes().item(i).getNodeType() == Node.ELEMENT_NODE) {
- textShorts.add(element.getChildNodes().item(i).getTextContent());
- textSnippetsExtractedOutOfXML = textShorts.toArray(String[]::new); // String[]::new = API
- // Collection.toArray(IntFunction
- // generator)
-// System.out.println(element.getChildNodes().item(i).getNodeType() + ": " + element.getChildNodes().item(i).getNodeName() + " - " + element.getChildNodes().item(i).getTextContent());
+ Element textSnippetsEl = getFirstElement(doc, "textSnippets");
+ if (textSnippetsEl != null) {
+ lst_txtSnipList.clear();
+ NodeList children = textSnippetsEl.getChildNodes();
+ for (int i = 0; i < children.getLength(); i++) {
+ Node child = children.item(i);
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ String v = child.getTextContent();
+ if (v != null) {
+ v = v.trim();
+ }
+ if (v != null && !v.isEmpty()) {
+ lst_txtSnipList.add(v);
}
}
-
}
+ }
- // if praktiKST found Shortcuts in the configfile, set it to the preferences
-// textSnippets = textSnippetsExtractedOutOfXML;
- // else use defaults (as the initialization vars had been)
- for (int i = 0; i < textSnippetsExtractedOutOfXML.length; i++) {
- lst_txtSnipList.add(textSnippetsExtractedOutOfXML[i]);
- System.out.println("[Chatpreferences, Info]: Setting Snip " + i + " \""
- + textSnippetsExtractedOutOfXML[i] + "\"");
+ /**
+ * Case QSO-sniffer lists (added later; older configs won't have them)
+ */
+ list = doc.getElementsByTagName("snifferWords");
+ if (list != null && list.getLength() != 0) {
+ // reset to avoid duplicates when reloading
+ lstNotify_QSOSniffer_sniffedWordsList.clear();
+ for (int temp = 0; temp < list.getLength(); temp++) {
+ Node node = list.item(temp);
+ if (node.getNodeType() == Node.ELEMENT_NODE) {
+ Element element = (Element) node;
+ NodeList children = element.getChildNodes();
+ for (int i = 0; i < children.getLength(); i++) {
+ Node child = children.item(i);
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ String word = child.getTextContent();
+ if (word != null) {
+ word = word.trim();
+ }
+ if (word != null && !word.isEmpty()) {
+ lstNotify_QSOSniffer_sniffedWordsList.add(word);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ list = doc.getElementsByTagName("snifferPrefixes");
+ if (list != null && list.getLength() != 0) {
+ lstNotify_QSOSniffer_sniffedPrefixLocList.clear();
+ for (int temp = 0; temp < list.getLength(); temp++) {
+ Node node = list.item(temp);
+ if (node.getNodeType() == Node.ELEMENT_NODE) {
+ Element element = (Element) node;
+ NodeList children = element.getChildNodes();
+ for (int i = 0; i < children.getLength(); i++) {
+ Node child = children.item(i);
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ String prefix = child.getTextContent();
+ if (prefix != null) {
+ prefix = prefix.trim();
+ }
+ if (prefix != null && !prefix.isEmpty()) {
+ lstNotify_QSOSniffer_sniffedPrefixLocList.add(prefix);
+ }
+ }
+ }
+ }
}
}
@@ -1887,124 +2064,47 @@ public class ChatPreferences {
* Case beaconCQ
*/
- list = doc.getElementsByTagName("beaconCQ");
- if (list.getLength() != 0) {
+ Element beaconCQEl = getFirstElement(doc, "beaconCQ");
+ if (beaconCQEl != null) {
+ bcn_beaconsEnabledMainCat = getBoolean(beaconCQEl, bcn_beaconsEnabledMainCat, "bcn_beaconsEnabledMainCat", "beaconCQEnabled");
+ bcn_beaconIntervalInMinutesMainCat = getInt(beaconCQEl, bcn_beaconIntervalInMinutesMainCat, "bcn_beaconIntervalInMinutesMainCat", "beaconCQIntervalMinutes");
+ bcn_beaconTextMainCat = getText(beaconCQEl, bcn_beaconTextMainCat, "bcn_beaconTextMainCat", "beaconCQText");
- for (int temp = 0; temp < list.getLength(); temp++) {
+ bcn_beaconsEnabledSecondCat = getBoolean(beaconCQEl, bcn_beaconsEnabledSecondCat, "bcn_beaconsEnabledSecondCat", "beaconCQEnabledSecondCat");
+ bcn_beaconIntervalInMinutesSecondCat = getInt(beaconCQEl, bcn_beaconIntervalInMinutesSecondCat, "bcn_beaconIntervalInMinutesSecondCat", "beaconCQIntervalMinutesSecondCat");
+ bcn_beaconTextSecondCat = getText(beaconCQEl, bcn_beaconTextSecondCat, "bcn_beaconTextSecondCat", "beaconCQTextSecondText");
- Node node = list.item(temp);
-
- if (node.getNodeType() == Node.ELEMENT_NODE) {
-
- Element element = (Element) node;
-
- String beaconCQEnabled = element.getElementsByTagName("beaconCQEnabled").item(0)
- .getTextContent();
-
- if (beaconCQEnabled.equals("true")) {
-
- bcn_beaconsEnabledMainCat = true;
- } else {
- bcn_beaconsEnabledMainCat = false;
- }
-
- String beaconCQIntervalMinutes = element.getElementsByTagName("beaconCQIntervalMinutes").item(0)
- .getTextContent();
-
- if (isNumeric(beaconCQIntervalMinutes)) {
- bcn_beaconIntervalInMinutesMainCat = Integer.parseInt(beaconCQIntervalMinutes);
- } else {
- bcn_beaconIntervalInMinutesMainCat = 20; // Default value, TODO: Set this in default list
- }
-
- String beaconCQText = element.getElementsByTagName("beaconCQText").item(0).getTextContent();
- this.setBcn_beaconTextMainCat(beaconCQText);
-
- String beaconCQEnabledSecondCat;
- try {
- beaconCQEnabledSecondCat = element.getElementsByTagName("beaconCQEnabledSecondCat").item(0)
- .getTextContent();
-
- if (beaconCQEnabledSecondCat.equals("true")) {
-
- bcn_beaconsEnabledSecondCat = true;
- } else {
- bcn_beaconsEnabledSecondCat = false;
- }
-
- String beaconCQIntervalMinutesSecondCat = element.getElementsByTagName("beaconCQIntervalMinutesSecondCat").item(0)
- .getTextContent();
-
- if (isNumeric(beaconCQIntervalMinutesSecondCat)) {
- bcn_beaconIntervalInMinutesSecondCat = Integer.parseInt(beaconCQIntervalMinutesSecondCat);
- } else {
- bcn_beaconIntervalInMinutesSecondCat = 3; // Default value, TODO: Set this in default list
- }
-
- String beaconCQTextSecondText = element.getElementsByTagName("beaconCQTextSecondText").item(0).getTextContent();
- this.setBcn_beaconTextSecondCat(beaconCQTextSecondText);
-
- } catch (Exception previousVersionException) {
- bcn_beaconsEnabledSecondCat = false;
- bcn_beaconIntervalInMinutesSecondCat = 3;
- this.setBcn_beaconTextSecondCat(this.getStn_loginCallSign() + " is QRV, pse sked for contact");
-
- }
-//
- System.out.println("[ChatPreferences, info]: set the beacon text to: " + beaconCQText + " and " + this.getBcn_beaconTextSecondCat());
-
- }
- }
+ System.out.println("[ChatPreferences, info]: beaconCQ main='" + bcn_beaconTextMainCat + "', second='" + bcn_beaconTextSecondCat + "'");
}
/**
* Case beaconUnworkedstations
- *
+ *
*/
- list = doc.getElementsByTagName("beaconUnworkedstations");
- if (list.getLength() != 0) {
-
- for (int temp = 0; temp < list.getLength(); temp++) {
-
- Node node = list.item(temp);
-
- if (node.getNodeType() == Node.ELEMENT_NODE) {
-
- Element element = (Element) node;
-//
- String beaconUnworkedstationsText = element.getElementsByTagName("beaconUnworkedstationsText")
- .item(0).getTextContent();
- messageHandling_unworkedStnRequesterBeaconsText = beaconUnworkedstationsText;
-
- String beaconUnworkedstationsIntervalMinutes = element
- .getElementsByTagName("beaconUnworkedstationsIntervalMinutes").item(0).getTextContent();
-
- if (isNumeric(beaconUnworkedstationsIntervalMinutes)) {
- messageHandling_unworkedStnRequesterBeaconsInterval = Integer
- .parseInt(beaconUnworkedstationsIntervalMinutes);
- } else {
- messageHandling_unworkedStnRequesterBeaconsInterval = 20;
- }
-
- String beaconUnworkedstationsEnabled = element
- .getElementsByTagName("beaconUnworkedstationsEnabled").item(0).getTextContent();
-
- if (beaconUnworkedstationsEnabled.equals("true")) {
- messageHandling_unworkedStnRequesterBeaconsEnabled = true;
- } else {
- messageHandling_unworkedStnRequesterBeaconsEnabled = false;
- }
-
- String beaconUnworkedstationsPrefix = element
- .getElementsByTagName("beaconUnworkedstationsPrefix").item(0).getTextContent();
-
- messageHandling_beaconUnworkedstationsPrefix = beaconUnworkedstationsPrefix;
-
- }
- }
- System.out.println("[ChatPreferences, info]: set the unworked stn beacon text to: "
- + messageHandling_unworkedStnRequesterBeaconsText);
+ Element beaconUnworkedEl = getFirstElement(doc, "beaconUnworkedstations");
+ if (beaconUnworkedEl != null) {
+ messageHandling_unworkedStnRequesterBeaconsText = getText(
+ beaconUnworkedEl,
+ messageHandling_unworkedStnRequesterBeaconsText,
+ "messageHandling_unworkedStnRequesterBeaconsText",
+ "beaconUnworkedstationsText");
+ messageHandling_unworkedStnRequesterBeaconsInterval = getInt(
+ beaconUnworkedEl,
+ messageHandling_unworkedStnRequesterBeaconsInterval,
+ "messageHandling_unworkedStnRequesterBeaconsInterval",
+ "beaconUnworkedstationsIntervalMinutes");
+ messageHandling_unworkedStnRequesterBeaconsEnabled = getBoolean(
+ beaconUnworkedEl,
+ messageHandling_unworkedStnRequesterBeaconsEnabled,
+ "messageHandling_unworkedStnRequesterBeaconsEnabled",
+ "beaconUnworkedstationsEnabled");
+ messageHandling_beaconUnworkedstationsPrefix = getText(
+ beaconUnworkedEl,
+ messageHandling_beaconUnworkedstationsPrefix,
+ "messageHandling_beaconUnworkedstationsPrefix",
+ "beaconUnworkedstationsPrefix");
+ System.out.println("[ChatPreferences, info]: unworked-stations beacon text='" + messageHandling_unworkedStnRequesterBeaconsText + "'");
}
@@ -2014,85 +2114,35 @@ public class ChatPreferences {
* case messageHandling
*
***********************************************/
- list = doc.getElementsByTagName("messageHandling");
- if (list.getLength() != 0) {
+ Element messageHandlingEl = getFirstElement(doc, "messageHandling");
+ if (messageHandlingEl != null) {
+ messageHandling_autoAnswerTextMainCat = getText(
+ messageHandlingEl,
+ messageHandling_autoAnswerTextMainCat,
+ "messageHandling_autoAnswerTextMainCat",
+ "autoAnswerText");
+ messageHandling_autoAnswerEnabled = getBoolean(
+ messageHandlingEl,
+ messageHandling_autoAnswerEnabled,
+ "messageHandling_autoAnswerEnabled",
+ "autoAnswerEnabled");
+ messageHandling_autoAnswerToQRGRequestEnabled = getBoolean(
+ messageHandlingEl,
+ messageHandling_autoAnswerToQRGRequestEnabled,
+ "messageHandling_autoAnswerToQRGRequestEnabled",
+ "autoAnswerToQrgRequestEnabled",
+ "autoAnswerToQRGRequestEnabled");
- for (int temp = 0; temp < list.getLength(); temp++) {
-
- Node node = list.item(temp);
-
- if (node.getNodeType() == Node.ELEMENT_NODE) {
-
- Element element = (Element) node;
-
- try{
-
- String autoAnswerText = element.getElementsByTagName("autoAnswerText").item(0)
- .getTextContent();
-
- this.setMessageHandling_autoAnswerTextMainCat(autoAnswerText);
-
- String autoAnswerEnabled = element.getElementsByTagName("autoAnswerEnabled").item(0)
- .getTextContent();
-
- if (autoAnswerEnabled.equals("true")) {
- this.setMessageHandling_autoAnswerEnabled(true);
- } else {
- this.setMessageHandling_autoAnswerEnabled(false);
- }
-
- String autoAnswerToQrgRequestEnabled = element.getElementsByTagName("autoAnswerToQrgRequestEnabled").item(0)
- .getTextContent();
-
- if (autoAnswerToQrgRequestEnabled.equals("true")) {
- this.setMessageHandling_autoAnswerToQRGRequestEnabled(true);
- } else {
- this.setMessageHandling_autoAnswerToQRGRequestEnabled(false);
- }
-
-
- }
-
- catch (NullPointerException tooOldConfigFileOrFormatError) {
- /**
- * In program version 1.24 there had not been these settings in the xml and not founding em
- * would cause an exception and dumb values for the preferences. So we have to initialize
- * these variables and later write a proper configfile which can be used correctly then.
- *
- * So THESE ARE DEFAULTS for the new variables
- */
-
- tooOldConfigFileOrFormatError.printStackTrace();
- this.setMessageHandling_autoAnswerTextMainCat("Hi, sry I am not qrv, just testing new features of KST4Contest " + ApplicationConstants.APPLICATION_CURRENTVERSIONNUMBER);
- this.setMessageHandling_autoAnswerEnabled(false);
- this.setMessageHandling_autoAnswerToQRGRequestEnabled(true);
- }
-
- try {
- String autoAnswerTextSecondCat = element.getElementsByTagName("autoAnswerTextSecondCat").item(0)
- .getTextContent();
-
- this.setMessageHandling_autoAnswerTextSecondCat(autoAnswerTextSecondCat);
-
-
- String autoAnswerEnabledSecondCat = element.getElementsByTagName("autoAnswerEnabledSecondCat").item(0)
- .getTextContent();
-
- if (autoAnswerEnabledSecondCat.equals("true")) {
- this.setMessageHandling_autoAnswerEnabledSecondCat(true);
- } else {
- this.setMessageHandling_autoAnswerEnabledSecondCat(false);
- }
- } catch (Exception prevVersionExc) {
-
- String autoAnswerTextSecondCat = "[KST4Contest autoreply] change me ... ";
- this.setMessageHandling_autoAnswerEnabledSecondCat(false);
-
- }
-
-
- }
- }
+ messageHandling_autoAnswerTextSecondCat = getText(
+ messageHandlingEl,
+ messageHandling_autoAnswerTextSecondCat,
+ "messageHandling_autoAnswerTextSecondCat",
+ "autoAnswerTextSecondCat");
+ messageHandling_autoAnswerEnabledSecondCat = getBoolean(
+ messageHandlingEl,
+ messageHandling_autoAnswerEnabledSecondCat,
+ "messageHandling_autoAnswerEnabledSecondCat",
+ "autoAnswerEnabledSecondCat");
}
@@ -2119,77 +2169,69 @@ public class ChatPreferences {
Element element = (Element) node;
- try{
+ // Scene sizes (semicolon separated), defaults are already in the arrays.
+ parseSemicolonDoublesInto(getText(element, null, "GUIscn_ChatwindowMainSceneSizeHW"), this.getGUIscn_ChatwindowMainSceneSizeHW());
+ parseSemicolonDoublesInto(getText(element, null, "GUIclusterAndQSOMonStage_SceneSizeHW"), this.getGUIclusterAndQSOMonStage_SceneSizeHW());
+ parseSemicolonDoublesInto(getText(element, null, "GUIstage_updateStage_SceneSizeHW"), this.getGUIstage_updateStage_SceneSizeHW());
+ parseSemicolonDoublesInto(getText(element, null, "GUIsettingsStageSceneSizeHW"), this.getGUIsettingsStageSceneSizeHW());
- String GUIscn_ChatwindowMainSceneSizeHW = element.getElementsByTagName("GUIscn_ChatwindowMainSceneSizeHW").item(0)
- .getTextContent();
-
- for (int i = 0; i < (GUIscn_ChatwindowMainSceneSizeHW.split(";").length); i++) {
- this.getGUIscn_ChatwindowMainSceneSizeHW()[i] =
- Double.parseDouble(GUIscn_ChatwindowMainSceneSizeHW.split(";")[i]);
+ // Splitpane divider positions
+ String s1 = getText(element, null, "GUIselectedCallSignSplitPane_dividerposition");
+ if (s1 != null) {
+ this.setGUIselectedCallSignSplitPane_dividerposition(csvStringToDoubleArray(s1));
+ }
+ String s2 = getText(element, null, "GUImainWindowLeftSplitPane_dividerposition");
+ if (s2 != null) {
+ this.setGUImainWindowLeftSplitPane_dividerposition(csvStringToDoubleArray(s2));
+ }
+ String s3 = getText(element, null, "GUImessageSectionSplitpane_dividerposition");
+ if (s3 != null) {
+ double[] parsed = csvStringToDoubleArray(s3);
+ // Config files older than ~1.40 had fewer panes.
+ if (parsed.length >= 4) {
+ this.setGUImessageSectionSplitpane_dividerposition(parsed);
}
+ }
+ // GUImainWindowRightSplitPane divider positions (2 dividers => 2 values)
+// Backward compatible: old configs stored a single CSV tag.
+ String rightLegacy = getText(element, null, "GUImainWindowRightSplitPane_dividerposition");
+ String right0 = getText(element, null, "GUImainWindowRightSplitPane_dividerposition0");
+ String right1 = getText(element, null, "GUImainWindowRightSplitPane_dividerposition1");
- System.out.println(
- "[ChatPreferences, info]: Set the GUIscn_ChatwindowMainSceneSizeHW size to " + GUIclusterAndQSOMonStage_SceneSizeHW);
+ if (right0 != null || right1 != null) {
+ // New format: two dedicated tags
+ double p0 = (right0 != null) ? parseDoubleOrDefault(right0, this.GUImainWindowRightSplitPane_dividerpositionDefault[0])
+ : this.GUImainWindowRightSplitPane_dividerpositionDefault[0];
- String GUIclusterAndQSOMonStage_SceneSizeHW = element.getElementsByTagName("GUIclusterAndQSOMonStage_SceneSizeHW").item(0)
- .getTextContent();
+ double p1 = (right1 != null) ? parseDoubleOrDefault(right1, this.GUImainWindowRightSplitPane_dividerpositionDefault[1])
+ : this.GUImainWindowRightSplitPane_dividerpositionDefault[1];
- for (int i = 0; i < (GUIclusterAndQSOMonStage_SceneSizeHW.split(";").length); i++) {
- this.getGUIclusterAndQSOMonStage_SceneSizeHW()[i] =
- Double.parseDouble(GUIclusterAndQSOMonStage_SceneSizeHW.split(";")[i]);
+ this.setGUImainWindowRightSplitPane_dividerposition(new double[] { p0, p1 });
+
+ } else if (rightLegacy != null) {
+
+ // Old format: CSV array (often length 1)
+ double[] parsed = csvStringToDoubleArray(rightLegacy);
+
+ // Upgrade older config files gracefully
+ if (parsed.length >= 2) {
+ this.setGUImainWindowRightSplitPane_dividerposition(new double[] { parsed[0], parsed[1] });
+ } else if (parsed.length == 1) {
+ this.setGUImainWindowRightSplitPane_dividerposition(new double[] {
+ parsed[0],
+ this.GUImainWindowRightSplitPane_dividerpositionDefault[1]
+ });
}
-
- String GUIselectedCallSignSplitPane_dividerposition = element.getElementsByTagName("GUIselectedCallSignSplitPane_dividerposition").item(0)
- .getTextContent();
- this.setGUIselectedCallSignSplitPane_dividerposition(csvStringToDoubleArray(GUIselectedCallSignSplitPane_dividerposition));
-
- String GUImainWindowLeftSplitPane_dividerposition = element.getElementsByTagName("GUImainWindowLeftSplitPane_dividerposition").item(0)
- .getTextContent();
- this.setGUImainWindowLeftSplitPane_dividerposition(csvStringToDoubleArray(GUImainWindowLeftSplitPane_dividerposition));
-
- String GUImessageSectionSplitpane_dividerposition = element.getElementsByTagName("GUImessageSectionSplitpane_dividerposition").item(0)
- .getTextContent();
- this.setGUImessageSectionSplitpane_dividerposition(csvStringToDoubleArray(GUImessageSectionSplitpane_dividerposition));
-
- String GUImainWindowRightSplitPane_dividerposition = element.getElementsByTagName("GUImainWindowRightSplitPane_dividerposition").item(0)
- .getTextContent();
- this.setGUImainWindowRightSplitPane_dividerposition(csvStringToDoubleArray(GUImainWindowRightSplitPane_dividerposition));
-
- String GUIpnl_directedMSGWin_dividerpositionDefault = element.getElementsByTagName("GUIpnl_directedMSGWin_dividerpositionDefault").item(0)
- .getTextContent();
- this.setGUIpnl_directedMSGWin_dividerpositionDefault(csvStringToDoubleArray(GUIpnl_directedMSGWin_dividerpositionDefault));
-
-
-
-
-// System.out.println(
-// "[ChatPreferences, info]: Set the GUIclusterAndQSOMonStage_SceneSizeHW size to " + GUIclusterAndQSOMonStage_SceneSizeHW);
-
}
- catch (NullPointerException tooOldConfigFileOrFormatError) {
- /**
- * In program version 1.2 there had not been these settings in the xml and not founding em
- * would cause an exception and dumb values for the preferences. So we have to initialize
- * these variables and later write a proper configfile which can be used correctly then.
- *
- * So THESE ARE DEFAULTS
- */
+ // Ensure correct length no matter what was in the config (prevents AIOOBE)
+ ensureMainWindowRightSplitPaneDividerPositions(2);
- tooOldConfigFileOrFormatError.printStackTrace();
- GUIscn_ChatwindowMainSceneSizeHW = new double[] {768, 1234};
- GUIclusterAndQSOMonStage_SceneSizeHW = new double[] {700, 500};
- GUIstage_updateStage_SceneSizeHW = new double[] {640, 480};
- GUIsettingsStageSceneSizeHW = new double[] {720, 768};
- GUIselectedCallSignSplitPane_dividerposition = new double[]{0.9};
- setGUImainWindowLeftSplitPane_dividerposition(new double[]{0.7});
- GUImessageSectionSplitpane_dividerposition = new double[]{0.5};
- GUImainWindowRightSplitPane_dividerposition = new double[]{0.8};
- GUIpnl_directedMSGWin_dividerpositionDefault = new double[]{0.8};
-// GUImainWindowLeftSplitPane_dividerposition
+ String s5 = getText(element, null, "GUIpnl_directedMSGWin_dividerpositionDefault");
+ if (s5 != null) {
+ this.setGUIpnl_directedMSGWin_dividerpositionDefault(csvStringToDoubleArray(s5));
}
}
}
@@ -2200,76 +2242,16 @@ public class ChatPreferences {
* case read guiSaveableOptions
*
***********************************************/
- list = doc.getElementsByTagName("guiSaveableOptions");
- if (list.getLength() != 0) {
+ Element guiSaveableOptionsEl = getFirstElement(doc, "guiSaveableOptions");
+ if (guiSaveableOptionsEl != null) {
+ this.setGuiOptions_defaultFilterNothing(getBoolean(guiSaveableOptionsEl, this.isGuiOptions_defaultFilterNothing(), "guiOptions_defaultFilterNothing"));
+ this.setGuiOptions_defaultFilterPmToMe(getBoolean(guiSaveableOptionsEl, this.isGuiOptions_defaultFilterPmToMe(), "guiOptions_defaultFilterPmToMe"));
+ this.setGuiOptions_defaultFilterPmToOther(getBoolean(guiSaveableOptionsEl, this.isGuiOptions_defaultFilterPmToOther(), "guiOptions_defaultFilterPmToOther"));
+ this.setGuiOptions_defaultFilterPublicMsgs(getBoolean(guiSaveableOptionsEl, this.isGuiOptions_defaultFilterPublicMsgs(), "guiOptions_defaultFilterPublicMsgs"));
- for (int temp = 0; temp < list.getLength(); temp++) {
-
- Node node = list.item(temp);
-
- if (node.getNodeType() == Node.ELEMENT_NODE) {
-
- Element element = (Element) node;
-
- try{
-
- String guiOptions_defaultFilterNothing = element.getElementsByTagName("guiOptions_defaultFilterNothing").item(0)
- .getTextContent();
-
- if (guiOptions_defaultFilterNothing.equals("true")) {
- this.setGuiOptions_defaultFilterNothing(true);
- } else {
- this.setGuiOptions_defaultFilterNothing(false);
- }
-
- String guiOptions_defaultFilterPmToMe = element.getElementsByTagName("guiOptions_defaultFilterPmToMe").item(0)
- .getTextContent();
-
- if (guiOptions_defaultFilterPmToMe.equals("true")) {
- this.setGuiOptions_defaultFilterPmToMe(true);
- } else {
- this.setGuiOptions_defaultFilterNothing(false);
- }
-
- String guiOptions_defaultFilterPmToOther = element.getElementsByTagName("guiOptions_defaultFilterPmToOther").item(0)
- .getTextContent();
-
- if (guiOptions_defaultFilterPmToOther.equals("true")) {
- this.setGuiOptions_defaultFilterPmToOther(true);
- } else {
- this.setGuiOptions_defaultFilterPmToOther(false);
- }
-
- String guiOptions_defaultFilterPublicMsgs = element.getElementsByTagName("guiOptions_defaultFilterPublicMsgs").item(0)
- .getTextContent();
-
- if (guiOptions_defaultFilterPublicMsgs.equals("true")) {
- this.setGuiOptions_defaultFilterPublicMsgs(true);
- } else {
- this.setGuiOptions_defaultFilterPublicMsgs(false);
- }
-
-
- }
-
-
-
-
-
- catch (NullPointerException tooOldConfigFileOrFormatError) {
- /**
- * In program version 1.24 there had not been these settings in the xml and not founding em
- * would cause an exception and dumb values for the preferences. So we have to initialize
- * these variables and later write a proper configfile which can be used correctly then.
- *
- * So THESE ARE DEFAULTS for the new variables
- */
-
- tooOldConfigFileOrFormatError.printStackTrace();
- this.setGuiOptions_defaultFilterPmToMe(true);
- }
- }
- }
+ // Added in later versions: dark mode flags
+ this.GUI_darkModeActive = getBoolean(guiSaveableOptionsEl, this.GUI_darkModeActive, "guiOptions_darkModeActive");
+ this.GUI_darkModeActiveByDefault = getBoolean(guiSaveableOptionsEl, this.GUI_darkModeActiveByDefault, "guiOptions_darkModeActiveByDefault");
}
@@ -2375,8 +2357,24 @@ public class ChatPreferences {
this.stn_bandActive10G = stn_bandActive10G;
}
+ public boolean isGUI_darkModeActive() {
+ return GUI_darkModeActive;
+ }
+
+ public void setGUI_darkModeActive(boolean GUI_darkModeActive) {
+ this.GUI_darkModeActive = GUI_darkModeActive;
+ }
+
+ public boolean isGUI_darkModeActiveByDefault() {
+ return GUI_darkModeActiveByDefault;
+ }
+
+ public void setGUI_darkModeActiveByDefault(boolean GUI_darkModeActiveByDefault) {
+ this.GUI_darkModeActiveByDefault = GUI_darkModeActiveByDefault;
+ }
+
/**
- *
+ *
* If the file-reading goes wrong, set the defaults
*/
public void setPreferencesDefaults() {
@@ -2384,10 +2382,130 @@ public class ChatPreferences {
}
+ // ---------------------------------------------------------------------
+ // XML helper methods
+ // ---------------------------------------------------------------------
+
+ private static Element getFirstElement(Document doc, String tagName) {
+ NodeList nl = doc.getElementsByTagName(tagName);
+ if (nl == null || nl.getLength() == 0) {
+ return null;
+ }
+ Node n = nl.item(0);
+ return (n instanceof Element) ? (Element) n : null;
+ }
+
+ /**
+ * Returns the text content of the first matching child tag (directly under {@code parent})
+ * or {@code defaultValue} if the tag does not exist or is empty.
+ */
+ private static String getText(Element parent, String defaultValue, String... tagNames) {
+ if (parent == null || tagNames == null) {
+ return defaultValue;
+ }
+ for (String t : tagNames) {
+ if (t == null || t.isEmpty()) {
+ continue;
+ }
+ NodeList nl = parent.getElementsByTagName(t);
+ if (nl == null || nl.getLength() == 0) {
+ continue;
+ }
+ Node n = nl.item(0);
+ if (n == null) {
+ continue;
+ }
+ String v = n.getTextContent();
+ if (v != null) {
+ v = v.trim();
+ }
+ if (v != null && !v.isEmpty()) {
+ return v;
+ }
+ }
+ return defaultValue;
+ }
+
+ private static boolean getBoolean(Element parent, boolean defaultValue, String... tagNames) {
+ String v = getText(parent, null, tagNames);
+ if (v == null) {
+ return defaultValue;
+ }
+ return "true".equalsIgnoreCase(v) || "1".equals(v) || "yes".equalsIgnoreCase(v);
+ }
+
+ private static int getInt(Element parent, int defaultValue, String... tagNames) {
+ String v = getText(parent, null, tagNames);
+ if (v == null) {
+ return defaultValue;
+ }
+ try {
+ return Integer.parseInt(v.trim());
+ } catch (NumberFormatException ignore) {
+ return defaultValue;
+ }
+ }
+
+ private static double getDouble(Element parent, double defaultValue, String... tagNames) {
+ String v = getText(parent, null, tagNames);
+ if (v == null) {
+ return defaultValue;
+ }
+ try {
+ return Double.parseDouble(v.trim());
+ } catch (NumberFormatException ignore) {
+ return defaultValue;
+ }
+ }
+
+ private static int getIntFromDoc(Document doc, int defaultValue, String... tagNames) {
+ if (doc == null) {
+ return defaultValue;
+ }
+ for (String t : tagNames) {
+ if (t == null || t.isEmpty()) {
+ continue;
+ }
+ NodeList nl = doc.getElementsByTagName(t);
+ if (nl == null || nl.getLength() == 0) {
+ continue;
+ }
+ Node n = nl.item(0);
+ if (n == null) {
+ continue;
+ }
+ String v = n.getTextContent();
+ if (v == null) {
+ continue;
+ }
+ try {
+ return Integer.parseInt(v.trim());
+ } catch (NumberFormatException ignore) {
+ // try next
+ }
+ }
+ return defaultValue;
+ }
+
+ private static void parseSemicolonDoublesInto(String input, double[] target) {
+ if (input == null || target == null) {
+ return;
+ }
+ String[] parts = input.trim().split(";");
+ int len = Math.min(parts.length, target.length);
+ for (int i = 0; i < len; i++) {
+ try {
+ target[i] = Double.parseDouble(parts[i].trim());
+ } catch (NumberFormatException ignore) {
+ // keep existing value in target[i]
+ }
+ }
+ }
+
/**
* Checks wheter the input value of the String is numeric or not, true if yes
* TODO: Move to a utils class for checking input values by user...
- *
+ *
* @param str
* @return
*/
@@ -2397,14 +2515,63 @@ public class ChatPreferences {
// public ObservableList getTxtSnippetsAsObservableList(){
// ObservableList lst_txtSnipList = FXCollections.observableArrayList();
-//
+//
// for (int i = 0; i < textSnippets.length; i++) {
// lst_txtSnipList.add(textSnippets[i]);
// System.out.println(textSnippets[i]);
// }
-//
+//
// return lst_txtSnipList;
-//
+//
// }
+
+ /**
+ * Ensures that the divider position array matches the current number of dividers.
+ * This upgrades older XML configs (e.g. only 1 divider stored) without crashing.
+ */
+ public void ensureMainWindowRightSplitPaneDividerPositions(int requiredDividerCount) {
+ if (requiredDividerCount < 0) return;
+
+ if (GUImainWindowRightSplitPane_dividerposition != null
+ && GUImainWindowRightSplitPane_dividerposition.length == requiredDividerCount) {
+ return;
+ }
+
+ double[] upgraded = new double[requiredDividerCount];
+
+ for (int i = 0; i < requiredDividerCount; i++) {
+
+ // Prefer existing stored values if present
+ if (GUImainWindowRightSplitPane_dividerposition != null
+ && i < GUImainWindowRightSplitPane_dividerposition.length) {
+ upgraded[i] = GUImainWindowRightSplitPane_dividerposition[i];
+ continue;
+ }
+
+ // Otherwise use defaults, fallback to even spacing
+ if (i < GUImainWindowRightSplitPane_dividerpositionDefault.length) {
+ upgraded[i] = GUImainWindowRightSplitPane_dividerpositionDefault[i];
+ } else {
+ upgraded[i] = (i + 1.0) / (requiredDividerCount + 1.0);
+ }
+ }
+
+ GUImainWindowRightSplitPane_dividerposition = upgraded;
+ }
+
+ private static double parseDoubleOrDefault(String value, double defaultValue) {
+ if (value == null) return defaultValue;
+ String v = value.trim();
+ if (v.isEmpty()) return defaultValue;
+ try {
+ return Double.parseDouble(v);
+ } catch (Exception ignore) {
+ return defaultValue;
+ }
+ }
+
}
+
+
+
diff --git a/src/main/java/kst4contest/model/ContestSked.java b/src/main/java/kst4contest/model/ContestSked.java
new file mode 100644
index 0000000..bb3c576
--- /dev/null
+++ b/src/main/java/kst4contest/model/ContestSked.java
@@ -0,0 +1,52 @@
+package kst4contest.model;
+
+/**
+ * Represents a scheduled event or an AirScout opportunity in the future.
+ * Used for the Timeline View and Priority Calculation.
+ */
+public class ContestSked {
+
+ private String targetCallsign;
+ private double targetAzimuth; // Required for Antenna-Visuals
+ private long skedTimeEpoch; // The peak time (e.g., AP)
+ private Band band;
+ // Opportunity potential (0..100). -1 means "unknown".
+ int opportunityPotentialPercent = -1;
+
+ // Status flags to prevent spamming alarms
+ private boolean warning3MinSent = false;
+ private boolean warningNowSent = false;
+
+ public ContestSked(String call, double azimuth, long time, Band b) {
+ this.targetCallsign = call;
+ this.targetAzimuth = azimuth;
+ this.skedTimeEpoch = time;
+ this.band = b;
+ }
+
+ /**
+ * Returns the seconds remaining until the event.
+ * Negative values mean the event is in the past.
+ */
+ public long getTimeUntilSkedSeconds() {
+ return (skedTimeEpoch - System.currentTimeMillis()) / 1000;
+ }
+
+ // Getters and Setters...
+ public String getTargetCallsign() { return targetCallsign; }
+ public double getTargetAzimuth() { return targetAzimuth; }
+ public long getSkedTimeEpoch() { return skedTimeEpoch; }
+ public Band getBand() { return band; }
+ public boolean isWarning3MinSent() { return warning3MinSent; }
+ public void setWarning3MinSent(boolean b) { this.warning3MinSent = b; }
+ public boolean isWarningNowSent() { return warningNowSent; }
+ public void setWarningNowSent(boolean b) { this.warningNowSent = b; }
+
+ public int getOpportunityPotentialPercent() {
+ return opportunityPotentialPercent;
+ }
+
+ public void setOpportunityPotentialPercent(int opportunityPotentialPercent) {
+ this.opportunityPotentialPercent = opportunityPotentialPercent;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/kst4contest/model/ThreadStateMessage.java b/src/main/java/kst4contest/model/ThreadStateMessage.java
new file mode 100644
index 0000000..0d2ed89
--- /dev/null
+++ b/src/main/java/kst4contest/model/ThreadStateMessage.java
@@ -0,0 +1,103 @@
+package kst4contest.model;
+
+/**
+ * Object for the description of the activity of a Thread to show these information in a View.
+ *
+ * If state is critical, there could be used a further information field for the stacktrace
+ */
+public class ThreadStateMessage {
+ String threadNickName;
+ String threadDescription;
+ boolean running;
+ String runningInformationTextDescription;
+ String runningInformation;
+
+ boolean criticalState;
+ String criticalStateFurtherInfo;
+
+
+
+ public ThreadStateMessage(String threadNickName, boolean running, String runningInformation, boolean criticalState) {
+
+ this.threadNickName = threadNickName;
+ this.running = running;
+ this.criticalState = criticalState;
+ this.runningInformation = runningInformation;
+
+ }
+
+ /**
+ * This triggers the message for "Sked armed"
+ *
+ * @return
+ */
+ public String getRunningInformationTextDescription() {
+
+ // If a custom description was set (e.g. for UI indicator buttons), prefer it.
+ if (runningInformationTextDescription != null && !runningInformationTextDescription.isBlank()) {
+ return runningInformationTextDescription;
+ }
+
+ // Fallback (legacy behavior)
+ if (isRunning()) {
+ return "on";
+ } else if (!isRunning() && isCriticalState()) {
+ return "FAILED";
+ } else {
+ return "off";
+ }
+ }
+
+ public void setRunningInformationTextDescription(String runningInformationTextDescription) {
+ this.runningInformationTextDescription = runningInformationTextDescription;
+ }
+
+ public String getThreadNickName() {
+ return threadNickName;
+ }
+
+ public void setThreadNickName(String threadNickName) {
+ this.threadNickName = threadNickName;
+ }
+
+ public String getThreadDescription() {
+ return threadDescription;
+ }
+
+ public void setThreadDescription(String threadDescription) {
+ this.threadDescription = threadDescription;
+ }
+
+ public boolean isRunning() {
+ return running;
+ }
+
+ public void setRunning(boolean running) {
+ this.running = running;
+ }
+
+ public String getRunningInformation() {
+ return runningInformation;
+ }
+
+ public void setRunningInformation(String runningInformation) {
+ this.runningInformation = runningInformation;
+ }
+
+ public boolean isCriticalState() {
+ return criticalState;
+ }
+
+ public void setCriticalState(boolean criticalState) {
+ this.criticalState = criticalState;
+ }
+
+ public String getCriticalStateFurtherInfo() {
+ return criticalStateFurtherInfo;
+ }
+
+ public void setCriticalStateFurtherInfo(String criticalStateFurtherInfo) {
+ this.criticalStateFurtherInfo = criticalStateFurtherInfo;
+ }
+}
+
diff --git a/src/main/java/kst4contest/test/MockKstServer.java b/src/main/java/kst4contest/test/MockKstServer.java
new file mode 100644
index 0000000..da8e627
--- /dev/null
+++ b/src/main/java/kst4contest/test/MockKstServer.java
@@ -0,0 +1,256 @@
+package kst4contest.test;
+
+import java.io.*;
+import java.net.*;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+public class MockKstServer {
+
+ private static final int PORT = 23001;
+ private static final String CHAT_ID = "2"; // 2 = 144/432 MHz
+
+ // Thread-sichere Liste aller verbundenen Clients (OutputStreams)
+ private final List clients = new CopyOnWriteArrayList<>();
+
+ // Permanente User (Ihre Test-Callsigns)
+ private final Map onlineUsers = new HashMap<>();
+ // Historien müssen synchronisiert werden
+ private final List historyChat = Collections.synchronizedList(new ArrayList<>());
+ private final List historyDx = Collections.synchronizedList(new ArrayList<>());
+
+ private boolean running = false;
+ private ServerSocket serverSocket;
+
+ public MockKstServer() {
+ // Initiale Permanente User
+ addUser("DK5EW", "Erwin", "JN47NX");
+ addUser("DL1TEST", "TestOp", "JO50XX");
+ addUser("ON4KST", "Alain", "JO20HI");
+ addUser("PA9R-2", "2", "JO20HI");
+ addUser("PA9R-70", "70", "JO20HI");
+ addUser("PA9R", "general", "JO20HI");
+ }
+
+ // Startet den Server im Hintergrund (Non-Blocking)
+ public void start() {
+ if (running) return;
+ running = true;
+
+ new Thread(() -> {
+ try {
+ serverSocket = new ServerSocket(PORT);
+ System.out.println("[Server] ON4KST Simulation gestartet auf Port " + PORT);
+
+ // Startet den Simulator für Zufallstraffic
+ new Thread(this::simulationLoop).start();
+
+ while (running) {
+ Socket clientSocket = serverSocket.accept();
+ System.out.println("[Server] Neuer Client verbunden: " + clientSocket.getInetAddress());
+ new Thread(new ClientHandler(clientSocket)).start();
+ }
+ } catch (IOException e) {
+ if (running) e.printStackTrace();
+ }
+ }).start();
+ }
+
+ public void stop() {
+ running = false;
+ try {
+ if (serverSocket != null) serverSocket.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void addUser(String call, String name, String loc) {
+ onlineUsers.put(call, new User(call, name, loc));
+ }
+
+ private void removeUser(String call) {
+ onlineUsers.remove(call);
+ }
+
+ // Sendet Nachricht an ALLE verbundenen Clients (inkl. Sender)
+ private void broadcast(String message) {
+ if (!message.endsWith("\r\n")) message += "\r\n";
+ String finalMsg = message;
+
+ for (PrintWriter writer : clients) {
+ try {
+ writer.print(finalMsg);
+ writer.flush(); // WICHTIG: Sofort senden!
+ } catch (Exception e) {
+ // Client wohl weg, wird beim nächsten Schreibversuch oder im Handler entfernt
+ }
+ }
+ }
+
+ // --- Innere Logik: Client Handler ---
+ private class ClientHandler implements Runnable {
+ private Socket socket;
+ private PrintWriter out;
+ private BufferedReader in;
+ private String myCall = "MYCLIENT"; // Default, wird bei LOGIN überschrieben
+
+ public ClientHandler(Socket socket) {
+ this.socket = socket;
+ }
+
+ @Override
+ public void run() {
+ try {
+ // ISO-8859-1 ist Standard für KST/Telnet Cluster
+ in = new BufferedReader(new InputStreamReader(socket.getInputStream(), "ISO-8859-1"));
+ out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), "ISO-8859-1"), true);
+
+ clients.add(out);
+
+ String line;
+ boolean loginComplete = false;
+
+ while ((line = in.readLine()) != null) {
+ // System.out.println("[RECV] " + line); // Debugging aktivieren falls nötig
+ String[] parts = line.split("\\|");
+ String cmd = parts[0];
+
+ if (cmd.equals("LOGIN") || cmd.equals("LOGINC")) {
+ // Protokoll: LOGIN|callsign|password|... [cite: 21]
+ if (parts.length > 1) myCall = parts[1];
+
+ // 1. Login Bestätigung
+ // Format: LOGSTAT|100|chat id|client software version|session key|config|dx option|
+ send("LOGSTAT|100|" + CHAT_ID + "|JavaSim|KEY123|Config|3|");
+
+ // Bei LOGIN senden wir die Daten sofort
+ // Bei LOGINC warten wir eigentlich auf SDONE, senden hier aber vereinfacht direkt
+ if (cmd.equals("LOGIN")) {
+ sendInitialData();
+ loginComplete = true;
+ }
+ }
+ else if (cmd.equals("SDONE")) {
+ // Abschluss der Settings (bei LOGINC) [cite: 34]
+ sendInitialData();
+ loginComplete = true;
+ }
+ else if (cmd.equals("MSG")) {
+ // MSG|chat id|destination|command|0| [cite: 42]
+ if (parts.length >= 4) {
+ String text = parts[3];
+ // Nachricht sofort als CH Frame an alle verteilen (Echo)
+ handleChatMessage(myCall, "Me", text);
+ }
+ }
+ else if (cmd.equals("CK")) {
+ // Keepalive [cite: 20]
+ // Server muss nicht zwingend antworten, aber Connection bleibt offen
+ }
+ }
+ } catch (IOException e) {
+ // System.out.println("Client getrennt");
+ } finally {
+ clients.remove(out);
+ try { socket.close(); } catch (IOException e) {}
+ }
+ }
+
+ private void send(String msg) {
+ if (!msg.endsWith("\r\n")) msg += "\r\n";
+ out.print(msg);
+ out.flush();
+ }
+
+ private void sendInitialData() {
+ // 1. User Liste UA0 [cite: 14]
+ for (User u : onlineUsers.values()) {
+ send("UA0|" + CHAT_ID + "|" + u.call + "|" + u.name + "|" + u.loc + "|0|");
+ }
+ // 2. Chat History CR [cite: 7]
+ synchronized(historyChat) {
+ for (String h : historyChat) send(h);
+ }
+ // 3. DX History DL [cite: 10]
+ synchronized(historyDx) {
+ for (String d : historyDx) send(d);
+ }
+ // 4. Ende User Liste UE [cite: 15]
+ send("UE|" + CHAT_ID + "|" + onlineUsers.size() + "|");
+ }
+ }
+
+ // --- Hilfsmethoden für Traffic ---
+
+ private void handleChatMessage(String call, String name, String text) {
+ // CH|chat id|date|callsign|firstname|destination|msg|highlight|
+ String date = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
+ String frame = String.format("CH|%s|%s|%s|%s|0|%s|0|", CHAT_ID, date, call, name, text);
+
+ synchronized(historyChat) {
+ historyChat.add(frame);
+ if (historyChat.size() > 50) historyChat.remove(0);
+ }
+ broadcast(frame);
+ }
+
+ private void handleDxSpot(String spotter, String dx, String freq) {
+ // DL|Unix time|dx utc|spotter|qrg|dx|info|spotter locator|dx locator| [cite: 10]
+ long unixTime = System.currentTimeMillis() / 1000;
+ String utc = new SimpleDateFormat("HHmm").format(new Date());
+ // Simple Dummy Locators
+ String frame = String.format("DL|%d|%s|%s|%s|%s|Simulated|JO00|JO99|",
+ unixTime, utc, spotter, freq, dx);
+
+ synchronized(historyDx) {
+ historyDx.add(frame);
+ if (historyDx.size() > 20) historyDx.remove(0);
+ }
+ broadcast(frame);
+ }
+
+ private void simulationLoop() {
+ String[] randomCalls = {"PA0GUS", "F6APE", "OH8K", "OZ2M", "G4CBW"};
+ String[] msgs = {"CQ 144.300", "Tnx for QSO", "Any sked?", "QRV 432.200"};
+ Random rand = new Random();
+
+ while (running) {
+ try {
+ Thread.sleep(3000 + rand.nextInt(5000)); // 3-8 Sek Pause
+
+ int action = rand.nextInt(10);
+ String call = randomCalls[rand.nextInt(randomCalls.length)];
+
+ if (action < 4) { // 40% Chat
+ handleChatMessage(call, "SimOp", msgs[rand.nextInt(msgs.length)]);
+ } else if (action < 7) { // 30% DX Spot
+ handleDxSpot(call, randomCalls[rand.nextInt(randomCalls.length)], "144." + rand.nextInt(400));
+ } else if (action == 8) { // Login Simulation UA5
+ if (!onlineUsers.containsKey(call)) {
+ addUser(call, "SimOp", "JO11");
+ broadcast("UA5|" + CHAT_ID + "|" + call + "|SimOp|JO11|2|");
+ }
+ } else if (action == 9) { // Logout Simulation UR6
+ if (onlineUsers.containsKey(call) && !call.equals("DK5EW")) { // DK5EW nicht kicken
+ removeUser(call);
+ broadcast("UR6|" + CHAT_ID + "|" + call + "|");
+ }
+ }
+
+ // Ping ab und zu
+ if (rand.nextInt(5) == 0) broadcast("CK|");
+
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ // Kleine Datenklasse
+ private static class User {
+ String call, name, loc;
+ User(String c, String n, String l) { this.call=c; this.name=n; this.loc=l; }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/kst4contest/view/GuiUtils.java b/src/main/java/kst4contest/view/GuiUtils.java
index 9af1d4f..44225ab 100644
--- a/src/main/java/kst4contest/view/GuiUtils.java
+++ b/src/main/java/kst4contest/view/GuiUtils.java
@@ -44,25 +44,33 @@ public class GuiUtils {
public static void triggerGUIFilteredChatMemberListChange(ChatController chatController) {
- {
- //trick to trigger gui changes on property changes of obects
-
- Predicate dummyPredicate = new Predicate() {
- @Override
- public boolean test(ChatMember chatMember) {
- return true;
- }
- };
-
- /**
- * //TODO: following 2 lines are a quick fix to making disappear worked chatmembers of the list
- * Thats uncomfortable due to this also causes selection changes,
- * Better way is to change all worked and qrv values to observables and then trigger the underlying
- * list to fire an invalidationevent. Really Todo!
- */
- chatController.getLst_chatMemberListFilterPredicates().add(dummyPredicate);
- chatController.getLst_chatMemberListFilterPredicates().remove(dummyPredicate);
-
- }
+ if (javafx.application.Platform.isFxApplicationThread()) {
+ triggerUpdate(chatController);
+ } else{
+ javafx.application.Platform.runLater(() -> triggerUpdate(chatController));
+ }
}
+
+ private static void triggerUpdate(ChatController chatController) {
+ {
+ //trick to trigger gui changes on property changes of obects
+
+ Predicate dummyPredicate = new Predicate() {
+ @Override
+ public boolean test(ChatMember chatMember) {
+ return true;
+ }
+ };
+
+ /**
+ * //TODO: following 2 lines are a quick fix to making disappear worked chatmembers of the list
+ * Thats uncomfortable due to this also causes selection changes,
+ * Better way is to change all worked and qrv values to observables and then trigger the underlying
+ * list to fire an invalidationevent. Really Todo!
+ */
+ chatController.getLst_chatMemberListFilterPredicates().add(dummyPredicate);
+ chatController.getLst_chatMemberListFilterPredicates().remove(dummyPredicate);
+
+ }
+ }
}
diff --git a/src/main/java/kst4contest/view/Kst4ContestApplication.java b/src/main/java/kst4contest/view/Kst4ContestApplication.java
index 92665c9..0b9578e 100644
--- a/src/main/java/kst4contest/view/Kst4ContestApplication.java
+++ b/src/main/java/kst4contest/view/Kst4ContestApplication.java
@@ -7,6 +7,15 @@ import java.util.*;
import java.util.function.Consumer;
import java.util.function.Predicate;
+import javafx.animation.KeyFrame;
+import javafx.animation.Timeline;
+import javafx.collections.FXCollections;
+import javafx.event.Event;
+import kst4contest.view.TimelineView; // The new class we created
+import kst4contest.model.ContestSked; // The new model
+import javafx.scene.control.TableRow; // For the priority coloring
+
+import javafx.animation.PauseTransition;
import javafx.beans.binding.Bindings;
import javafx.css.PseudoClass;
import javafx.geometry.*;
@@ -15,8 +24,10 @@ import javafx.scene.input.*;
import javafx.scene.layout.*;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
+import javafx.util.Duration;
import kst4contest.ApplicationConstants;
import kst4contest.controller.ChatController;
+import kst4contest.controller.StatusUpdateListener;
import kst4contest.controller.Utils4KST;
import javafx.application.Application;
import javafx.application.Platform;
@@ -48,9 +59,37 @@ import javafx.scene.shape.Polygon;
import kst4contest.utils.ApplicationFileUtils;
-public class Kst4ContestApplication extends Application {
+public class Kst4ContestApplication extends Application implements StatusUpdateListener {
// private static final Kst4ContestApplication dbcontroller = new DBController();
+
+ private final Button btnBandUpgradeIndicator = new Button("BAND+");
+ private final Tooltip tipBandUpgradeIndicator = new Tooltip();
+ private Timeline bandUpgradeBlinkTimeline;
+
+ private final Button btnSkedWarnIndicator = new Button("SKED");
+ private final Tooltip tipSkedWarnIndicator = new Tooltip();
+ private Timeline skedWarnBlinkTimeline;
+
+
+ // Timeline: show at most N priority markers per minute bucket (minute 0/1 often has many planes)
+ private static final int TIMELINE_PRIORITY_MARKERS_PER_MINUTE = 2;
+
+ // Timeline: show 2 more in other directions
+ private static final int TIMELINE_BEAM_MARKERS_PER_MINUTE = 2;
+
+
+ // Keep in sync with TimelineView PREVIEW_TIME_MS (currently 30 minutes = 30L * 60L * 1000L)
+ private static final long TIMELINE_PREVIEW_TIME_MS = 30L * 60L * 1000L;
+
+
+ //recoloring of the chatmembers list is turned on and off here
+ private static final boolean ENABLE_PRIORITY_SCORE_ROW_COLORING = false;
+
+ private TimelineView timelineView; //timeline view above the sendtext-field
+
+ private final Map statusButtons = new HashMap<>(); //there we will place some flickering
+
public static final String STYLE_DEFAULTCSSDAY_FILE = "KST4ContestDefaultDay.css";
public static final String STYLE_DEFAULTCSSDAY_RESOURCE = "/KST4ContestDefaultDay.css";
@@ -59,16 +98,47 @@ public class Kst4ContestApplication extends Application {
String chatState;
ChatController chatcontroller;
+
+
Button MYQRGButton; // TODO: clean code? Got the myqrg button out of the factory method to modify
// the text later
Button MYCALLSetQRGButton;
Timer timer_buildWindowTitle;
- Timer timer_chatMemberTableSortTimer; // need that because javafx bug, it´s the only way to actualize the table...
+// Timer timer_chatMemberTableSortTimer; // need that because javafx bug, it´s the only way to actualize the table...
Timer timer_updatePrivatemessageTable; // same here
VBox selectedCallSignFurtherInfoPane = new VBox();
- Button[] btnQtfButtonsAvl = new Button[8];
+ ToggleButton[] btnQtfButtonsAvl = new ToggleButton[8];
+
+ /**
+ * helper DTO for planes and arriving time in minutes. Maybe
+ */
+ private static final class NextApInfo {
+ final AirPlane plane;
+ final int arrivingMinutes;
+
+ private NextApInfo(AirPlane plane, int arrivingMinutes) {
+ this.plane = plane;
+ this.arrivingMinutes = arrivingMinutes;
+ }
+ }
+
+ /**
+ * Helper DTO for timeline building
+ */
+ private static final class TimelineCandidateTmp {
+ final kst4contest.controller.ScoreService.TopCandidate top;
+ final ChatMember representativeMember;
+ final NextApInfo nextAp;
+
+ TimelineCandidateTmp(kst4contest.controller.ScoreService.TopCandidate top, ChatMember representativeMember, NextApInfo nextAp) {
+ this.top = top;
+ this.representativeMember = representativeMember;
+ this.nextAp = nextAp;
+ }
+ }
+
public static void showUserInputErrorWindow (String message) {
@@ -121,6 +191,123 @@ public class Kst4ContestApplication extends Application {
return new javafx.scene.Group(arrowLine, arrowhead);
}
+ /**
+ * Gets thread notifications and makes new statusbuttons at the top
+ *
+ * @param sourceName
+ */
+ private void updateStatusButton(String sourceName, ThreadStateMessage threadStateMessage) {
+ Button button = statusButtons.computeIfAbsent(sourceName, name -> {
+ Button b = new Button(threadStateMessage.getThreadNickName());
+ b.getStyleClass().removeIf(cls -> cls.startsWith("btn-showstate"));
+
+ b.getStyleClass().add("btn-showstate-enabled");
+ b.setTooltip(new Tooltip(threadStateMessage.getRunningInformation()));
+
+ this.flwpne_StatusBar.getChildren().add(b); // BorderPane oder HBox o. ä.
+ return b;
+ });
+
+
+ button.setText(sourceName + ": " + threadStateMessage.getRunningInformationTextDescription());
+
+ button.getTooltip().setText(threadStateMessage.getRunningInformation());
+ button.getStyleClass().removeIf(cls -> cls.startsWith("btn-showstate"));
+ button.getStyleClass().add("btn-showstate-enabled-furtherInfo");
+// button.setStyle("-fx-text-fill: red;");
+
+
+ PauseTransition pause = new PauseTransition(Duration.seconds(0.2));
+ pause.setOnFinished(e -> {
+ button.getStyleClass().removeIf(cls -> cls.startsWith("btn-showstate"));
+ button.getStyleClass().add("btn-showstate-enabled-default");
+// button.setStyle("-fx-text-fill: blue;");
+ });
+ pause.play();
+
+ }
+
+ /**
+ * Helps the view to format the RX Bands for a callsign, using the chatmembers frequencies detected MAP
+ * @param callSignRaw
+ * @param maxAgeMs
+ * @return
+ */
+ private String formatDetectedRxBandsForCallsignRaw(String callSignRaw, long maxAgeMs) {
+
+ if (callSignRaw == null) return "Bands: -";
+
+ // band -> (freq,timestamp) newest across ALL category-variants
+ Map newestPerBand = new java.util.EnumMap<>(kst4contest.model.Band.class);
+
+ synchronized (chatcontroller.getLst_chatMemberList()) {
+ for (ChatMember m : chatcontroller.getLst_chatMemberList()) {
+ if (m == null) continue;
+ if (m.getCallSignRaw() == null) continue;
+ if (!m.getCallSignRaw().equalsIgnoreCase(callSignRaw)) continue;
+
+ Map map = m.getKnownActiveBands();
+ if (map == null) continue;
+
+ for (Map.Entry e : map.entrySet()) {
+ kst4contest.model.Band band = e.getKey();
+ ChatMember.ActiveFrequencyInfo info = e.getValue();
+ if (band == null || info == null) continue;
+
+ // optional age filter (e.g. last 30 minutes)
+ if (maxAgeMs > 0 && (System.currentTimeMillis() - info.timestampEpoch) > maxAgeMs) {
+ continue;
+ }
+
+ ChatMember.ActiveFrequencyInfo existing = newestPerBand.get(band);
+ if (existing == null || info.timestampEpoch > existing.timestampEpoch) {
+ newestPerBand.put(band, info);
+ }
+ }
+ }
+ }
+
+ if (newestPerBand.isEmpty()) {
+ return "Bands: -";
+ }
+
+ // Render sorted by band enum order
+ StringBuilder sb = new StringBuilder("Bands: ");
+ boolean first = true;
+
+ for (kst4contest.model.Band b : kst4contest.model.Band.values()) {
+ ChatMember.ActiveFrequencyInfo info = newestPerBand.get(b);
+ if (info == null) continue;
+
+ long ageMin = (System.currentTimeMillis() - info.timestampEpoch) / 60000L;
+
+ if (!first) sb.append(" | ");
+ first = false;
+
+ sb.append(String.format(java.util.Locale.US, "%.3f", info.frequency))
+ .append(" MHz")
+ .append(" (")
+ .append(ageMin)
+ .append(" min ago)");
+ }
+
+ return sb.toString();
+ }
+
+ private String bandToHumanLabel(kst4contest.model.Band b) {
+ // Human-friendly labels for VHF/UHF/microwave contesting
+ return switch (b) {
+ case B_144 -> "2m";
+ case B_432 -> "70cm";
+ case B_1296 -> "23cm";
+ case B_2320 -> "13cm";
+ case B_3400 -> "9cm";
+ case B_5760 -> "6cm";
+ case B_10G -> "3cm";
+ case B_24G -> "24G";
+ };
+ }
+
/**
* This method generates a BoderPane which shows some additional information about a callsign which had been
@@ -158,6 +345,96 @@ public class Kst4ContestApplication extends Application {
selectedCallSignDownerSiteGridPane.add(selectedCallSignInfoLblQRBInfo, 0,1,1,1);
selectedCallSignDownerSiteGridPane.add(new Label("Last activity: " + new Utils4KST().time_convertEpochToReadable(selectedCallSignInfoStageChatMember.getActivityTimeLastInEpoch()+"")), 0,2,1,1);
selectedCallSignDownerSiteGridPane.add(new Label(("(" + Utils4KST.time_getSecondsBetweenEpochAndNow(selectedCallSignInfoStageChatMember.getActivityTimeLastInEpoch()+"") /60%60) +" min ago)"), 0,3,1,1);
+
+ // Show detected RX bands based on frequency recognition in chat history.
+ // Default: last 30 minutes (same horizon as Smart Parser history usage)
+ Label lblDetectedRxBands = new Label(
+ formatDetectedRxBandsForCallsignRaw(selectedCallSignInfoStageChatMember.getCallSignRaw(), 30L * 60L * 1000L)
+ );
+ lblDetectedRxBands.setWrapText(true);
+ selectedCallSignDownerSiteGridPane.add(lblDetectedRxBands, 0, 4, 1, 1);
+
+
+ Label selectedCallSignInfoLblPriorityScore = new Label();
+ selectedCallSignInfoLblPriorityScore.textProperty().bind(Bindings.createStringBinding(
+ () -> {
+ double s = chatcontroller.getScoreService().selectedCallPriorityScoreProperty().get();
+ if (Double.isNaN(s)) return "Priority score: -";
+ return String.format(java.util.Locale.US, "Priority score: %.0f", s);
+ },
+ chatcontroller.getScoreService().selectedCallPriorityScoreProperty()));
+// selectedCallSignDownerSiteGridPane.add(selectedCallSignInfoLblPriorityScore, 0,5,1,1);
+
+ Button btnSkedFail = new Button("Sked fail");
+ btnSkedFail.setTooltip(new Tooltip("Marks the path as failed (permanent until reset). Strongly reduces priority score."));
+ btnSkedFail.setOnAction(e -> {
+ ChatMember sel = chatcontroller.getScoreService().selectedChatMemberProperty().get();
+ if (sel == null) return;
+ chatcontroller.getStationMetricsService().markManualSkedFail(sel.getCallSignRaw());
+ chatcontroller.getScoreService().requestRecompute("manual-sked-fail");
+ });
+
+ Button btnSkedFailReset = new Button("Reset fail");
+ btnSkedFailReset.setTooltip(new Tooltip("Resets the manual sked-fail flag for this station."));
+ btnSkedFailReset.setOnAction(e -> {
+ ChatMember sel = chatcontroller.getScoreService().selectedChatMemberProperty().get();
+ if (sel == null) return;
+ chatcontroller.getStationMetricsService().resetManualSkedFail(sel.getCallSignRaw());
+ chatcontroller.getScoreService().requestRecompute("manual-sked-fail-reset");
+ });
+
+ HBox priorityRow = new HBox(8, selectedCallSignInfoLblPriorityScore, btnSkedFail, btnSkedFailReset);
+ priorityRow.setAlignment(Pos.CENTER_LEFT);
+
+ selectedCallSignDownerSiteGridPane.add(priorityRow, 0, 5, 1, 1);
+
+ ChoiceBox cbSkedMinutes = new ChoiceBox<>(FXCollections.observableArrayList(2, 3, 4, 5, 6,7,8,9, 10,11,12,13,14, 15, 20));
+ cbSkedMinutes.getSelectionModel().select(Integer.valueOf(5));
+
+ ChoiceBox cbReminderOffsets = new ChoiceBox<>(FXCollections.observableArrayList("2+1", "5+2+1", "10+5+2+1"));
+ cbReminderOffsets.getSelectionModel().select("2+1");
+
+ CheckBox chkPmReminders = new CheckBox("Remind-PM in ");
+
+ Button btnCreateSked = new Button("Create sked");
+ btnCreateSked.setTooltip(new Tooltip("Creates a sked entry and boosts priority (ramp-up)."));
+
+ btnCreateSked.setOnAction(e -> {
+ ChatMember sel = chatcontroller.getScoreService().selectedChatMemberProperty().get();
+ if (sel == null) return;
+
+ int minutes = cbSkedMinutes.getValue() == null ? 5 : cbSkedMinutes.getValue();
+ long skedTime = System.currentTimeMillis() + minutes * 60_000L;
+
+ double az = sel.getQTFdirection() != null ? sel.getQTFdirection() : 0.0;
+
+ // band is not strictly required for scoring; keep current category context
+ Band band = Band.B_144; // if you want, replace with a real dropdown later
+ ContestSked sked = new ContestSked(sel.getCallSignRaw(), az, skedTime, band);
+
+ chatcontroller.addSked(sked);
+ chatcontroller.getScoreService().requestRecompute("sked-created");
+
+ if (chkPmReminders.isSelected()) {
+ List offsets = parseMinuteOffsets(cbReminderOffsets.getValue());
+ chatcontroller.getSkedReminderService().armReminders(sel.getCallSignRaw(), sel.getChatCategory(), skedTime, offsets);
+ }
+ });
+
+ HBox skedRow = new HBox(10,
+ new Label("Sked in"),
+ cbSkedMinutes,
+ new Label("min"),
+ btnCreateSked,
+ chkPmReminders,
+ cbReminderOffsets
+ );
+ skedRow.setAlignment(Pos.CENTER_LEFT);
+
+ selectedCallSignDownerSiteGridPane.add(skedRow, 0, 6, 1, 1);
+
+
+
Label selectedCallSignChatCategoryLabelDesc = new Label(selectedCallSignInfoStageChatMember.getCallSign() + " in chatcategory: " + selectedCallSignInfoStageChatMember.getChatCategory().getChatCategoryName(selectedCallSignInfoStageChatMember.getChatCategory().getCategoryNumber()));
selectedCallSignChatCategoryLabelDesc.getStyleClass().clear();
@@ -399,9 +676,30 @@ public class Kst4ContestApplication extends Application {
chatcontroller.airScout_SendAsShowPathPacket(selectedCallSignInfoStageChatMember);
}
});
-
selectedCallSignShowAsPathBtn.setGraphic(createArrow(selectedCallSignInfoStageChatMember.getQTFdirection()));
+
+ Button selectedCallSignTurnAntBtn = new Button("Turn ant1 to " + selectedCallSignInfoStageChatMember.getCallSignRaw());
+ selectedCallSignTurnAntBtn.setOnAction(new EventHandler() {
+ @Override
+ public void handle(ActionEvent actionEvent) {
+// chatcontroller.airScout_SendAsShowPathPacket(selectedCallSignInfoStageChatMember);
+// Alert a = new Alert(AlertType.INFORMATION);
+//
+// a.setTitle("Not yet implemented!");
+// a.setHeaderText("kst4Contest " + ApplicationConstants.APPLICATION_CURRENTVERSIONNUMBER + ": This is a todo!");
+// a.setContentText("Mach mal hinne!");
+// a.show();
+// chatcontroller.stopRotator(); //if it´s running, stop it firstly, then set the new value
+// chatcontroller.stopRotator();
+ chatcontroller.rotateTo(selectedCallSignInfoStageChatMember.getQTFdirection());
+
+
+ //TODO: Hier muss was hin
+ }
+ });
+ selectedCallSignTurnAntBtn.setGraphic(createArrow(selectedCallSignInfoStageChatMember.getQTFdirection()));
+
Button selectedCallSignShowQRZprofile = new Button("Lookup on qrz.com");
selectedCallSignShowQRZprofile.setOnAction(new EventHandler() {
@Override
@@ -419,8 +717,10 @@ public class Kst4ContestApplication extends Application {
});
selectedCallSignDownerSiteGridPane.add(selectedCallSignShowAsPathBtn, 1,0,1,1);
- selectedCallSignDownerSiteGridPane.add(selectedCallSignShowQRZprofile, 1,1,1,1);
- selectedCallSignDownerSiteGridPane.add(selectedCallSignShowQRZCqprofile, 1,2,1,1);
+ selectedCallSignDownerSiteGridPane.add(selectedCallSignTurnAntBtn, 1,1,1,1);
+
+ selectedCallSignDownerSiteGridPane.add(selectedCallSignShowQRZprofile, 1,2,1,1);
+ selectedCallSignDownerSiteGridPane.add(selectedCallSignShowQRZCqprofile, 1,3,1,1);
@@ -476,6 +776,11 @@ public class Kst4ContestApplication extends Application {
try {
+ //message is directed to all and I am not mentioned
+ if (chatMessage.getReceiver().getCallSign().equals("ALL") && !(chatMessage.getMessageText().toLowerCase().contains(chatcontroller.getChatPreferences().getStn_loginCallSign().toLowerCase()))) {
+ return false;
+ }
+
if (((chatMessage.getReceiver().getCallSign().equals(chatcontroller.getChatPreferences().getStn_loginCallSign())) || (chatMessage.getSender().getCallSign().equals(chatcontroller.getChatPreferences().getStn_loginCallSign()))
) && ((chatMessage.getReceiver().getCallSign().equals(selectedCallSignInfoStageChatMember.getCallSign())) || (chatMessage.getSender().getCallSign().equals(selectedCallSignInfoStageChatMember.getCallSign())))) {
return true;
@@ -612,6 +917,24 @@ public class Kst4ContestApplication extends Application {
}
+ /**
+ * Helper method for furtherinfoPane
+ * @param s
+ * @return
+ */
+ private static List parseMinuteOffsets(String s) {
+ if (s == null || s.isBlank()) return List.of();
+ String[] parts = s.split("\\+");
+ List out = new ArrayList<>();
+ for (String p : parts) {
+ try {
+ out.add(Integer.parseInt(p.trim()));
+ } catch (Exception ignore) {}
+ }
+ return out;
+ }
+
+
private TableView initChatMemberTable() {
TableView tbl_chatMemberTable = new TableView();
@@ -842,7 +1165,7 @@ public class Kst4ContestApplication extends Application {
// qrg = (cellDataFeatures.getValue().getFrequency());
// if (!qrg.getValue().equals("")) {
-//
+//
// }
return cellDataFeatures.getValue().getFrequency();
@@ -1272,146 +1595,136 @@ public class Kst4ContestApplication extends Application {
* the table in intervals to keep the table up to date.
*/
- timer_chatMemberTableSortTimer = new Timer();
-
- timer_chatMemberTableSortTimer.scheduleAtFixedRate(new TimerTask() {
-
- public void run() {
- Thread.currentThread().setName("chatMemberTableSortTimer");
-
-// System.out.println("[KST4CApp, Info:] Chatmemberlist-Filterlist predicates size: " + chatcontroller.getLst_chatMemberListFilterPredicates().size());
-
-// {
-// //trick to trigger gui changes on property changes of obects
+// timer_chatMemberTableSortTimer = new Timer();
+// timer_chatMemberTableSortTimer.scheduleAtFixedRate(new TimerTask() {
//
-// Predicate dummyPredicate = new Predicate() {
-// @Override
-// public boolean test(ChatMember chatMember) {
-// return true;
-// }
-// };
+// public void run() {
+// Thread.currentThread().setName("chatMemberTableSortTimer");
//
-// /**
-// * //TODO: following 2 lines are a quick fix to making disappear worked chatmembers of the list
-// * Thats uncomfortable due to this also causes selection changes,
-// * Better way is to change all worked and qrv values to observables and then trigger the underlying
-// * list to fire an invalidationevent. Really Todo!
-// */
-// chatcontroller.getLst_chatMemberListFilterPredicates().add(dummyPredicate);
-//// chatcontroller.getLst_chatMemberListFilterPredicates().remove(dummyPredicate);
+// Platform.runLater(() -> {
//
-// }
-
-// System.out.println("[KST4CApp, Info:] Deviderpos: " + spl);
-// for (int i = 0; i < chatcontroller.getLst_chatMemberListFilterPredicates().size(); i++) {
+// try {
//
-// Predicate test = chatcontroller.getLst_chatMemberListFilterPredicates().get(i);
-// test.so
-// }
-
-
- Platform.runLater(() -> {
-
- try {
-
-// tbl_chatMemberTable.sort();
-
- } catch (Exception e) {
- System.out.println("[Main.java, Warning:] Table sorting (actualizing) failed this time.");
- }
-
-
- tbl_chatMemberTable.refresh();
-
-// tbl_chatMemberTable.
-
- });
- }
- }, new Date(), 5000);
+//// tbl_chatMemberTable.sort();
+//
+// } catch (Exception e) {
+// System.out.println("[Main.java, Warning:] Table sorting (actualizing) failed this time.");
+// }
+//
+//
+// tbl_chatMemberTable.refresh();
+//
+//// tbl_chatMemberTable.
+//
+// });
+// }
+// }, new Date(), 5000);
tbl_chatMemberTable.setColumnResizePolicy(TableView.UNCONSTRAINED_RESIZE_POLICY);
tbl_chatMemberTable.autosize();
+
+ /**
+ * expoerimental, new since 1.40: priorities
+ */
+
+ tbl_chatMemberTable.setRowFactory(tv -> new TableRow() {
+ @Override
+ protected void updateItem(ChatMember item, boolean empty) {
+ super.updateItem(item, empty);
+
+ if (!ENABLE_PRIORITY_SCORE_ROW_COLORING) {
+
+ setStyle(""); // Reset style for empty rows
+ } else {
+ double score = item.getCurrentPriorityScore(); // Ensure ChatMember has this getter!
+
+ // Color Logic:
+ // > 1000 = NUCLEAR (Imminent Sked) -> Blinking Red (simulated here with solid red)
+ // > 200 = High Prio (AirScout / Good Sked) -> Orange
+ // > 100 = Medium Prio (Unworked / New Multi) -> Light Yellow
+ // <= 0 = Low Prio / Not Reachable -> Greyed out text
+
+ // Note: Styles need to be adjusted if Dark Mode is active!
+
+ boolean isDark = chatcontroller.getChatPreferences().isGUI_darkModeActive();
+
+ if (score > 1000) {
+ // Critical Alert
+ setStyle("-fx-background-color: #ff4d4d; -fx-text-fill: white; -fx-font-weight: bold;");
+ } else if (score >= 200) {
+ // High Priority
+ setStyle("-fx-background-color: " + (isDark ? "#cc6600" : "#ffcc00") + "; -fx-text-fill: black;");
+ } else if (score >= 100) {
+ // Medium Priority
+ setStyle("-fx-background-color: " + (isDark ? "#888800" : "#ffffcc") + "; -fx-text-fill: black;");
+ } else if (score <= 0) {
+ // Penalty / Not Reachable
+ setStyle("-fx-text-fill: " + (isDark ? "#666666" : "#aaaaaa") + ";");
+ } else {
+ // Standard Reset
+ setStyle("");
+ }
+ }
+ }
+ });
+
return tbl_chatMemberTable;
}
- /**
- * Initializes the right click contextmenu for the chatmember-table, sets the
- * clickhandler for the contextmenu out of a string array (each menuitam will be
- * created out of exact one array-entry). These are initialized by the
- * chatpreferences object out of the config-xml
- *
- *
- * @return
- */
-// private ContextMenu initChatMemberTableContextMenu(String[] menuTexts) { old mechanic
-//
-// ContextMenu chatMemberContextMenu = new ContextMenu();
-//
-// for (int i = 0; i < menuTexts.length; i++) {
-// final MenuItem menuItem = new MenuItem(menuTexts[i]);
-// menuItem.setOnAction(new EventHandler() {
-// public void handle(ActionEvent event) {
-// txt_chatMessageUserInput.setText(txt_chatMessageUserInput.getText() + menuItem.getText());
-// }
-// });
-//
-// chatMemberContextMenu.getItems().add(menuItem);
-// }
-//
-//// MenuItem macro1 = new MenuItem("Pse Sked?");
-//// macro1.setOnAction(new EventHandler() {
-//// public void handle(ActionEvent event) {
-//// txt_chatMessageUserInput.setText(txt_chatMessageUserInput.getText() + macro1.getText());
-//// }
-//// });
-//// MenuItem macro10 = new MenuItem("Pse qrg 2m?");
-//// MenuItem macro20 = new MenuItem("Pse Call at ");
-//// MenuItem macro30 = new MenuItem("In qso nw, pse qrx, I will meep you");
-//// MenuItem macro40 = new MenuItem("Pse qrg 70cm?");
-//// MenuItem macro50 = new MenuItem("pse qrg 23cm?");
-//// MenuItem macro60 = new MenuItem("____________________________________");
-//// MenuItem macro70 = new MenuItem("Watch QSO history");
-////
-//// chatMemberContextMenu.getItems().add(macro1);
-//// chatMemberContextMenu.getItems().add(macro10);
-//// chatMemberContextMenu.getItems().add(macro20);
-//// chatMemberContextMenu.getItems().add(macro30);
-//// chatMemberContextMenu.getItems().add(macro40);
-//// chatMemberContextMenu.getItems().add(macro50);
-//// chatMemberContextMenu.getItems().add(macro60);
-//// chatMemberContextMenu.getItems().add(macro70);
-//
-// return chatMemberContextMenu;
-//
-// }
+ private ChatMember resolveChatMemberForCallRawAndCategory(String callRaw, ChatCategory preferredCategory) {
+
+ if (callRaw == null) return null;
+
+ // 1) Prefer exact (callRaw + category)
+ synchronized (chatcontroller.getLst_chatMemberList()) {
+ for (ChatMember m : chatcontroller.getLst_chatMemberList()) {
+ if (m == null) continue;
+ if (m.getCallSignRaw() == null) continue;
+ if (!m.getCallSignRaw().equalsIgnoreCase(callRaw)) continue;
+
+ if (preferredCategory != null && preferredCategory.equals(m.getChatCategory())) {
+ return m;
+ }
+ }
+
+ // 2) Fallback: any variant with same callsignRaw
+ for (ChatMember m : chatcontroller.getLst_chatMemberList()) {
+ if (m == null) continue;
+ if (m.getCallSignRaw() == null) continue;
+ if (m.getCallSignRaw().equalsIgnoreCase(callRaw)) return m;
+ }
+ }
+
+ return null;
+ }
+
+ private void focusChatMemberAndPrepareCq(ChatMember member) {
+ if (member == null) return;
+
+ // Try selecting in table if it is visible (nice UX), but do not depend on it
+ try {
+ if (tbl_chatMember != null && tbl_chatMember.getItems() != null && tbl_chatMember.getItems().contains(member)) {
+ tbl_chatMember.getSelectionModel().select(member);
+ tbl_chatMember.scrollTo(member);
+ }
+ } catch (Exception ignored) {
+ // ignore: table not ready or filtered
+ }
+
+ // Force selection effects regardless of filters/selection state
+ selectedCallSignInfoStageChatMember = member;
+ chatcontroller.getScoreService().setSelectedChatMember(member);
+
+ selectedCallSignFurtherInfoPane.getChildren().setAll(generateFurtherInfoAbtSelectedCallsignBP(member));
+
+ txt_chatMessageUserInput.clear();
+ txt_chatMessageUserInput.setText("/cq " + member.getCallSign() + " ");
+ txt_chatMessageUserInput.requestFocus();
+ txt_chatMessageUserInput.selectEnd();
+ }
+
-// private Stage initializeCommunicationOverMyHeadVizalizationStage(ChatMember selectedChatMember) {
-// Stage stage_CommunicationOverMyHeadVizalizationStage = new Stage();
-// stage_CommunicationOverMyHeadVizalizationStage.setAlwaysOnTop(true);
-//
-// MaidenheadLocatorMapPane locatorMapPane = new MaidenheadLocatorMapPane();
-// locatorMapPane.addLocator("JO51IJ", Color.RED);
-// locatorMapPane.addLocator("JN39OC", Color.BLUE);
-// locatorMapPane.addLocator("JN49GL", Color.GREEN);
-// locatorMapPane.connectLocators("JO51IJ", "JN49GL");
-//
-// try {
-//
-//
-// BorderPane bp_CommunicationOverMyHeadVizalizationStage = new BorderPane();
-//
-// stage_CommunicationOverMyHeadVizalizationStage.setTitle("Further info on "+ selectedChatMember.getCallSign());
-//
-// stage_CommunicationOverMyHeadVizalizationStage.setScene(new Scene(locatorMapPane));
-// stage_CommunicationOverMyHeadVizalizationStage.show();
-//
-// return stage_CommunicationOverMyHeadVizalizationStage;
-// } catch (Exception exception){
-//
-// }
-// return stage_CommunicationOverMyHeadVizalizationStage;
-// }
/**
* Initializes the right click contextmenu for the chatmember-table, sets the
@@ -1709,6 +2022,7 @@ public class Kst4ContestApplication extends Application {
TableColumn qrgCol = new TableColumn("Last QRG");
qrgCol.setCellValueFactory(new Callback, ObservableValue>() {
+
@Override
public ObservableValue call(CellDataFeatures cellDataFeatures) {
StringProperty qrg = new SimpleStringProperty();
@@ -1725,7 +2039,7 @@ public class Kst4ContestApplication extends Application {
}
});
-
+ applyQrgUiFormatting(qrgCol); //fills ending 0 to format the qrgs pretty
TableColumn msgCol = new TableColumn("Message");
@@ -1934,6 +2248,8 @@ public class Kst4ContestApplication extends Application {
return qrg;
}
});
+ applyQrgUiFormatting(qrgCol); //fills ending 0 to format the qrgs pretty
+
TableColumn msgCol = new TableColumn("Message");
msgCol.setCellValueFactory(new Callback, ObservableValue>() {
@@ -2277,6 +2593,8 @@ public class Kst4ContestApplication extends Application {
return qrg;
}
});
+ applyQrgUiFormatting(qrgCol); //fills ending 0 to format the qrgs pretty
+
TableColumn msgCol = new TableColumn("Message");
msgCol.setCellValueFactory(new Callback, ObservableValue>() {
@@ -2553,30 +2871,395 @@ public class Kst4ContestApplication extends Application {
flwPane_textSnippets.getChildren().clear();
flwPane_textSnippets.getChildren()
.addAll(buttonFactory(chatcontroller.getChatPreferences().getLst_txtShortCutBtnList()));
-
-//TODO: redraw panel
-// chatMessageContextMenu = initChatMemberTableContextMenu(chatcontroller.getChatPreferences().getLst_txtSnipList()); // TODO: thats not
-// // clean, there had
-// // to be a listener
-// // triggered update
-// // method
-// chatMemberContextMenu = initChatMemberTableContextMenu(chatcontroller.getChatPreferences().getLst_txtSnipList());
-
}
});
tbl_txtShorts.getColumns().addAll(ShortCol);
tbl_txtShorts.setEditable(true);
-// tbl_txtSnips.set
-
-// ObservableList lst_textSnipList = );
tbl_txtShorts.setItems(chatcontroller.getChatPreferences().getLst_txtShortCutBtnList());
-// tbl_txtSnips.bind
return tbl_txtShorts;
} // TODO: Textsnippets table
+
+ private BorderPane initTopPriorityListPane(TableView tbl_chatMember, TextField txt_chatMessageUserInput) {
+
+ BorderPane pane = new BorderPane();
+ pane.setStyle("-fx-padding: 3;");
+
+ Label header = new Label("Top priority candidates");
+ header.getStyleClass().add("label");
+
+ ListView listView = new ListView<>();
+ listView.setItems(chatcontroller.getScoreService().getTopCandidatesFx());
+
+ listView.setCellFactory(lv -> new ListCell<>() {
+ @Override
+ protected void updateItem(kst4contest.controller.ScoreService.TopCandidate item, boolean empty) {
+ super.updateItem(item, empty);
+ if (empty || item == null) {
+ setText(null);
+ return;
+ }
+ // Keep it compact; score is mainly evaluated in FurtherInfo
+ setText(item.getDisplayCallSign() + " | score " + String.format(java.util.Locale.US, "%.0f", item.getScore()));
+ }
+ });
+
+ listView.setOnMouseClicked(evt -> {
+ if (evt.getClickCount() < 1) return;
+ kst4contest.controller.ScoreService.TopCandidate c = listView.getSelectionModel().getSelectedItem();
+ if (c == null) return;
+
+ ChatMember resolved = resolveChatMemberForTopCandidate(c);
+ if (resolved == null) return;
+
+ // Try to select in table (reuses existing selection logic)
+ if (tbl_chatMember.getItems().contains(resolved)) {
+ tbl_chatMember.getSelectionModel().select(resolved);
+ tbl_chatMember.scrollTo(resolved);
+ } else {
+ // Fallback: if filtered out, still show FurtherInfo + prepare /cq
+ selectedCallSignInfoStageChatMember = resolved;
+ chatcontroller.getScoreService().setSelectedChatMember(selectedCallSignInfoStageChatMember);
+
+ selectedCallSignFurtherInfoPane.getChildren().setAll(generateFurtherInfoAbtSelectedCallsignBP(resolved));
+ txt_chatMessageUserInput.clear();
+ txt_chatMessageUserInput.setText("/cq " + resolved.getCallSign() + " ");
+ txt_chatMessageUserInput.requestFocus();
+ txt_chatMessageUserInput.selectEnd();
+
+ // Keep ScoreService selection in sync
+ chatcontroller.getScoreService().setSelectedChatMember(resolved);
+ }
+ });
+
+ pane.setTop(header);
+ pane.setCenter(listView);
+ return pane;
+ }
+
+ private ChatMember resolveChatMemberForTopCandidate(kst4contest.controller.ScoreService.TopCandidate c) {
+
+ String callRaw = c.getCallSignRaw();
+ ChatCategory preferredCategory = c.getPreferredChatCategory();
+
+ // 1) Prefer exact (callRaw + category) match
+ synchronized (chatcontroller.getLst_chatMemberList()) {
+ for (ChatMember m : chatcontroller.getLst_chatMemberList()) {
+ if (m == null) continue;
+ if (m.getCallSignRaw() == null) continue;
+ if (!m.getCallSignRaw().equalsIgnoreCase(callRaw)) continue;
+
+ if (preferredCategory != null && preferredCategory.equals(m.getChatCategory())) {
+ return m;
+ }
+ }
+
+ // 2) Fallback: any variant with the same callsignRaw
+ for (ChatMember m : chatcontroller.getLst_chatMemberList()) {
+ if (m == null) continue;
+ if (m.getCallSignRaw() == null) continue;
+ if (m.getCallSignRaw().equalsIgnoreCase(callRaw)) return m;
+ }
+ }
+
+ return null;
+ }
+
+
+ private void updateTimelineVisuals() {
+ if (timelineView == null || chatcontroller == null) return;
+
+ if (!Platform.isFxApplicationThread()) {
+ Platform.runLater(this::updateTimelineVisuals);
+ return;
+ }
+
+ List skedsSnapshot = new ArrayList<>(chatcontroller.getActiveSkeds());
+ List candidates = buildTimelinePriorityCandidateEvents();
+
+ timelineView.updateVisuals(skedsSnapshot, candidates);
+ }
+
+ /**
+ * Build candidate markers for the timeline:
+ * - Use ScoreService TopCandidates (already sorted)
+ * - Resolve representative ChatMember (preferred category if possible)
+ * - Use "next airplane arriving minute" as time basis
+ * - Bucket by minute, keep top 1-2 per minute (config above)
+ */
+ private List buildTimelinePriorityCandidateEvents() {
+
+ if (chatcontroller.getScoreService() == null) return Collections.emptyList();
+
+ long now = System.currentTimeMillis();
+
+ // Snapshot to avoid concurrent modifications (TopCandidates list is FX observable)
+ List topSnapshot =
+ new ArrayList<>(chatcontroller.getScoreService().getTopCandidatesFx());
+
+ Map> byMinute = new HashMap<>();
+
+ for (kst4contest.controller.ScoreService.TopCandidate c : topSnapshot) {
+
+ ChatMember representative = resolveChatMemberForTopCandidate(c);
+ if (representative == null) continue;
+
+ AirPlaneReflectionInfo apInfo = representative.getAirPlaneReflectInfo();
+
+ // choose airplane by (highest potential) then (shortest time) within preview window
+ int maxMinutes = (int) (TIMELINE_PREVIEW_TIME_MS / 60_000L);
+ NextApInfo selectedAp = findBestAirplane(apInfo, maxMinutes);
+ if (selectedAp == null) continue;
+
+ long timeUntilMs = selectedAp.arrivingMinutes * 60_000L;
+ if (timeUntilMs < 0 || timeUntilMs > TIMELINE_PREVIEW_TIME_MS) continue;
+
+ int minuteBucket = selectedAp.arrivingMinutes;
+
+ byMinute.computeIfAbsent(minuteBucket, k -> new ArrayList<>())
+ .add(new TimelineCandidateTmp(c, representative, selectedAp));
+ }
+
+ List out = new ArrayList<>();
+
+ for (Map.Entry> e : byMinute.entrySet()) {
+
+ int minuteBucket = e.getKey();
+ List bucket = e.getValue();
+
+ // Highest score first
+ bucket.sort((a, b) -> Double.compare(b.top.getScore(), a.top.getScore()));
+
+
+ // 1) Pick top-N in beam -> lanes 0..1
+ List inBeam = new ArrayList<>();
+ for (TimelineCandidateTmp tmp : bucket) {
+ if (chatcontroller.isChatMemberInMyBeam(tmp.representativeMember)) {
+ inBeam.add(tmp);
+ }
+ }
+
+ // Avoid duplicates between beam and global selection
+ Set used = new HashSet<>();
+
+ int beamTake = Math.min(TIMELINE_BEAM_MARKERS_PER_MINUTE, inBeam.size());
+ for (int lane = 0; lane < beamTake; lane++) {
+
+ TimelineCandidateTmp tmp = inBeam.get(lane);
+ used.add(tmp.top.getCallSignRaw());
+
+ double az = (tmp.representativeMember.getQTFdirection() != null) ? tmp.representativeMember.getQTFdirection() : 0.0;
+ long timeUntilMs = minuteBucket * 60_000L;
+
+ String tooltip = buildTimelineCandidateTooltip(tmp, minuteBucket);
+ int potential = (tmp.nextAp != null && tmp.nextAp.plane != null) ? tmp.nextAp.plane.getPotential() : 0;
+
+ out.add(new TimelineView.CandidateEvent(
+ tmp.top.getCallSignRaw(),
+ tmp.top.getDisplayCallSign(),
+ tmp.top.getPreferredChatCategory(),
+ timeUntilMs,
+ minuteBucket,
+ lane, // lanes 0..1 = in-beam
+ az,
+ tmp.top.getScore(),
+ potential,
+ tooltip
+ ));
+ }
+
+ // 2) Pick top-N global distinct -> lanes 2..3
+ int globalAdded = 0;
+ for (TimelineCandidateTmp tmp : bucket) {
+
+ if (globalAdded >= TIMELINE_PRIORITY_MARKERS_PER_MINUTE) break;
+ if (used.contains(tmp.top.getCallSignRaw())) continue;
+
+ double az = (tmp.representativeMember.getQTFdirection() != null) ? tmp.representativeMember.getQTFdirection() : 0.0;
+ long timeUntilMs = minuteBucket * 60_000L;
+
+ String tooltip = buildTimelineCandidateTooltip(tmp, minuteBucket);
+ int potential = (tmp.nextAp != null && tmp.nextAp.plane != null) ? tmp.nextAp.plane.getPotential() : 0;
+
+ int laneIndex = TIMELINE_BEAM_MARKERS_PER_MINUTE + globalAdded; // lanes 2..3
+
+ out.add(new TimelineView.CandidateEvent(
+ tmp.top.getCallSignRaw(),
+ tmp.top.getDisplayCallSign(),
+ tmp.top.getPreferredChatCategory(),
+ timeUntilMs,
+ minuteBucket,
+ laneIndex,
+ az,
+ tmp.top.getScore(),
+ potential,
+ tooltip
+ ));
+
+ globalAdded++;
+ }
+ }
+
+ out.sort(Comparator
+ .comparingInt(TimelineView.CandidateEvent::getMinuteBucket)
+ .thenComparingInt(TimelineView.CandidateEvent::getLaneIndex));
+
+ return out;
+ }
+
+ private String buildTimelineCandidateTooltip(TimelineCandidateTmp tmp, int minuteBucket) {
+ AirPlane p = tmp.nextAp.plane;
+
+ String planeStr = "-";
+ if (p != null) {
+ planeStr = p.getApCallSign()
+ + " | " + p.getPotencialDescriptionAsWord()
+ + " | pot " + p.getPotential()
+ + " | dist " + p.getDistanceKm() + " km";
+ }
+
+ NextApInfo earliest = findEarliestAirplane(
+ tmp.representativeMember.getAirPlaneReflectInfo(),
+ (int) (TIMELINE_PREVIEW_TIME_MS / 60_000L)
+ );
+
+ String earliestStr = "";
+ if (earliest != null && earliest.plane != null) {
+ // only show if it differs from the selected/best plane minute
+ if (earliest.arrivingMinutes != minuteBucket) {
+ earliestStr = "\nearliest AP: +" + earliest.arrivingMinutes
+ + " min (pot " + earliest.plane.getPotential() + "%)";
+ }
+ }
+
+ return tmp.top.getDisplayCallSign()
+ + "\nscore: " + String.format(Locale.US, "%.0f", tmp.top.getScore())
+ + "\nbest AP: +" + minuteBucket + " min"
+ + "\nplane: " + planeStr
+ + earliestStr;
+ }
+
+ /**
+ * Select the airplane that should drive timeline/sked decisions.
+ *
+ * Rule: prefer highest potential; if tied, prefer shortest arriving time.
+ * Only considers planes within [0..maxMinutes] to avoid dropping stations completely.
+ */
+ private NextApInfo findBestAirplane(AirPlaneReflectionInfo apInfo, int maxMinutes) {
+ if (apInfo == null) return null;
+ if (apInfo.getRisingAirplanes() == null) return null;
+
+ AirPlane best = null;
+ int bestMin = Integer.MAX_VALUE;
+ int bestPot = Integer.MIN_VALUE;
+
+ for (AirPlane p : apInfo.getRisingAirplanes()) {
+ if (p == null) continue;
+
+ int m = p.getArrivingDurationMinutes();
+ if (m < 0 || m > maxMinutes) continue;
+
+ int pot = p.getPotential();
+
+ // primary: potential DESC, secondary: time ASC
+ if (best == null || pot > bestPot || (pot == bestPot && m < bestMin)) {
+ best = p;
+ bestPot = pot;
+ bestMin = m;
+ }
+ }
+
+ if (best == null) return null;
+ return new NextApInfo(best, bestMin);
+ }
+
+ /**
+ * Select the earliest airplane (used for additional tooltip info).
+ * Rule: prefer shortest arriving time; if tied, prefer higher potential.
+ */
+ private NextApInfo findEarliestAirplane(AirPlaneReflectionInfo apInfo, int maxMinutes) {
+ if (apInfo == null) return null;
+ if (apInfo.getRisingAirplanes() == null) return null;
+
+ AirPlane best = null;
+ int bestMin = Integer.MAX_VALUE;
+
+ for (AirPlane p : apInfo.getRisingAirplanes()) {
+ if (p == null) continue;
+
+ int m = p.getArrivingDurationMinutes();
+ if (m < 0 || m > maxMinutes) continue;
+
+ if (m < bestMin) {
+ bestMin = m;
+ best = p;
+ } else if (m == bestMin && best != null && p.getPotential() > best.getPotential()) {
+ best = p;
+ }
+ }
+
+ if (best == null || bestMin == Integer.MAX_VALUE) return null;
+ return new NextApInfo(best, bestMin);
+ }
+
+
+ private TableView initNotifyAtCallSignTable() {
+
+ TableView tbl_notifyTxtCallSign = new TableView();
+ tbl_notifyTxtCallSign.setTooltip(new Tooltip("Add Callsigns which you want to observe. Their Communcation will added to your PM Table"));
+
+
+
+ TableColumn callSignCol = new TableColumn("Sniff QSO of Callsign");
+ callSignCol.setCellValueFactory(new Callback, ObservableValue>() {
+
+ @Override
+ public ObservableValue call(CellDataFeatures cellDataFeatures) {
+ SimpleStringProperty callSign = new SimpleStringProperty();
+ callSign.setValue(cellDataFeatures.getValue());
+ return callSign;
+ }
+ });
+ callSignCol.setCellFactory(TextFieldTableCell.forTableColumn());
+
+ callSignCol.setOnEditCommit(new EventHandler>() {
+ @Override
+ public void handle(CellEditEvent t) {
+
+ String newValue = t.getNewValue().toUpperCase(); //its better as all callsigns in the chat are uppercase
+
+
+ t.getTableView().getItems().set(t.getTablePosition().getRow(), newValue);
+
+ if (newValue == "") { // delete lines which had been cleared
+ t.getTableView().getItems().remove(t.getTablePosition().getRow());
+ } else {
+ if (GuiUtils.isCallSignSyntax(newValue)) {
+
+ } else {
+ alertWindowEvent("Please try again with correct callsign syntax");
+ t.getTableView().getItems().remove(t.getTablePosition().getRow());
+ }
+ }
+
+ //TODO: Observe logic - add to the filters list!
+// flwPane_textSnippets.getChildren().clear();
+// flwPane_textSnippets.getChildren()
+// .addAll(buttonFactory(chatcontroller.getChatPreferences().getLst_txtShortCutBtnList()));
+ }
+ });
+
+ tbl_notifyTxtCallSign.getColumns().addAll(callSignCol);
+
+ tbl_notifyTxtCallSign.setEditable(true);
+// tbl_notifyTxtCallSign.setItems(chatcontroller.getChatPreferences().getLst_txtShortCutBtnList()); //TODO: Init aus Speicher muss noch her
+
+ return tbl_notifyTxtCallSign;
+ } // TODO: Callsign sniffer table
+
private TableView initTextSnippetsTable() {
TableView tbl_txtSnips = new TableView();
@@ -3013,6 +3696,9 @@ public class Kst4ContestApplication extends Application {
scn_ChatwindowMainScene.getStylesheets().add(ApplicationConstants.STYLECSSFILE_DEFAULT_EVENING);
clusterAndQSOMonScene.getStylesheets().add(ApplicationConstants.STYLECSSFILE_DEFAULT_EVENING);
settingsScene.getStylesheets().add(ApplicationConstants.STYLECSSFILE_DEFAULT_EVENING);
+
+ chatcontroller.getChatPreferences().setGUI_darkModeActive(true);
+
}
});
@@ -3030,6 +3716,7 @@ public class Kst4ContestApplication extends Application {
scn_ChatwindowMainScene.getStylesheets().add(ApplicationConstants.STYLECSSFILE_DEFAULT_DAYLIGHT);
clusterAndQSOMonScene.getStylesheets().add(ApplicationConstants.STYLECSSFILE_DEFAULT_DAYLIGHT);
settingsScene.getStylesheets().add(ApplicationConstants.STYLECSSFILE_DEFAULT_DAYLIGHT);
+ chatcontroller.getChatPreferences().setGUI_darkModeActive(false);
}
});
@@ -3057,7 +3744,6 @@ public class Kst4ContestApplication extends Application {
getHostServices().showDocument("https://www.paypal.com/paypalme/do5amf");
-
}
});
@@ -3125,21 +3811,178 @@ public class Kst4ContestApplication extends Application {
}
});
-// helpMenu.getItems().add(help1);
helpMenu.getItems().addAll(help2, help3, help4, menuItmDonateOV3T, menuItmDonateON4KST, help6, help8, help10);
-// helpMenu.getItems().add(help2);
-// helpMenu.getItems().add(help4);
-//
-// helpMenu.getItems().add(help10);
-
MenuBar menubar = new MenuBar();
menubar.getMenus().addAll(fileMenu, optionsMenu, windowMenu, helpMenu); // macromenu deleted
return menubar;
-
}
+
+ /*****************************************************
+ * Sked warning Initializing and functional section
+ ****************************************************/
+
+ /**
+ * Initializes the button for the Sked Warning (its an non clickable Info button)
+ */
+ private void initSkedWarnIndicatorButton() {
+ btnSkedWarnIndicator.setVisible(false);
+ btnSkedWarnIndicator.managedProperty().bind(btnSkedWarnIndicator.visibleProperty());
+
+ // "no click function" - it is just an indicator
+ btnSkedWarnIndicator.setMouseTransparent(true);
+ btnSkedWarnIndicator.setFocusTraversable(false);
+
+ btnSkedWarnIndicator.setStyle(
+ "-fx-background-color: rgba(255,0,255,0.85);" +
+ "-fx-text-fill: black;" +
+ "-fx-font-weight: bold;" +
+ "-fx-padding: 2 8 2 8;" +
+ "-fx-background-radius: 6;"
+ );
+
+ btnSkedWarnIndicator.setTooltip(tipSkedWarnIndicator);
+ }
+
+ private void maybeShowSkedWarnIndicator(String key, ThreadStateMessage msg) {
+ if (msg == null) return;
+
+ String text = msg.getRunningInformationTextDescription();
+ if (text == null || text.isBlank()) text = msg.getRunningInformation();
+ if (text == null || text.isBlank()) return;
+
+ String nick = msg.getThreadNickName() == null ? "" : msg.getThreadNickName().toLowerCase(Locale.ROOT);
+ String k = key == null ? "" : key.toLowerCase(Locale.ROOT);
+ String t = text.toLowerCase(Locale.ROOT);
+
+ boolean isSkedRelated = k.contains("sked") || nick.contains("sked") || t.contains("reminder");
+ if (!isSkedRelated) return;
+
+ final String finalText = text;
+ Platform.runLater(() -> showBlinkingSkedWarnIndicator(finalText + " SKED!"));
+ }
+
+ private void showBlinkingSkedWarnIndicator(String text) {
+ // short text for the button; full text in tooltip
+ String shown = text;
+ if (shown.length() > 38) shown = shown.substring(0, 35) + "...";
+
+ btnSkedWarnIndicator.setText(shown);
+ tipSkedWarnIndicator.setText(text);
+
+ btnSkedWarnIndicator.setVisible(true);
+ btnSkedWarnIndicator.setOpacity(1.0);
+
+ if (skedWarnBlinkTimeline != null) {
+ skedWarnBlinkTimeline.stop();
+ }
+
+ skedWarnBlinkTimeline = new Timeline(
+ new KeyFrame(Duration.ZERO, e -> btnSkedWarnIndicator.setOpacity(1.0)),
+ new KeyFrame(Duration.millis(250), e -> btnSkedWarnIndicator.setOpacity(0.25)),
+ new KeyFrame(Duration.millis(500), e -> btnSkedWarnIndicator.setOpacity(1.0))
+ );
+ skedWarnBlinkTimeline.setCycleCount(24); // 12 = 6 seconds
+ skedWarnBlinkTimeline.setOnFinished(e -> hideSkedWarnIndicator());
+ skedWarnBlinkTimeline.playFromStart();
+ }
+
+ private void hideSkedWarnIndicator() {
+ btnSkedWarnIndicator.setOpacity(1.0);
+ btnSkedWarnIndicator.setVisible(false);
+ }
+
+
+ /*****************************************************
+ * Band-Upgrade warning (after log entry) section
+ ****************************************************/
+
+ /**
+ * Initializes the button for the Band-Upgrade Hint.
+ * Non-clickable; it blinks and shows the reason (call + remaining bands).
+ */
+ private void initBandUpgradeIndicatorButton() {
+ btnBandUpgradeIndicator.setVisible(false);
+ btnBandUpgradeIndicator.managedProperty().bind(btnBandUpgradeIndicator.visibleProperty());
+
+ btnBandUpgradeIndicator.setMouseTransparent(true);
+ btnBandUpgradeIndicator.setFocusTraversable(false);
+
+ btnBandUpgradeIndicator.setStyle(
+ "-fx-background-color: rgba(255,255,0,0.85);" +
+ "-fx-text-fill: black;" +
+ "-fx-font-weight: bold;" +
+ "-fx-padding: 2 8 2 8;" +
+ "-fx-background-radius: 6;"
+ );
+
+ btnBandUpgradeIndicator.setTooltip(tipBandUpgradeIndicator);
+ }
+
+ private void maybeShowBandUpgradeIndicator(String key, ThreadStateMessage msg) {
+ if (msg == null) return;
+
+ String nick = msg.getThreadNickName() == null ? "" : msg.getThreadNickName().toLowerCase(Locale.ROOT);
+ String k = key == null ? "" : key.toLowerCase(Locale.ROOT);
+
+ boolean isBandUpgrade = k.contains("bandupgrade") || nick.contains("bandupgrade");
+ if (!isBandUpgrade) return;
+
+ String buttonText = msg.getRunningInformationTextDescription();
+ if (buttonText == null || buttonText.isBlank()) buttonText = "BAND+";
+
+ String tooltip = msg.getRunningInformation();
+ if (tooltip == null || tooltip.isBlank()) tooltip = buttonText;
+
+ final String finalButtonText = buttonText;
+ final String finalTooltip = tooltip;
+
+ Platform.runLater(() -> showBlinkingBandUpgradeIndicator(finalButtonText, finalTooltip));
+ }
+
+ private void showBlinkingBandUpgradeIndicator(String buttonText, String tooltipText) {
+
+ // short text for the button; full text in tooltip
+ String shown = buttonText;
+ if (shown.length() > 38) shown = shown.substring(0, 35) + "...";
+
+ btnBandUpgradeIndicator.setText(shown);
+ tipBandUpgradeIndicator.setText(tooltipText);
+
+ btnBandUpgradeIndicator.setVisible(true);
+ btnBandUpgradeIndicator.setOpacity(1.0);
+
+ if (bandUpgradeBlinkTimeline != null) {
+ bandUpgradeBlinkTimeline.stop();
+ }
+
+ bandUpgradeBlinkTimeline = new Timeline(
+ new KeyFrame(Duration.ZERO, e -> btnBandUpgradeIndicator.setOpacity(1.0)),
+ new KeyFrame(Duration.millis(250), e -> btnBandUpgradeIndicator.setOpacity(0.25)),
+ new KeyFrame(Duration.millis(500), e -> btnBandUpgradeIndicator.setOpacity(1.0))
+ );
+ bandUpgradeBlinkTimeline.setCycleCount(24); // ~12 seconds
+ bandUpgradeBlinkTimeline.setOnFinished(e -> hideBandUpgradeIndicator());
+ bandUpgradeBlinkTimeline.playFromStart();
+ }
+
+ private void hideBandUpgradeIndicator() {
+ btnBandUpgradeIndicator.setOpacity(1.0);
+ btnBandUpgradeIndicator.setVisible(false);
+ }
+
+/**
+ * End Band-Upgrade section
+ */
+
+
+ /**
+ * End Sked warning section
+ */
+
+
// SimpleStringProperty messageBusOfChatCtrl = messageBus;
Scene scn_ChatwindowMainScene;
Scene clusterAndQSOMonScene;
@@ -3159,18 +4002,22 @@ public class Kst4ContestApplication extends Application {
ContextMenu chatMemberContextMenu;// public due need to update it on modify
HBox chatMemberTableFilterQTFAndQRBHbox;
+ TableView tbl_chatMember = new TableView();
+
FlowPane flwPane_textSnippets;
+ FlowPane flwpne_StatusBar;
Stage clusterAndQSOMonStage;
// Stage stage_selectedCallSignInfoStage;
ChatMember selectedCallSignInfoStageChatMember;
BorderPane selectedCallSignInfoBorderPane;
-
Stage stage_updateStage;
-
Stage settingsStage;
+ Stage notify_setSnifferEntitiesStage;
+
+
ChoiceBox stn_choiceBxChatChategorySecond;
@@ -3296,8 +4143,8 @@ public class Kst4ContestApplication extends Application {
timer_buildWindowTitle.purge();
timer_buildWindowTitle.cancel();
- timer_chatMemberTableSortTimer.purge();
- timer_chatMemberTableSortTimer.cancel();
+// timer_chatMemberTableSortTimer.purge();
+// timer_chatMemberTableSortTimer.cancel();
timer_updatePrivatemessageTable.purge();
timer_updatePrivatemessageTable.cancel();
@@ -3310,6 +4157,9 @@ public class Kst4ContestApplication extends Application {
private Queue musicList = new LinkedList();
private MediaPlayer mediaPlayer ;
+
+
+
private void playCWLauncher(String playThisChars) {
char[] playThisInCW = playThisChars.toUpperCase().toCharArray();
@@ -3625,20 +4475,71 @@ public class Kst4ContestApplication extends Application {
@Override
public void start(Stage primaryStage) throws InterruptedException, IOException, URISyntaxException {
+
+
+ VBox pnl_inputAndSendButtons = new VBox(); //gets the sendtext field, send button and the timeline
+ timelineView = new TimelineView();
+ timelineView.prefWidthProperty().bind(pnl_inputAndSendButtons.widthProperty());
+ timelineView.setMinHeight(80); //min height
+ timelineView.setPrefHeight(80);
+ timelineView.setStyle("-fx-background-color: #333333; -fx-border-color: red;"); //TODO:Debug!
+ pnl_inputAndSendButtons.getChildren().add(timelineView);
+
+ timelineView.setSkedTooltipExtraTextProvider(this::buildSkedHoverInfo);
+
+ /**
+ * if user changing width
+ */
+ timelineView.widthProperty().addListener((obs, oldV, newV) -> {
+ if (newV.doubleValue() > 10) {
+ updateTimelineVisuals();
+ }
+ });
+
+ /**
+ * if user changing height
+ */
+ timelineView.heightProperty().addListener((obs, oldV, newV) -> {
+ if (newV.doubleValue() > 10) {
+ updateTimelineVisuals();
+ }
+ });
+
+
ApplicationFileUtils.copyResourceIfRequired(ApplicationConstants.APPLICATION_NAME, STYLE_DEFAULTCSSDAY_RESOURCE, STYLE_DEFAULTCSSDAY_FILE);
ApplicationFileUtils.copyResourceIfRequired(ApplicationConstants.APPLICATION_NAME, STYLE_DEFAULTCSSEVENING_RESOURCE, STYLE_DEFAULTCSSEVENING_FILE);
ChatMember ownChatMemberObject = new ChatMember();
- chatcontroller = new ChatController(ownChatMemberObject); // instantiate the Chatcontroller with the user object
+ chatcontroller = new ChatController(ownChatMemberObject, this); // instantiate the Chatcontroller with the user object
+ chatcontroller.setStatusListener(this); //callback interface for updating Thread events in visual
-// this.chatcontroller.getPlayAudioUtils().playNoiseLauncher('!');
+ // 1. Timeline an die Sked-Liste binden
+ chatcontroller.getActiveSkeds().addListener((ListChangeListener) c -> {
+ updateTimelineVisuals();
+ });
-// chatcontroller.execute(); //TODO:THAT IS THE MAIN POINT WHERE THE CHAT WILL BE STARTED --- MOVED TO CONNECT BUTTON EVENTHANDLER
+ // 1. bind table to the sked list
+ chatcontroller.getScoreService().uiPulseProperty().addListener((obs, oldVal, newVal) -> {
+ updateTimelineVisuals();
+ });
-// System.out.println(chatcontroller.getChatMemberTable().size());
+ // Keep TimelineView antenna azimuth in sync with preferences (rotator / QTF)
+// chatcontroller.getChatPreferences().getActualQTF().addListener((obs, oldV, newV) -> {
+// timelineView.setCurrentAntennaAzimuth(newV.doubleValue());
+// timelineView.updateVisuals(chatcontroller.getActiveSkeds());
+// });
+
+ // initial value
+ timelineView.setCurrentAntennaAzimuth(chatcontroller.getChatPreferences().getActualQTF().get());
+ timelineView.setBeamWidthDeg(chatcontroller.getChatPreferences().getStn_antennaBeamWidthDeg());
+
+ // Update visuals when rotor direction changes
+ chatcontroller.getChatPreferences().getActualQTF().addListener((obs, oldV, newV) -> {
+ timelineView.setCurrentAntennaAzimuth(newV.doubleValue());
+ updateTimelineVisuals();
+ });
try {
-// txt_ownqrg.setStyle("-fx-text-inner-color: #BA55D3;");
txt_ownqrgMainCategory.getStyleClass().clear();
txt_ownqrgMainCategory.getStyleClass().add("text-input");
@@ -3682,6 +4583,10 @@ public class Kst4ContestApplication extends Application {
txt_myQTF.getStyleClass().add("text-input");
txt_myQTF.getStyleClass().add("text-input-MYQRG1");
+ txt_myQTF.textProperty().bind(Bindings.createStringBinding(
+ () -> Double.toString(chatcontroller.getChatPreferences().getActualQTF().get()),
+ chatcontroller.getChatPreferences().getActualQTF()));
+
txt_myQTF.focusedProperty().addListener(new ChangeListener() {
@Override
public void changed(ObservableValue extends Boolean> arg0, Boolean oldPropertyValue,
@@ -3705,7 +4610,7 @@ public class Kst4ContestApplication extends Application {
txt_myQTF.setPrefSize(40, 0);
// txt_ownqrg.setMinSize(40, 0);
txt_myQTF.setAlignment(Pos.BASELINE_RIGHT);
- txt_myQTF.setTooltip(new Tooltip("Enter/update your actual qtf here for using path suggestions"));
+ txt_myQTF.setTooltip(new Tooltip("This is your current QTF, read out at PSTRotator"));
txt_myQTF.setFocusTraversable(false);
SplitPane mainWindowLeftSplitPane = new SplitPane();
@@ -3810,11 +4715,19 @@ public class Kst4ContestApplication extends Application {
// scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
MenuBar mainScreenMenuBar = initMenuBar();
- bPaneChatWindow.setTop(mainScreenMenuBar);
+// HPane hbxNorthForStatusBar = new HBox();
+ flwpne_StatusBar = new FlowPane();
+
+ flwpne_StatusBar.getChildren().add(mainScreenMenuBar);
+ bPaneChatWindow.setTop(flwpne_StatusBar);
+
+ initSkedWarnIndicatorButton();
+ flwpne_StatusBar.getChildren().add(btnSkedWarnIndicator);
+
+ initBandUpgradeIndicatorButton();
+ flwpne_StatusBar.getChildren().add(btnBandUpgradeIndicator);
-// bPaneChatWindow.setLeft(new Label("This will be at the left"));
-// bPaneChatWindow.setRight(scrollabeUserListPanel);
SplitPane messageSectionSplitpane = new SplitPane();
messageSectionSplitpane.setOrientation(Orientation.VERTICAL);
@@ -3823,8 +4736,8 @@ public class Kst4ContestApplication extends Application {
// FlowPane textInputFlowPane = new FlowPane();
- sendButton = new Button("send");
- sendButton.setMinSize(60, 0);
+ sendButton = new Button("TX");
+ sendButton.setMinSize(20, 0);
sendButton.setOnAction(new EventHandler() {
@Override
public void handle(ActionEvent event) {
@@ -3855,6 +4768,11 @@ public class Kst4ContestApplication extends Application {
sendMe.setChatCategory(sendMeInThisCat); //new in 1.26, answer in channel of the selected member
sendMe.setMessageText(txt_chatMessageUserInput.getText());
+
+ // If operator sends "/cq CALL ..." => arm pending ping metrics for reply-time / no-reply tracking
+ chatcontroller.getStationMetricsService().tryRecordOutboundCq(sendMe.getMessageText(), System.currentTimeMillis());
+ chatcontroller.getScoreService().requestRecompute("outbound-tx");
+
sendMe.setMessageDirectedToServer(false);
chatcontroller.getMessageTXBus().add(sendMe); //move the message to the tx queue
@@ -3868,7 +4786,7 @@ public class Kst4ContestApplication extends Application {
// sendButton.setMnemonicParsing(true);
Button btn_clear = new Button("clear");
- btn_clear.setMinSize(60, 0);
+ btn_clear.setMinSize(20, 0);
btn_clear.setOnAction(new EventHandler() {
@Override
public void handle(ActionEvent event) {
@@ -4051,6 +4969,7 @@ public class Kst4ContestApplication extends Application {
}
});
+
final Separator sepVert1 = new Separator();
sepVert1.setOrientation(Orientation.VERTICAL);
sepVert1.setValignment(VPos.CENTER);
@@ -4058,14 +4977,14 @@ public class Kst4ContestApplication extends Application {
sepVert1.setPrefWidth(30);
txt_ownqrgMainCategory.setText("MYQRG");
- txt_ownqrgMainCategory.setPrefSize(80, 0);
- txt_ownqrgMainCategory.setAlignment(Pos.BASELINE_RIGHT);
+ txt_ownqrgMainCategory.setPrefSize(70, 0);
+ txt_ownqrgMainCategory.setAlignment(Pos.BASELINE_LEFT);
txt_ownqrgMainCategory.setFocusTraversable(false);
// txt_ownqrgSecondCategory.setText("SECONDQRG");
txt_ownqrgSecondCategory.setText(chatcontroller.getChatPreferences().getMYQRGSecondCat().getValue());
- txt_ownqrgSecondCategory.setPrefSize(140, 0);
- txt_ownqrgSecondCategory.setAlignment(Pos.BASELINE_RIGHT);
+ txt_ownqrgSecondCategory.setPrefSize(70, 0);
+ txt_ownqrgSecondCategory.setAlignment(Pos.BASELINE_CENTER);
txt_ownqrgSecondCategory.setFocusTraversable(false);
txt_ownqrgSecondCategory.setTooltip(new Tooltip("Enter frequency for second chat-category here by hand! "));
@@ -4115,23 +5034,21 @@ public class Kst4ContestApplication extends Application {
}
}, new Date(), 5000);
+
+
+ textInputFlowPane.setSpacing(6);
+ textInputFlowPane.setAlignment(Pos.CENTER_LEFT);
+
textInputFlowPane.getChildren().addAll(txt_chatMessageUserInput, sendButton, btn_clear, sepVert1,
txt_ownqrgMainCategory, txt_ownqrgSecondCategory, txt_myQTF);
-// HBox hbx_textSnippets = new HBox();
flwPane_textSnippets = new FlowPane();
flwPane_textSnippets.getChildren()
.addAll(buttonFactory(this.chatcontroller.getChatPreferences().getLst_txtShortCutBtnList()));
-// hbx_textSnippets.getChildren().add(flwPane_textSnippets);
-// hbx_textSnippets.set
-
TableView privateMessageTable = initChatprivateMSGTable();
-//
-// ContextMenu chatMessageContextMenu = initChatMemberTableContextMenu( old mechanic
-// this.chatcontroller.getChatPreferences().getTextSnippets());
chatMessageContextMenu = initChatMemberTableContextMenu(
this.chatcontroller.getChatPreferences().getLst_txtSnipList()); // new mechanic
@@ -4186,15 +5103,23 @@ public class Kst4ContestApplication extends Application {
} else {
+
txt_chatMessageUserInput.clear();
txt_chatMessageUserInput.setText("/cq "
+ selectedChatMemberPrivateChat.getList().get(0).getSender().getCallSign() + " ");
txt_chatMessageUserInput.requestFocus();
txt_chatMessageUserInput.selectEnd();
+
+ focusChatMemberAndPrepareCq(selectedChatMemberPrivateChat.getList().get(0).getSender());
+
+
try {
selectedCallSignFurtherInfoPane.getChildren().clear();
selectedCallSignInfoStageChatMember = selectedChatMemberPrivateChat.getList().get(0).getSender();
+ chatcontroller.getScoreService().setSelectedChatMember(selectedCallSignInfoStageChatMember);
+
+ chatcontroller.getScoreService().setSelectedChatMember(selectedCallSignInfoStageChatMember); //important after selection change
selectedCallSignFurtherInfoPane.getChildren().add(generateFurtherInfoAbtSelectedCallsignBP(selectedCallSignInfoStageChatMember));
txt_chatMessageUserInput.requestFocus();
txt_chatMessageUserInput.selectEnd();
@@ -4256,12 +5181,24 @@ public class Kst4ContestApplication extends Application {
+ selectedChatMemberGeneralChat.getList().get(0).getSender().getCallSign() + " ");
txt_chatMessageUserInput.requestFocus();
txt_chatMessageUserInput.selectEnd();
- System.out.println("privChat selected ChatMember: "
+ System.out.println("cq chat selected ChatMember: "
+ selectedChatMemberGeneralChat.getList().get(0).getSender());
+
+ try {
+ //scroll the chatmembers table to the entry - try because of sender could be null
+ focusChatMemberAndPrepareCq(selectedChatMemberGeneralChat.getList().get(0).getSender());
+
+ } catch (Exception exception) {
+ System.out.println("KST4CApp, <<>>>: message sender is not in the userlist any more!");
+ }
+
try {
selectedCallSignFurtherInfoPane.getChildren().clear();
selectedCallSignInfoStageChatMember = selectedChatMemberGeneralChat.getList().get(0).getSender();
+ chatcontroller.getScoreService().setSelectedChatMember(selectedCallSignInfoStageChatMember);
+
+ chatcontroller.getScoreService().setSelectedChatMember(selectedCallSignInfoStageChatMember); //important after selection change
selectedCallSignFurtherInfoPane.getChildren().add(generateFurtherInfoAbtSelectedCallsignBP(selectedCallSignInfoStageChatMember));
txt_chatMessageUserInput.requestFocus();
txt_chatMessageUserInput.selectEnd();
@@ -4276,7 +5213,7 @@ public class Kst4ContestApplication extends Application {
- messageSectionSplitpane.getItems().addAll(privateMessageTable, flwPane_textSnippets, textInputFlowPane,
+ messageSectionSplitpane.getItems().addAll(privateMessageTable, flwPane_textSnippets,pnl_inputAndSendButtons, textInputFlowPane,
tbl_generalMessageTable);
messageSectionSplitpane.setDividerPositions(chatcontroller.getChatPreferences().getGUImessageSectionSplitpane_dividerposition());
@@ -4302,9 +5239,20 @@ public class Kst4ContestApplication extends Application {
bPaneChatWindow.setCenter(mainWindowLeftSplitPane);
- TableView tbl_chatMember = new TableView();
+
tbl_chatMember = initChatMemberTable();
+ timelineView.setOnCandidateClicked(ev -> {
+ if (ev == null) return;
+
+ ChatMember resolved = resolveChatMemberForCallRawAndCategory(ev.getCallSignRaw(), ev.getPreferredChatCategory());
+ if (resolved == null) return;
+
+ // Always prepare /cq + FurtherInfo (even if filtered out in table)
+ focusChatMemberAndPrepareCq(resolved);
+ });
+
+
TableViewSelectionModel selectionModelChatMember = tbl_chatMember.getSelectionModel();
selectionModelChatMember.setSelectionMode(SelectionMode.SINGLE);
@@ -4325,6 +5273,7 @@ public class Kst4ContestApplication extends Application {
selectedCallSignInfoStageChatMember = selectionModelChatMember.getSelectedItems().get(0); //TODO: temp test 1.26: get selected chatmember out of ist
+ chatcontroller.getScoreService().setSelectedChatMember(selectedCallSignInfoStageChatMember); //important after selection cchange
// selectedCallSignInfoStageChatMember = chatcontroller.getLst_chatMemberList()
// .get(chatcontroller.checkListForChatMemberIndexByCallSign(
@@ -4388,7 +5337,7 @@ public class Kst4ContestApplication extends Application {
SplitPane mainWindowRightSplitPane = new SplitPane();
mainWindowRightSplitPane.setOrientation(Orientation.VERTICAL);
- mainWindowRightSplitPane.setDividerPositions(chatcontroller.getChatPreferences().getGUImainWindowRightSplitPane_dividerposition());
+// mainWindowRightSplitPane.setDividerPositions(chatcontroller.getChatPreferences().getGUImainWindowRightSplitPane_dividerposition());
BorderPane chatMemberTableBorderPane = new BorderPane();
chatMemberTableBorderPane.setCenter(tbl_chatMember);
@@ -4475,6 +5424,7 @@ public class Kst4ContestApplication extends Application {
if (!newValue.matches("\\d*")) {
chatMemberTableFilterQtfTF.setText(newValue.replaceAll("[^\\d]", ""));
}
+ System.out.println("new default QTF: " + newValue);
chatMemberTableFilterQtfEnableChkbx.setSelected(false);
chatMemberTableFilterQtfEnableChkbx.setSelected(true);
}
@@ -4517,7 +5467,22 @@ public class Kst4ContestApplication extends Application {
- Button qtfNorth = new Button("N");
+ ToggleGroup tglGrpQTF = new ToggleGroup(); //Tooglegroup for the qtf filter options
+
+ tglGrpQTF.selectedToggleProperty().addListener(new ChangeListener() {
+ @Override
+ public void changed(ObservableValue extends Toggle> observableValue, Toggle toggle, Toggle t1) {
+ if (t1 == null) {
+ chatMemberTableFilterQtfEnableChkbx.setSelected(false);
+ } else {
+ chatMemberTableFilterQtfEnableChkbx.setSelected(true);
+ }
+ }
+ });
+
+// Button qtfNorth = new Button("N");
+ ToggleButton qtfNorth = new ToggleButton("N");
+ qtfNorth.setToggleGroup(tglGrpQTF);
btnQtfButtonsAvl[0] = qtfNorth;
qtfNorth.setOnAction(new EventHandler() {
@@ -4529,7 +5494,8 @@ public class Kst4ContestApplication extends Application {
});
- Button qtfNorthEast = new Button("NE");
+ ToggleButton qtfNorthEast = new ToggleButton("NE");
+ qtfNorthEast.setToggleGroup(tglGrpQTF);
btnQtfButtonsAvl[1] = qtfNorthEast;
qtfNorthEast.setOnAction(new EventHandler() {
@Override
@@ -4539,7 +5505,8 @@ public class Kst4ContestApplication extends Application {
}
});
- Button qtfEast = new Button("E");
+ ToggleButton qtfEast = new ToggleButton("E");
+ qtfEast.setToggleGroup(tglGrpQTF);
btnQtfButtonsAvl[2] = qtfEast;
qtfEast.setOnAction(new EventHandler() {
@Override
@@ -4549,7 +5516,8 @@ public class Kst4ContestApplication extends Application {
}
});
- Button qtfSouthEast = new Button("SE");
+ ToggleButton qtfSouthEast = new ToggleButton("SE");
+ qtfSouthEast.setToggleGroup(tglGrpQTF);
btnQtfButtonsAvl[3] = qtfSouthEast;
qtfSouthEast.setOnAction(new EventHandler() {
@Override
@@ -4558,7 +5526,9 @@ public class Kst4ContestApplication extends Application {
// uiHelper_recolorQtfDirectionButtonsExceptThisOne(qtfSouthEast);
}
});
- Button qtfSouth = new Button("S");
+
+ ToggleButton qtfSouth = new ToggleButton("S");
+ qtfSouth.setToggleGroup(tglGrpQTF);
btnQtfButtonsAvl[4] = qtfSouth;
qtfSouth.setOnAction(new EventHandler() {
@Override
@@ -4568,7 +5538,8 @@ public class Kst4ContestApplication extends Application {
}
});
- Button qtfSouthWest = new Button("SW");
+ ToggleButton qtfSouthWest = new ToggleButton("SW");
+ qtfSouthWest.setToggleGroup(tglGrpQTF);
btnQtfButtonsAvl[5] = qtfSouthWest;
qtfSouthWest.setOnAction(new EventHandler() {
@Override
@@ -4577,7 +5548,8 @@ public class Kst4ContestApplication extends Application {
// uiHelper_recolorQtfDirectionButtonsExceptThisOne(qtfSouthWest);
}
});
- Button qtfWest = new Button("W");
+ ToggleButton qtfWest = new ToggleButton("W");
+ qtfWest.setToggleGroup(tglGrpQTF);
btnQtfButtonsAvl[6] = qtfWest;
qtfWest.setOnAction(new EventHandler() {
@Override
@@ -4587,8 +5559,10 @@ public class Kst4ContestApplication extends Application {
}
});
- Button qtfNorthWest = new Button("NW");
+ ToggleButton qtfNorthWest = new ToggleButton("NW");
+ qtfNorthWest.setToggleGroup(tglGrpQTF);
btnQtfButtonsAvl[7] = qtfNorthWest;
+ qtfNorthWest.setToggleGroup(tglGrpQTF);
qtfNorthWest.setOnAction(new EventHandler() {
@Override
public void handle(ActionEvent actionEvent) {
@@ -4598,7 +5572,6 @@ public class Kst4ContestApplication extends Application {
});
-
// chatMemberTableFilterQTFHBox.setSpacing(5);
chatMemberTableFilterQTFHBox.getChildren().addAll(chatMemberTableFilterQtfTF, new Label("deg +/- " + chatcontroller.getChatPreferences().getStn_antennaBeamWidthDeg() + ""), qtfNorth, qtfNorthEast, qtfEast, qtfSouthEast, qtfSouth, qtfSouthWest, qtfWest, qtfNorthWest);
chatMemberTableFilterQTFAndQRBHbox.getChildren().add(chatMemberTableFilterQTFHBox);
@@ -4618,8 +5591,6 @@ public class Kst4ContestApplication extends Application {
chatcontroller.getLst_chatMemberListFiltered().predicateProperty().bind(Bindings.createObjectBinding(() -> chatcontroller.getLst_chatMemberListFilterPredicates().stream().reduce(x -> true, Predicate::and), chatcontroller.getLst_chatMemberListFilterPredicates()));
-
-
TextField chatMemberTableFilterTextField = new TextField("Find...");
chatMemberTableFilterTextField.setFocusTraversable(false);
chatMemberTableFilterTextField.focusedProperty().addListener(new ChangeListener() {
@@ -4958,6 +5929,9 @@ public class Kst4ContestApplication extends Application {
mainWindowRightSplitPane.getItems().add(chatMemberTableBorderPane);
+ BorderPane topPriorityListPane = initTopPriorityListPane(tbl_chatMember, txt_chatMessageUserInput);
+ mainWindowRightSplitPane.getItems().add(topPriorityListPane);//adds priority list panel
+
mainWindowLeftSplitPane.getItems().addAll(messageSectionSplitpane, mainWindowRightSplitPane);
mainWindowLeftSplitPane.setDividerPositions(chatcontroller.getChatPreferences().getGUImainWindowLeftSplitPane_dividerposition());
@@ -4979,28 +5953,15 @@ public class Kst4ContestApplication extends Application {
}
-/**
- * initializing the furter infos of a callsign part of the right splitpane
- */
-
-
-
-
-
-
-// selectedCallSignFurtherInfoPane.getChildren().add(generateFurtherInfoAbtSelectedCallsignBP(selectedCallSignInfoStageChatMember));
-
-
-// selectedCallSignInfoPane.getChildren().add(selectedCallSignInfoBorderPane);
-
-
-
- /**
- * end of initializing the furter infos of a callsign part of the right splitpane
- */
mainWindowRightSplitPane.getItems().add(selectedCallSignFurtherInfoPane);
+ // Ensure the stored divider array matches the current UI layout (2 dividers = 3 items).
+ chatcontroller.getChatPreferences().ensureMainWindowRightSplitPaneDividerPositions(mainWindowRightSplitPane.getDividers().size());
+
+ // Apply persisted divider positions AFTER all items exist.
+ mainWindowRightSplitPane.setDividerPositions(chatcontroller.getChatPreferences().getGUImainWindowRightSplitPane_dividerposition());
+
//first initialize how much divider positions we need...
// chatcontroller.getChatPreferences().setGUImainWindowRightSplitPane_dividerposition(new double[mainWindowRightSplitPane.getDividers().size()]);
@@ -5013,7 +5974,19 @@ public class Kst4ContestApplication extends Application {
@Override
public void changed(ObservableValue extends Number> observableValue, Number oldDividerPos, Number newDividerPosition) {
System.out.println("<<<<<<<<<<<<<<<<<<<>>>>>> devider mainwindowRIGHTsplitpane " + mainWindowRightSplitPane.getDividers().indexOf(divider) + " position change, new position: " + newDividerPosition + " // size dev: " + mainWindowRightSplitPane.getDividers().size());
- chatcontroller.getChatPreferences().getGUImainWindowRightSplitPane_dividerposition()[mainWindowRightSplitPane.getDividers().indexOf(divider)] = newDividerPosition.doubleValue();
+// chatcontroller.getChatPreferences().getGUImainWindowRightSplitPane_dividerposition()[mainWindowRightSplitPane.getDividers().indexOf(divider)] = newDividerPosition.doubleValue();
+
+ int dividerIndex = mainWindowRightSplitPane.getDividers().indexOf(divider);
+ double[] storedPositions = chatcontroller.getChatPreferences().getGUImainWindowRightSplitPane_dividerposition();
+
+ if (dividerIndex >= 0 && dividerIndex < storedPositions.length) {
+ storedPositions[dividerIndex] = newDividerPosition.doubleValue();
+ } else {
+ // Avoid crashes if preferences are older than the current UI layout.
+ System.out.println("WARN: cannot store mainWindowRightSplitPane divider position: index="
+ + dividerIndex + ", storedLen=" + storedPositions.length + ", dividerCount="
+ + mainWindowRightSplitPane.getDividers().size());
+ }
}
});
@@ -5050,10 +6023,6 @@ public class Kst4ContestApplication extends Application {
pnl_directedMSGWin.getItems().addAll(initDXClusterTable(), initChatToOtherMSGTable());
-
- //first initialize how much divider positions we need...
-// chatcontroller.getChatPreferences().setGUIpnl_directedMSGWin_dividerpositionDefault(new double[pnl_directedMSGWin.getDividers().size()]);
-
/**
* here will follow the Splitpane divider listener to save the user made UI changes, should been made at the very end of all splitpane operations
*/
@@ -5088,8 +6057,6 @@ public class Kst4ContestApplication extends Application {
});
clusterAndQSOMonStage.setScene(clusterAndQSOMonScene);
-
-
clusterAndQSOMonStage.show();
/**
@@ -5101,16 +6068,11 @@ public class Kst4ContestApplication extends Application {
* Window updates
*/
stage_updateStage = new Stage();
-// clusterAndQSOMonStage.initStyle(StageStyle.UTILITY);
- stage_updateStage.setTitle("Update information");
-// SplitPane pnl_directedMSGWin = new SplitPane();
-// apnl_directedMSGWin.setOrientation(Orientation.VERTICAL);
-// pnl_directedMSGWin.getItems().addAll(initDXClusterTable(), initChatToOtherMSGTable());
+ stage_updateStage.setTitle("Update information");
try {
-
stage_updateStage.setAlwaysOnTop(true);
Label lblUpdateInfo = new Label("Update aviable!");
@@ -5209,7 +6171,7 @@ public class Kst4ContestApplication extends Application {
stage_updateStage.show();
} else {
- stage_updateStage.show();
+// stage_updateStage.show(); only for debugging check
//nothing to do
}
@@ -5512,14 +6474,24 @@ public class Kst4ContestApplication extends Application {
txtFldstn_qtfDefault.setText(newString.replaceAll("[^\\d]", ""));
}
- System.out.println("[Main.java, Info]: Setted the QRB: " + txtFldstn_qtfDefault.getText());
- chatcontroller.getChatPreferences().setStn_antennaBeamWidthDeg(Double.parseDouble(txtFldstn_qtfDefault.getText()));
+ System.out.println("[Main.java, Info]: Setted the QTF: " + txtFldstn_qtfDefault.getText());
+ chatcontroller.getChatPreferences().setStn_qtfDefault(Double.parseDouble(txtFldstn_qtfDefault.getText()));
// chatMemberTableFilterQTFHBox.getChildren().addAll(chatMemberTableFilterQtfTF, new Label("deg, " + chatcontroller.getChatPreferences().getStn_antennaBeamWidthDeg() + " beamwidth"), qtfNorth, qtfNorthEast, qtfEast, qtfSouthEast, qtfSouth, qtfSouthWest, qtfWest, qtfNorthWest);
// chatMemberTableFilterQTFHBox.getChildren().addAll(chatMemberTableFilterQtfTF, new Label("deg, " + chatcontroller.getChatPreferences().getStn_antennaBeamWidthDeg() + " beamwidth"), qtfNorth, qtfNorthEast, qtfEast, qtfSouthEast, qtfSouth, qtfSouthWest, qtfWest, qtfNorthWest);
}
});
+ Label lbl_station_pstRotatorEnabled = new Label("Enable PSTRotator interface (auto QTF):");
+ CheckBox chkBx_station_pstRotatorEnabled = new CheckBox();
+ chkBx_station_pstRotatorEnabled.setSelected(chatcontroller.getChatPreferences().isStn_pstRotatorEnabled());
+ chkBx_station_pstRotatorEnabled.setTooltip(new Tooltip(
+ "If disabled: no PSTRotator connection is started and antenna direction is ignored in priority scoring."
+ ));
+ chkBx_station_pstRotatorEnabled.selectedProperty().addListener((obs, oldV, newV) ->
+ chatcontroller.getChatPreferences().setStn_pstRotatorEnabled(newV)
+ );
+
grdPnlStation.add(lblCallSign, 0, 0);
grdPnlStation.add(txtFldCallSign, 1, 0);
@@ -5537,10 +6509,37 @@ public class Kst4ContestApplication extends Application {
grdPnlStation.add(txtFldstn_maxQRBDefault, 1, 6);
grdPnlStation.add(new Label("Default filter QTF:"), 0, 7);
grdPnlStation.add(txtFldstn_qtfDefault, 1, 7);
+ grdPnlStation.add(lbl_station_pstRotatorEnabled, 0, 8);
+ grdPnlStation.add(chkBx_station_pstRotatorEnabled, 1, 8);
VBox vbxStation = new VBox();
vbxStation.setPadding(new Insets(10, 10, 10, 10));
- vbxStation.getChildren().addAll(
+
+ GridPane grdPanelServerHostName = new GridPane();
+
+ TextField stn_txtServerDNS = new TextField(this.chatcontroller.getChatPreferences().getStn_on4kstServersDns());
+ stn_txtServerDNS.focusedProperty().addListener(new ChangeListener() {
+ @Override
+ public void changed(ObservableValue extends Boolean> observableValue, Boolean aBoolean, Boolean t1) {
+
+ System.out.println("[Main.java, Info]: Set the Server DNS property by hand to: "
+ + stn_txtServerDNS.getText());
+ chatcontroller.getChatPreferences().setStn_on4kstServersDns(stn_txtServerDNS.getText());
+ }
+ });
+
+
+ grdPanelServerHostName.add(new Label("ON4KST Server [www.on4kst.org]: "), 0,1);
+ grdPanelServerHostName.add(stn_txtServerDNS, 1,1);
+
+ TextField stn_txtServerPort = new TextField(this.chatcontroller.getChatPreferences().getStn_on4kstServersPort()+"");
+
+ grdPanelServerHostName.add(new Label(" Port [23001]: "), 2,1);
+ grdPanelServerHostName.add(stn_txtServerPort, 3,1);
+
+ vbxStation.getChildren().addAll(grdPanelServerHostName);
+
+ vbxStation.getChildren().addAll(
generateLabeledSeparator(100, "Set your Login Credentials and Station Parameters here"), grdPnlStation);
vbxStation.getChildren().addAll(generateLabeledSeparator(50,
"! ! ! ! Don´t forget to reset the worked stations information before starting a new contest ! ! ! !"));
@@ -5774,10 +6773,72 @@ public class Kst4ContestApplication extends Application {
}
});
-
-
-
-
+
+
+ grdPnlLog.add(generateLabeledSeparator(100, "Win-Test Network-Listener"), 0, 6, 2, 1);
+
+ Label lblEnableWintest = new Label("Receive Win-Test network based UDP log messages");
+ CheckBox chkBxEnableWintestUDPReceiver = new CheckBox();
+ chkBxEnableWintestUDPReceiver.setSelected(
+ this.chatcontroller.getChatPreferences().isLogsynch_wintestNetworkListenerEnabled()
+ );
+
+ Label lblUDPByWintest = new Label("UDP-Port for Win-Test listener (default is 9871)");
+ TextField txtFldUDPPortforWintest = new TextField(
+ this.chatcontroller.getChatPreferences().getLogsynch_wintestNetworkPort() + ""
+ );
+
+ txtFldUDPPortforWintest.focusedProperty().addListener(new ChangeListener() {
+ @Override
+ public void changed(ObservableValue extends Boolean> arg0, Boolean oldPropertyValue, Boolean newPropertyValue) {
+ if (newPropertyValue) {
+ // focus gained -> nichts
+ } else {
+ if (GuiUtils.isNumeric(txtFldUDPPortforWintest.getText())) {
+
+ chatcontroller.getChatPreferences()
+ .setLogsynch_wintestNetworkPort(Integer.parseInt(txtFldUDPPortforWintest.getText()));
+
+ // Wenn enabled: Listener auf neuem Port neu starten
+ if (chatcontroller.getChatPreferences().isLogsynch_wintestNetworkListenerEnabled()) {
+ chatcontroller.restartWintestUdpListenerIfEnabled();
+ }
+
+ System.out.println("[Main.java, Info]: set Win-Test listener port to: "
+ + txtFldUDPPortforWintest.getText());
+
+ } else {
+ txtFldUDPPortforWintest.setText(txtFldUDPPortforWintest.getText() + " is an invalid Port");
+ }
+ }
+ }
+ });
+
+
+ chkBxEnableWintestUDPReceiver.selectedProperty().addListener(new ChangeListener() {
+ @Override
+ public void changed(ObservableValue extends Boolean> observable, Boolean oldValue, Boolean newValue) {
+
+ chatcontroller.getChatPreferences()
+ .setLogsynch_wintestNetworkListenerEnabled(chkBxEnableWintestUDPReceiver.isSelected());
+
+ txtFldUDPPortforWintest.setDisable(!chkBxEnableWintestUDPReceiver.isSelected());
+
+ if (chkBxEnableWintestUDPReceiver.isSelected()) {
+ chatcontroller.restartWintestUdpListenerIfEnabled();
+ } else {
+ chatcontroller.stopWintestUdpListener();
+ }
+
+ System.out.println("[Main.java, Info]: Win-Test UDP listener enabled: "
+ + chatcontroller.getChatPreferences().isLogsynch_wintestNetworkListenerEnabled());
+ }
+ });
+
+
+
+ txtFldUDPPortforWintest.setFocusTraversable(false);
+ txtFldUDPPortforWintest.setDisable(!chkBxEnableWintestUDPReceiver.isSelected());
// grdPnlLog.add(new Label("Settings for the file interpreter, which can interprete ASCII Callsigns out of all kinds of files by Patternmatching"), 0,0,1,1);
grdPnlLog.add(generateLabeledSeparator(100, "File polling for worked callsigns"), 0, 0, 2, 1);
@@ -5794,6 +6855,10 @@ public class Kst4ContestApplication extends Application {
// grdPnlLog.add(lblUDPbyUCXLogBackupFilePathAndNameTitle, 0, 6); removed due to db usage now
// grdPnlLog.add(lblUDPbyUCXLogBackupFilePathAndName, 1, 6); removed due to db usage now
// grdPnlLog.add(new Button("Change..."), 2, 6); removed due to db usage now
+ grdPnlLog.add(lblEnableWintest, 0, 7);
+ grdPnlLog.add(chkBxEnableWintestUDPReceiver, 1, 7);
+ grdPnlLog.add(lblUDPByWintest, 0, 8);
+ grdPnlLog.add(txtFldUDPPortforWintest, 1, 8);
VBox vbxLog = new VBox();
vbxLog.setPadding(new Insets(10, 10, 10, 10));
@@ -5811,6 +6876,17 @@ public class Kst4ContestApplication extends Application {
Label lblEnableTRXMsgbyUCX = new Label("Receive UCXLog network based UDP trx messages at Port 12060");
CheckBox chkBxEnableTRXMsgbyUCX = new CheckBox();
+ CheckBox chkBxEnableXVTRUsage = new CheckBox();
+
+ Label lblXVTRRFQrg = new Label("XVTR RF QRG in kHz, e.g. \"144000\" for 144 MHz), default = 144000");
+ lblXVTRRFQrg.setTooltip(new Tooltip("Where will your xvtr send?"));
+
+ Label lblTRXIFQrg = new Label("TRX IF QRG in kHz, e.g. \"28000\" for 28 MHz), default = 28000");
+ lblXVTRRFQrg.setTooltip(new Tooltip("Where will your TRX IF be?"));
+
+// Label lblRedultingLoQRG = new Label("The value of " + asd + " will be added to the readed QRG of your TRX to show correct QRG");
+
+
chkBxEnableTRXMsgbyUCX
.setSelected(this.chatcontroller.getChatPreferences().isTrxSynch_ucxLogUDPListenerEnabled());
@@ -6180,14 +7256,24 @@ public class Kst4ContestApplication extends Application {
@Override
public void handle(ActionEvent event) {
- ChatMember dummy = new ChatMember();
- dummy.setFrequency(new SimpleStringProperty("144300"));
- dummy.setQra("Congrats, you donated $100");
- dummy.setCallSign("DO5AMF");
+// ChatMember dummyCopy = new ChatMember();
+// dummyCopy.setCallSign(selectedCallSignInfoStageChatMember.getCallSign());
+// dummyCopy.setFrequency(new SimpleStringProperty("144300"));
+// dummyCopy.setQra(selectedCallSignInfoStageChatMember.getQra() + " AP: " +
+// selectedCallSignInfoStageChatMember.getAirPlaneReflectInfo().getRisingAirplanes().get(0).getPotential() + "%, " +
+// selectedCallSignInfoStageChatMember.getAirPlaneReflectInfo().getRisingAirplanes().get(0).getArrivingDurationMinutes() + "min" +
+// ", " +
+// selectedCallSignInfoStageChatMember.getAirPlaneReflectInfo().getRisingAirplanes().get(1).getPotential() + "%, " +
+// selectedCallSignInfoStageChatMember.getAirPlaneReflectInfo().getRisingAirplanes().get(1).getArrivingDurationMinutes() + "min");
+
+ ChatMember dummyCopy = new ChatMember();
+ dummyCopy.setFrequency(new SimpleStringProperty("144300"));
+ dummyCopy.setQra("Congrats, you donated $100");
+ dummyCopy.setCallSign("DO5AMF");
try {
- chatcontroller.getDxClusterServer().broadcastSingleDXClusterEntryToLoggers(dummy);
+ chatcontroller.getDxClusterServer().broadcastSingleDXClusterEntryToLoggers(dummyCopy);
// dummy = new ChatMember();
// dummy.setFrequency(new SimpleStringProperty("144366"));
@@ -6305,7 +7391,51 @@ public class Kst4ContestApplication extends Application {
grdPnlNotify.add(lblNotifyDXClusterServerTriggerOnEveryQRGDetect, 0, 12);
grdPnlNotify.add(chkBxNotifyDXClusterServerTriggerOnEveryQRGDetect, 1, 12);
+ grdPnlNotify.add(generateLabeledSeparator(100, "Band-upgrade hint (after log entry)"), 0, 13, 2, 1);
+ Label lblNotifyBandUpgradeHint = new Label("Blink + sound if logged station is still QRV on other unworked enabled band(s)");
+ CheckBox chkBxNotifyBandUpgradeHint = new CheckBox();
+ chkBxNotifyBandUpgradeHint.setSelected(chatcontroller.getChatPreferences().isNotify_bandUpgradeHintOnLogEnabled());
+ chkBxNotifyBandUpgradeHint.selectedProperty().addListener((obs, o, n) ->
+ chatcontroller.getChatPreferences().setNotify_bandUpgradeHintOnLogEnabled(n)
+ );
+
+ Label lblNotifyBandUpgradeBoost = new Label("Priority boost for band-upgrade cases (better visibility in toplists)");
+ CheckBox chkBxNotifyBandUpgradeBoost = new CheckBox();
+ chkBxNotifyBandUpgradeBoost.setSelected(chatcontroller.getChatPreferences().isNotify_bandUpgradePriorityBoostEnabled());
+ chkBxNotifyBandUpgradeBoost.selectedProperty().addListener((obs, o, n) ->
+ chatcontroller.getChatPreferences().setNotify_bandUpgradePriorityBoostEnabled(n)
+ );
+
+ grdPnlNotify.add(lblNotifyBandUpgradeHint, 0, 14);
+ grdPnlNotify.add(chkBxNotifyBandUpgradeHint, 1, 14);
+
+ grdPnlNotify.add(lblNotifyBandUpgradeBoost, 0, 15);
+ grdPnlNotify.add(chkBxNotifyBandUpgradeBoost, 1, 15);
+
+
+// grdPnlNotify.add(generateLabeledSeparator(100, "QSO Sniffing tool"), 0, 14, 2, 1);
+ grdPnlNotify.add(generateLabeledSeparator(100, "QSO Sniffing tool"), 0, 17, 2, 1);
+
+
+ TableView tblVw_notify_sniffCallSigns = new TableView();
+ tblVw_notify_sniffCallSigns = initNotifyAtCallSignTable();
+ tblVw_notify_sniffCallSigns.setItems(this.chatcontroller.getLstNotify_QSOSniffer_sniffedCallSignList());
+
+ Button btn_notifySniffCall_addLine = new Button("Add new CallSign");
+ btn_notifySniffCall_addLine.setOnAction(new EventHandler() {
+ @Override
+ public void handle(ActionEvent event) {
+ String newTextSnippet = "Pse change (DOUBLECLICK)";
+ chatcontroller.getLstNotify_QSOSniffer_sniffedCallSignList().add(0, newTextSnippet);
+ }
+ });
+
+// grdPnlNotify.add(tblVw_notify_sniffCallSigns,0,15);
+// grdPnlNotify.add(btn_notifySniffCall_addLine, 0, 16);
+
+ grdPnlNotify.add(tblVw_notify_sniffCallSigns,0,18);
+ grdPnlNotify.add(btn_notifySniffCall_addLine, 0, 19);
VBox vbxNotify = new VBox();
vbxNotify.setPadding(new Insets(10, 10, 10, 10));
@@ -6609,6 +7739,17 @@ public class Kst4ContestApplication extends Application {
TextField txtFld_messageHandlingAutoAnswer = new TextField();
txtFld_messageHandlingAutoAnswer.setText(this.chatcontroller.getChatPreferences().getMessageHandling_autoAnswerTextMainCat());
+ txtFld_messageHandlingAutoAnswer.textProperty().addListener(new ChangeListener() {
+
+ @Override
+ public void changed(ObservableValue extends String> observed, String oldString, String newString) {
+ System.out.println("[Main.java, Info]: Setted the autoanswer: " + txtFld_messageHandlingAutoAnswer.getText().toUpperCase());
+ chatcontroller.getChatPreferences().setMessageHandling_autoAnswerTextMainCat(txtFld_messageHandlingAutoAnswer.getText().toUpperCase());
+ chatcontroller.getChatPreferences().setMessageHandling_autoAnswerTextSecondCat(txtFld_messageHandlingAutoAnswer.getText().toUpperCase());
+ }
+ });
+
+
grdPnlMessageHandlingBeacon.add(txtFld_messageHandlingAutoAnswer,1,2);
grdPnlMessageHandlingBeacon.add(chkbx_msgHandlingAutoAnswerEnabled,0,2);
@@ -6642,30 +7783,38 @@ public class Kst4ContestApplication extends Application {
vbxInternalDB.getChildren().addAll(grdPnlInternalDBPane);
TableView