1297 lines
59 KiB
Python
1297 lines
59 KiB
Python
# Script to automatically Generate Icons on Panel for automation purposes
|
|
#
|
|
# Author: Dave Sand, Bill Fitch, copyright 2022
|
|
# Part of the JMRI distribution
|
|
|
|
from javax.swing import JOptionPane
|
|
from java.awt.geom import Point2D
|
|
from java.awt import Color
|
|
|
|
|
|
# from jython.DispatcherSystem.Startup import OptionDialog
|
|
|
|
|
|
# IS:DSCT:nnn Control sensors
|
|
# IS:DSMT:nnn Move TO sensors
|
|
# IS:DSMP:nnn Move Progress sensors
|
|
# IX:DSLX:1 Logix
|
|
|
|
# Remove Icons
|
|
# Block content labels
|
|
# Labels
|
|
# Sensors
|
|
# Remove Logix
|
|
# Remove Transits
|
|
# Remove Sections
|
|
# Remove SML
|
|
# Remove Sensors
|
|
#
|
|
# Add sensors
|
|
# Generate SML and Sections
|
|
# Add Logix
|
|
# Add Icons
|
|
# Sensors
|
|
# Labels
|
|
# Block content labels
|
|
|
|
|
|
class processPanels(jmri.jmrit.automat.AbstractAutomaton):
|
|
|
|
if "list" in globals() and type(globals()["list"]).__name__ != "type":
|
|
# print(" Detected shadowed 'list' type: ", type(globals()["list"])) # list is being used in JMRI. This enables us to use list in Jython
|
|
del globals()["list"]
|
|
|
|
if "set" in globals() and type(globals()["set"]).__name__ != "type":
|
|
# print(" Detected shadowed 'set' type: ", type(globals()["set"])) # set is being used in JMRI. This enables us to use set in Jython
|
|
del globals()["set"]
|
|
|
|
logLevel = 0
|
|
version_no = 0.2 #used to delete DispatcherPanel for new versions if the number of controlsensors/icons has changed
|
|
|
|
list_of_stopping_points = []
|
|
blockPoints1 = {}
|
|
blockPoints = {} # Block center points used by direct access process
|
|
editorManager = jmri.InstanceManager.getDefault(jmri.jmrit.display.EditorManager)
|
|
|
|
# row number, user name, label name, x offset, y offset
|
|
i = 1
|
|
controlSensors = []
|
|
controlSensors.append([i, 'startDispatcherSensor', 'Run Dispatcher System', 0, 0]); i += 1
|
|
controlSensors.append([i, 'stopMasterSensor', 'Stop Dispatcher System', 0, 0]); i += 1
|
|
controlSensors.append([i, 'modifyMasterSensor', 'Modify Dispatcher System', 0, 0]); i += 1
|
|
|
|
controlSensors.append([i, 'Express', 'Express Train (no stopping)', 10, 5]); i += 1
|
|
controlSensors.append([i, 'newTrainSensor', 'Setup Train in Section', 10, 5]); i += 1
|
|
controlSensors.append([i, 'soundSensor', 'Enable Announcements', 10, 5]); i += 1
|
|
controlSensors.append([i, 'simulateSensor', 'Simulate Dispatched Trains', 10, 5]); i += 1
|
|
controlSensors.append([i, 'checkRouteSensor', 'Dispatch Path must be clear', 10, 5]); i += 1
|
|
controlSensors.append([i, 'stopAtStopSensor', 'Stop at Stop Sensors (Default)', 10, 5]); i += 1
|
|
|
|
controlSensors.append([i, 'setDispatchSensor', 'Run Dispatch', 0, 5]); i += 1
|
|
controlSensors.append([i, 'setRouteSensor', 'Setup Route', 0, 5]); i += 1
|
|
controlSensors.append([i, 'setStoppingDistanceSensor', 'Set Stopping Length', 0, 5]); i += 1
|
|
controlSensors.append([i, 'setStopSensor', 'Set Stop Sensor', 0, 5]); i += 1
|
|
controlSensors.append([i, 'setStationWaitTimeSensor', 'Set Station Wait Time', 0, 5]); i += 1
|
|
controlSensors.append([i, 'setStationDirectionSensor', 'Set Station Direction', 0, 5]); i += 1
|
|
controlSensors.append([i, 'setTransitBlockRestrictionSensor', 'Restrict Transit Operation', 0, 5]); i += 1
|
|
|
|
controlSensors.append([i, 'runRouteSensor', 'Run Route', 10, 5]); i += 1
|
|
controlSensors.append([i, 'editRoutesSensor', 'View/Edit Routes', 10, 5]); i += 1
|
|
controlSensors.append([i, 'viewScheduledSensor', 'View/Edit Scheduled Trains', 10, 5]); i += 1
|
|
controlSensors.append([i, 'showClockSensor', 'Show Analog Clock', 10, 5]); i += 1
|
|
controlSensors.append([i, 'startSchedulerSensor', 'Start Scheduler', 10, 5]); i += 1
|
|
controlSensors.append([i, 'timetableSensor', 'Show Timetable', 10, 5]); i += 1
|
|
controlSensors.append([i, 'departureTimeSensor', 'Setup Departure Times', 10, 5]); i += 1
|
|
controlSensors.append([i, 'helpSensor', 'Help', 0, 5]); i += 1
|
|
|
|
|
|
|
|
def __init__(self):
|
|
self.result = "Success" #value is returned in __str__ and set to "Failure" in self.tryme()
|
|
self.define_DisplayProgress_global()
|
|
if self.perform_initial_checks():
|
|
self.show_progress(0)
|
|
self.tryme(self.saveForwardStoppingSensors, "Cannot save Forward Stopping Sensors: Contact Developer")
|
|
self.tryme(self.removeIconsAndLabels, "Cannot remove Icons And Labels: Contact Developer")
|
|
self.tryme(self.removeLogix, "Cannot remove startup Logix: Contact Developer")
|
|
self.tryme(self.removeTransits, "Cannot remove Transits: Contact Developer")
|
|
self.tryme(self.removeSML, "Cannot remove SML: Contact Developer") # do before removeSections in case direction sensors have been added to the SML
|
|
self.tryme(self.removeSections, "Cannot remove Sections: Contact Developer")
|
|
self.show_progress(20)
|
|
self.tryme(self.removeSensors, "Cannot generate startup Logix: Contact Developer")
|
|
self.show_progress(40)
|
|
# print "A"
|
|
self.tryme(self.updatePanels, "Cannot update Panels: Contact Developer")
|
|
# print "B"
|
|
self.get_list_of_stopping_points()
|
|
# print "C"
|
|
# self.tryme(self.get_list_of_stopping_points, "Cannot get list of stopping points, Contact Developer")
|
|
self.addSensors()
|
|
# print "D"
|
|
self.generateSML()
|
|
# print "E"
|
|
self.show_progress(60)
|
|
self.generateSections() # if it fails need a better fail message
|
|
# print "F"
|
|
# self.tryme(self.generateSections, "Cannot generate Sections: Signal Masts not set up correctly. Needs to be fixed before using Dispatcher System.")
|
|
self.show_progress(80)
|
|
self.tryme(self.addLogix, "Cannot generate startup Logix: Contact Developer")
|
|
# print "G"
|
|
self.addIcons()
|
|
self.tryme(self.retrieveForwardStoppingSensors, "Cannot retrieve Stopping Sensors: Contact Developer")
|
|
self.setVersionNo()
|
|
self.stop_all_threads()
|
|
self.end_show_progress()
|
|
|
|
else:
|
|
self.result = "Failure"
|
|
|
|
def __str__(self):
|
|
return self.result
|
|
|
|
|
|
def setVersionNo(self):
|
|
memory = memories.provideMemory('IS:ISMEM:' + "versionNo")
|
|
if memory is not None:
|
|
memory.setValue(self.version_no)
|
|
|
|
def version_number_changed(self):
|
|
memory = memories.getMemory('IMIS:ISMEM:' + "versionNo")
|
|
# print "memory", memory, type(memory)
|
|
if memory is None:
|
|
# print "version_no changed", "memory:", "version", self.version_no
|
|
return True
|
|
elif memory.getValue() != self.version_no:
|
|
# print "version_no changed", "memory:", memory.getValue(), "version", self.version_no
|
|
return True
|
|
else:
|
|
# print "version_no not changed", "memory:", memory.getValue(), "version", self.version_no
|
|
return False
|
|
|
|
|
|
def stop_all_threads(self):
|
|
summary = jmri.jmrit.automat.AutomatSummary.instance()
|
|
automatsList = java.util.concurrent.CopyOnWriteArrayList()
|
|
for automat in summary.getAutomats():
|
|
automatsList.add(automat)
|
|
|
|
for automat in automatsList:
|
|
automat.stop()
|
|
|
|
def tryme(self, func, failure_message):
|
|
try:
|
|
func()
|
|
except:
|
|
title = "Error in Routine"
|
|
Query().displayMessage(failure_message,title)
|
|
self.result = "Failure"
|
|
pass
|
|
|
|
def define_DisplayProgress_global(self):
|
|
global dpg
|
|
dpg = DisplayProgress()
|
|
|
|
def show_progress(self, progress):
|
|
global dpg
|
|
dpg.Update("creating icons: " + str(progress)+ "% complete")
|
|
|
|
def end_show_progress(self):
|
|
global dpg
|
|
dpg.killLabel()
|
|
|
|
# **************************************************
|
|
# perform initial checks
|
|
# **************************************************
|
|
|
|
def perform_initial_checks(self):
|
|
|
|
sensors_OK = False
|
|
block_sensors_OK = False
|
|
stops_OK = False
|
|
lengths_OK = False
|
|
speed_profiles_OK = False
|
|
|
|
#JOptionPane.showMessageDialog(None, "Performing some preliminary checks to ensure the trains run correctly\nAll errors will need to be fixed for Dispatcher to run correctly\nSome errors will cause the panel to be set up incorrectly in this stage", 'Checks', JOptionPane.WARNING_MESSAGE)
|
|
|
|
# check all blocks have sensors
|
|
if self.check_all_blocks_have_sensors() == False:
|
|
self.msg = self.msg + "\n***********************\n Do you wish to continue\n***********************"
|
|
myAnswer = JOptionPane.showConfirmDialog(None, self.msg)
|
|
if myAnswer == JOptionPane.YES_OPTION:
|
|
#JOptionPane.showMessageDialog(None, 'OK continuing', "As you wish", JOptionPane.WARNING_MESSAGE)
|
|
pass
|
|
elif myAnswer == JOptionPane.NO_OPTION:
|
|
msg = 'Stopping'
|
|
JOptionPane.showMessageDialog(None, 'Stopping', "Fix Error" , JOptionPane.WARNING_MESSAGE)
|
|
return False
|
|
elif myAnswer == JOptionPane.CANCEL_OPTION:
|
|
msg = 'Stopping'
|
|
JOptionPane.showMessageDialog(None, 'Stopping', "Have a cup of Tea", JOptionPane.WARNING_MESSAGE)
|
|
return False
|
|
elif myAnswer == JOptionPane.CLOSED_OPTION:
|
|
if self.logLevel > 0: print "You closed the window. How rude!"
|
|
else:
|
|
sensors_OK = True
|
|
|
|
|
|
if self.check_no_blocks_have_same_sensor() == False:
|
|
self.msg1 = self.msg1 + "\n***********************\n Do you wish to continue\n***********************"
|
|
myAnswer = JOptionPane.showConfirmDialog(None, self.msg1)
|
|
if self.logLevel > 0: print(1)
|
|
if myAnswer == JOptionPane.YES_OPTION:
|
|
#JOptionPane.showMessageDialog(None, 'OK continuing', "As you wish", JOptionPane.WARNING_MESSAGE)
|
|
pass
|
|
elif myAnswer == JOptionPane.NO_OPTION:
|
|
msg = 'Stopping'
|
|
JOptionPane.showMessageDialog(None, 'Stopping', "You need a cup of Tea" , JOptionPane.WARNING_MESSAGE)
|
|
return False
|
|
elif myAnswer == JOptionPane.CANCEL_OPTION:
|
|
msg = 'Stopping'
|
|
JOptionPane.showMessageDialog(None, 'Stopping', "Have a cup of Tea", JOptionPane.WARNING_MESSAGE)
|
|
return False
|
|
elif myAnswer == JOptionPane.CLOSED_OPTION:
|
|
if self.logLevel > 0: print "You closed the window. How rude!"
|
|
else:
|
|
block_sensors_OK = True
|
|
|
|
if self.check_sufficient_number_of_blocks() == False:
|
|
self.msg2 = "There are insufficient stopping points for Dispatcher to work\n" + self.msg2 + "\n***********************\n Do you wish to continue? You are advised to stop as the current stage cannot perfom correctly\n***********************"
|
|
if self.logLevel > 0: print(3)
|
|
myAnswer = JOptionPane.showConfirmDialog(None, self.msg2)
|
|
if myAnswer == JOptionPane.YES_OPTION:
|
|
#JOptionPane.showMessageDialog(None, 'OK continuing', "As you wish", JOptionPane.WARNING_MESSAGE)
|
|
pass
|
|
elif myAnswer == JOptionPane.NO_OPTION:
|
|
msg = 'Stopping'
|
|
JOptionPane.showMessageDialog(None, "Specify the stopping points by inserting 'stop' in the comment fields of the blocks" , "Stopping" , JOptionPane.WARNING_MESSAGE)
|
|
return False
|
|
elif myAnswer == JOptionPane.CANCEL_OPTION:
|
|
msg = 'Stopping'
|
|
JOptionPane.showMessageDialog(None, 'Stopping', "Have a cup of Tea", JOptionPane.WARNING_MESSAGE)
|
|
return False
|
|
elif myAnswer == JOptionPane.CLOSED_OPTION:
|
|
if self.logLevel > 0: print "You closed the window. How rude!"
|
|
else:
|
|
stops_OK = True
|
|
|
|
if self.check_all_blocks_have_lengths() == False:
|
|
self.msg5 = "Not all blocks have lengths\n" + self.msg5 + "\n***********************\n Do you wish to continue? Trains will not run correctly.\n***********************"
|
|
if self.logLevel > 0: print(3)
|
|
myAnswer = JOptionPane.showConfirmDialog(None, self.msg5)
|
|
if myAnswer == JOptionPane.YES_OPTION:
|
|
#JOptionPane.showMessageDialog(None, 'OK continuing', "As you wish", JOptionPane.WARNING_MESSAGE)
|
|
pass
|
|
elif myAnswer == JOptionPane.NO_OPTION:
|
|
msg = 'Stopping'
|
|
JOptionPane.showMessageDialog(None, "Specify the stopping points by inserting 'stop' in the comment fields of the blocks" , "Stopping" , JOptionPane.WARNING_MESSAGE)
|
|
return False
|
|
elif myAnswer == JOptionPane.CANCEL_OPTION:
|
|
msg = 'Stopping'
|
|
JOptionPane.showMessageDialog(None, 'Stopping', "Have a cup of Tea", JOptionPane.WARNING_MESSAGE)
|
|
return False
|
|
elif myAnswer == JOptionPane.CLOSED_OPTION:
|
|
if self.logLevel > 0: print "You closed the window. How rude!"
|
|
else:
|
|
lengths_OK = True
|
|
|
|
if self.check_engines_with_speed_profiles_exist() == False:
|
|
self.msg5 = "There are no engines with speed profiles\n" + self.msg5 + "\n***********************\n To continue either set up speed profiles for a train, \nor for a quick examination of Dispatcher System you can install the speed profiles stored in the Dispatcher System Folder\n*********Do you wish to continue?**************"
|
|
if self.logLevel > 0: print(3)
|
|
myAnswer = JOptionPane.showConfirmDialog(None, self.msg5)
|
|
if myAnswer == JOptionPane.YES_OPTION:
|
|
JOptionPane.showMessageDialog(None, 'Please install some of the speed profiles provided', "Look in the speed profile folder in the Dispatcher System Folder", JOptionPane.WARNING_MESSAGE)
|
|
return False
|
|
elif myAnswer == JOptionPane.NO_OPTION:
|
|
msg = 'Stopping'
|
|
JOptionPane.showMessageDialog(None, "Please run your trains over a suitable track with 3 blocks - see help" , "Install speed profiles" , JOptionPane.WARNING_MESSAGE)
|
|
return False
|
|
elif myAnswer == JOptionPane.CANCEL_OPTION:
|
|
msg = 'Stopping'
|
|
JOptionPane.showMessageDialog(None, 'Stopping', "Have a cup of Tea", JOptionPane.WARNING_MESSAGE)
|
|
return False
|
|
elif myAnswer == JOptionPane.CLOSED_OPTION:
|
|
if self.logLevel > 0: print "You closed the window. How rude!"
|
|
|
|
else:
|
|
speed_profiles_OK = True
|
|
|
|
msg = ""
|
|
some_checks_OK = False
|
|
if sensors_OK:
|
|
msg = msg + "All blocks have lengths\n"
|
|
some_checks_OK = True
|
|
if block_sensors_OK:
|
|
msg = msg + "All blocks have lengths\n"
|
|
some_checks_OK = True
|
|
if stops_OK:
|
|
msg = msg + "All blocks have lengths\n"
|
|
some_checks_OK = True
|
|
if lengths_OK:
|
|
msg = msg + "All blocks have lengths\n"
|
|
some_checks_OK = True
|
|
if speed_profiles_OK:
|
|
msg = msg + "You have engine(s) with speed profile\n"
|
|
some_checks_OK = True
|
|
|
|
if some_checks_OK:
|
|
msg = "Performed some preliminary checks to ensure the trains run correctly\n\nAll Checks OK"
|
|
title = "Checks"
|
|
opt1 = "Continue"
|
|
opt2 = "Look in more detail"
|
|
reply = Query().customQuestionMessage2str(msg, title, opt1, opt2)
|
|
if reply == opt2:
|
|
if sensors_OK:
|
|
Message = "All blocks have sensors"
|
|
JOptionPane.showMessageDialog(None, Message, 'Message', JOptionPane.INFORMATION_MESSAGE)
|
|
if block_sensors_OK:
|
|
Message = "no two blocks have the same sensor\nPassed check OK"
|
|
JOptionPane.showMessageDialog(None, Message, 'Message', JOptionPane.INFORMATION_MESSAGE)
|
|
if stops_OK:
|
|
Message = "The following blocks have been specified as stopping points\n" + self.msg2 + "\n there are sufficient blocks set up"
|
|
JOptionPane.showMessageDialog(None, Message, 'Message', JOptionPane.INFORMATION_MESSAGE)
|
|
if lengths_OK:
|
|
Message = "All blocks have lengths\n OK to continue \nNote that trains should also be set up with a speed profile to stop correctly"
|
|
JOptionPane.showMessageDialog(None, Message, 'Message', JOptionPane.INFORMATION_MESSAGE)
|
|
if speed_profiles_OK:
|
|
msg = ""
|
|
for engine in self.get_all_roster_entries_with_speed_profile():
|
|
msg += "\n" + str(engine)
|
|
Message = "You have the following trains with speed profiles" + msg
|
|
JOptionPane.showMessageDialog(None, Message, 'Message', JOptionPane.INFORMATION_MESSAGE)
|
|
return True
|
|
|
|
def check_all_blocks_have_sensors(self):
|
|
LayoutBlockManager=jmri.InstanceManager.getDefault(jmri.jmrit.display.layoutEditor.LayoutBlockManager)
|
|
list_of_errors = []
|
|
success = True
|
|
for block in blocks.getNamedBeanSet():
|
|
if block.getSensor() == None:
|
|
if LayoutBlockManager.getLayoutBlock(block) != None: #only include blocks included in a layout panel
|
|
if block.getUserName() != None: #all layout blocks have usernames, should not need this check
|
|
msg = "block {} does not have a sensor".format(block.getUserName())
|
|
else:
|
|
msg = "block {} does not have a sensor".format(block.getSystemName())
|
|
msg = msg + "\nblock {} does not have a username".format(block.getSystemName())
|
|
list_of_errors.append(msg)
|
|
self.msg = ""
|
|
for message in list_of_errors:
|
|
self.msg = self.msg +"\n" + message
|
|
success = False
|
|
return success
|
|
|
|
def check_no_blocks_have_same_sensor(self):
|
|
LayoutBlockManager=jmri.InstanceManager.getDefault(jmri.jmrit.display.layoutEditor.LayoutBlockManager)
|
|
dict = {}
|
|
success = True
|
|
for block in blocks.getNamedBeanSet():
|
|
if LayoutBlockManager.getLayoutBlock(block) != None: #only include blocks included in a layout panel
|
|
if block.getUserName() != None: #all layout blocks have usernames, should not need this check
|
|
block_name = block.getUserName()
|
|
else:
|
|
block_name = block.getSystemName()
|
|
sensor = block.getSensor()
|
|
if sensor != None:
|
|
if sensor.getUserName() != None:
|
|
sensor_name = sensor.getUserName()
|
|
else:
|
|
sensor_name = sensor.getSystemName()
|
|
dict[block_name] = sensor_name
|
|
|
|
list_of_errors = self.get_duplicate_values_in_dict(dict)
|
|
if self.logLevel > 0: print list_of_errors
|
|
if list_of_errors == []:
|
|
success = True
|
|
else:
|
|
success = False
|
|
self.msg1 = ""
|
|
for message in list_of_errors:
|
|
self.msg1 = self.msg1 + "\n" + message
|
|
|
|
return success
|
|
|
|
|
|
def get_duplicate_values_in_dict(self, input_dict):
|
|
|
|
# finding duplicate values
|
|
# from dictionary
|
|
# using a naive approach
|
|
rev_dict = {}
|
|
|
|
for key, value in input_dict.items():
|
|
rev_dict.setdefault(value, set()).add(key)
|
|
|
|
result = ["blocks " +', '.join(values) + " have the same sensor " + str( key) for key, values in rev_dict.items()
|
|
if len(values) > 1]
|
|
return result
|
|
|
|
def check_sufficient_number_of_blocks(self):
|
|
LayoutBlockManager=jmri.InstanceManager.getDefault(jmri.jmrit.display.layoutEditor.LayoutBlockManager)
|
|
list_of_stops = []
|
|
list_of_blocks = []
|
|
for block in blocks.getNamedBeanSet():
|
|
if LayoutBlockManager.getLayoutBlock(block) != None: #only include blocks included in a layout panel
|
|
if block.getUserName() != None: #all layout blocks have usernames, should not need this check
|
|
block_name = block.getUserName()
|
|
else:
|
|
block_name = block.getSystemName()
|
|
comment = str(block.getComment())
|
|
if comment !=None:
|
|
if "stop" in comment.lower():
|
|
list_of_stops.append("block " + block_name + " has a stop")
|
|
if self.logLevel > 0: print list_of_stops
|
|
else:
|
|
list_of_blocks.append("block " + block_name + " has no stop")
|
|
if self.logLevel > 0: print list_of_blocks
|
|
else:
|
|
list_of_blocks.append("block " + block_name + " has no stop")
|
|
#countthe number of blocks in dictionary
|
|
no_stops = len(list_of_stops)
|
|
if self.logLevel > 0: print "no_stops", no_stops
|
|
no_blocks = len(list_of_blocks)
|
|
if self.logLevel > 0: print "no blocks", no_blocks
|
|
if no_stops < 2:
|
|
success = False
|
|
else:
|
|
success = True
|
|
self.msg2 = " - "
|
|
self.msg2 = self.msg2 + '\n - '.join(list_of_stops)
|
|
if self.logLevel > 0: print self.msg2
|
|
self.msg3 = ""
|
|
self.msg3 = '\n - '.join(list_of_blocks)
|
|
if self.logLevel > 0: print self.msg3
|
|
if no_stops == 0:
|
|
self.msg2 = " - there are no stops"
|
|
return success
|
|
|
|
def check_all_blocks_have_lengths(self):
|
|
LayoutBlockManager=jmri.InstanceManager.getDefault(jmri.jmrit.display.layoutEditor.LayoutBlockManager)
|
|
list_of_errors = []
|
|
success = True
|
|
for block in blocks.getNamedBeanSet():
|
|
if LayoutBlockManager.getLayoutBlock(block) != None: #only include blocks included in a layout panel
|
|
if block.getLengthMm() < 0.01:
|
|
if block.getUserName() != None: #all layout blocks have usernames, should not need this check
|
|
msg = "block {} does not have a length".format(block.getUserName())
|
|
else:
|
|
msg = "block {} does not have a length".format(block.getSystemName())
|
|
msg = msg + "\nblock {} does not have a username".format(block.getSystemName())
|
|
list_of_errors.append(msg)
|
|
success = False
|
|
self.msg5 = " - "
|
|
self.msg5 = self.msg5 + '\n - '.join(list_of_errors)
|
|
|
|
return success
|
|
|
|
def check_engines_with_speed_profiles_exist(self):
|
|
roster_entries_with_speed_profile = self.get_all_roster_entries_with_speed_profile()
|
|
if roster_entries_with_speed_profile == []:
|
|
return False
|
|
else:
|
|
return True
|
|
# return True
|
|
|
|
def get_all_roster_entries_with_speed_profile(self):
|
|
roster_entries_with_speed_profile = []
|
|
r = jmri.jmrit.roster.Roster.getDefault()
|
|
for roster_entry in jmri.jmrit.roster.Roster.getAllEntries(r):
|
|
if self.logLevel > 0: print "roster_entry.getSpeedProfile()",roster_entry,roster_entry.getSpeedProfile()
|
|
if roster_entry.getSpeedProfile() != None:
|
|
roster_entries_with_speed_profile.append(roster_entry.getId())
|
|
if self.logLevel > 0: print "roster_entry.getId()",roster_entry.getId()
|
|
return roster_entries_with_speed_profile
|
|
|
|
def updatePanels(self):
|
|
for panel in self.editorManager.getAll(jmri.jmrit.display.layoutEditor.LayoutEditor):
|
|
if panel.getTitle() != 'Dispatcher System':
|
|
panel.invalidate()
|
|
panel.validate()
|
|
panel.repaint()
|
|
pass
|
|
|
|
# **************************************************
|
|
# remove icons and labels from panels
|
|
# **************************************************
|
|
|
|
def removeIconsAndLabels(self):
|
|
|
|
for panel in self.editorManager.getAll(jmri.jmrit.display.layoutEditor.LayoutEditor):
|
|
if panel.getTitle() == 'Dispatcher System':
|
|
if self.version_number_changed():
|
|
# print "removing panel, version number changed"
|
|
self.editorManager.remove(panel)
|
|
panel.dispose()
|
|
# Skip the Dispatcher System control panel if it exists
|
|
continue
|
|
|
|
self.removeBlockContentIcons(panel)
|
|
self.removeLabels(panel)
|
|
self.removeSensorIcons(panel)
|
|
|
|
def removeBlockContentIcons(self, panel):
|
|
deleteList = [] # Prevent concurrent modification
|
|
icons = panel.getBlockContentsLabelList()
|
|
for icon in icons:
|
|
blk = icon.getBlock()
|
|
if blk is not None:
|
|
deleteList.append(icon)
|
|
|
|
for item in deleteList:
|
|
panel.removeFromContents(item)
|
|
|
|
def removeLabels(self, panel):
|
|
labelText = []
|
|
for control in self.controlSensors:
|
|
labelText.append(control[2])
|
|
|
|
deleteList = [] # Prevent concurrent modification
|
|
for label in panel.getLabelImageList():
|
|
if label.isText():
|
|
if label.getText() in labelText:
|
|
deleteList.append(label)
|
|
|
|
for item in deleteList:
|
|
panel.removeFromContents(item)
|
|
|
|
def removeSensorIcons(self, panel):
|
|
blockSensors = []
|
|
for block in blocks.getNamedBeanSet():
|
|
sensor = block.getSensor()
|
|
if sensor is not None:
|
|
blockSensors.append(sensor)
|
|
|
|
deleteList = [] # Prevent concurrent modification
|
|
icons = panel.getSensorList()
|
|
for icon in icons:
|
|
sensor = icon.getSensor()
|
|
if sensor is not None:
|
|
name = sensor.getDisplayName()
|
|
if 'MoveTo' in name or 'MoveInProgress' in name:
|
|
# dispatcher system sensors
|
|
deleteList.append(icon)
|
|
else:
|
|
# block sensors
|
|
if sensor in blockSensors:
|
|
deleteList.append(icon)
|
|
|
|
for item in deleteList:
|
|
panel.removeFromContents(item)
|
|
|
|
# **************************************************
|
|
# remove Logix
|
|
# **************************************************
|
|
def removeLogix(self):
|
|
logixManager = jmri.InstanceManager.getDefault(jmri.LogixManager)
|
|
logix = logixManager.getLogix('Run Dispatcher')
|
|
if logix is not None:
|
|
logix.deActivateLogix()
|
|
logixManager.deleteLogix(logix)
|
|
|
|
# **************************************************
|
|
# remove Transits
|
|
# **************************************************
|
|
def removeTransits(self):
|
|
deleteList = [] # Prevent concurrent modification
|
|
for transit in transits.getNamedBeanSet():
|
|
deleteList.append(transit)
|
|
|
|
for item in deleteList:
|
|
transits.deleteBean(item, 'DoDelete')
|
|
|
|
# **************************************************
|
|
# remove Sections
|
|
# **************************************************
|
|
def removeSections(self):
|
|
|
|
#remove sections
|
|
deleteList = [] # Prevent concurrent modification
|
|
directionSensorDeleteList = []
|
|
for section in sections.getNamedBeanSet():
|
|
deleteList.append(section)
|
|
|
|
forward_sensor = section.getForwardBlockingSensor()
|
|
if forward_sensor is not None:
|
|
directionSensorDeleteList.append(forward_sensor)
|
|
|
|
reverse_sensor = section.getReverseBlockingSensor()
|
|
if reverse_sensor is not None:
|
|
directionSensorDeleteList.append(reverse_sensor)
|
|
|
|
for item in deleteList:
|
|
sections.deleteBean(item, 'DoDelete')
|
|
|
|
for item in directionSensorDeleteList:
|
|
sensors.deleteBean(item, 'DoDelete')
|
|
|
|
deleteList = []
|
|
directionSensorDeleteList = []
|
|
|
|
# **************************************************
|
|
# remove signal mast logic
|
|
# **************************************************
|
|
def removeSML(self):
|
|
smlManger = jmri.InstanceManager.getDefault(jmri.SignalMastLogicManager)
|
|
deleteList = [] # Prevent concurrent modification
|
|
for sml in smlManger.getNamedBeanSet():
|
|
deleteList.append(sml)
|
|
|
|
for item in deleteList:
|
|
smlManger.deleteBean(item, 'DoDelete')
|
|
|
|
# **************************************************
|
|
# remove sensors
|
|
# **************************************************
|
|
def removeSensors(self):
|
|
controlName = []
|
|
if self.editorManager.get("Dispatcher System") is None:
|
|
# OK to delete control sensors
|
|
for control in self.controlSensors:
|
|
controlName.append(control[1])
|
|
|
|
deleteList = [] # Prevent concurrent modification
|
|
for sensor in sensors.getNamedBeanSet():
|
|
userName = sensor.getUserName()
|
|
sysName = sensor.getSystemName()
|
|
if userName is not None:
|
|
if 'MoveTo' in userName or 'MoveInProgress' in userName:
|
|
deleteList.append(sensor)
|
|
elif userName in controlName:
|
|
deleteList.append(sensor)
|
|
|
|
for item in deleteList:
|
|
#print 'remove sensor {}'.format(item.getDisplayName())
|
|
sensors.deleteBean(item, 'DoDelete')
|
|
|
|
# ***********************************************************
|
|
# gets the list of stopping points (stations, sidings etc.)
|
|
# ***********************************************************
|
|
def get_list_of_stopping_points(self):
|
|
if self.logLevel > 0: print "in get_list_of_stopping_points"
|
|
stopping_points_set = set()
|
|
|
|
# First, get stopping points from block comments
|
|
for block in blocks.getNamedBeanSet():
|
|
comment = block.getComment()
|
|
if comment != None:
|
|
if "stop" in comment.lower():
|
|
stopping_points_set.add(block.getUserName())
|
|
|
|
# Second, automatically add blocks associated with LayoutTurntables and LayoutTraversers
|
|
editorManager = jmri.InstanceManager.getDefault(jmri.jmrit.display.EditorManager)
|
|
for editor in editorManager.getAll():
|
|
if isinstance(editor, jmri.jmrit.display.layoutEditor.LayoutEditor):
|
|
# The returned object is a Java Set, which needs to be converted to a list for safe iteration in Jython
|
|
for turntable in list(editor.getLayoutTurntables()):
|
|
layout_block = turntable.getLayoutBlock()
|
|
if layout_block is not None and layout_block.getUserName() is not None:
|
|
stopping_points_set.add(layout_block.getUserName())
|
|
|
|
# The returned object is a Java Set, which needs to be converted to a list for safe iteration in Jython
|
|
for traverser in list(editor.getLayoutTraversers()):
|
|
layout_block = traverser.getLayoutBlock()
|
|
if layout_block is not None and layout_block.getUserName() is not None:
|
|
stopping_points_set.add(layout_block.getUserName())
|
|
|
|
self.list_of_stopping_points = sorted(list(stopping_points_set))
|
|
if self.logLevel > 0: print "list of stopping points", self.list_of_stopping_points
|
|
|
|
# **************************************************
|
|
# add sensors
|
|
# **************************************************
|
|
def addSensors(self):
|
|
# Create the control sensors
|
|
for control in self.controlSensors:
|
|
sensor = sensors.provideSensor('IS:DSCT:' + str(control[0]))
|
|
if sensor is not None:
|
|
sensor.setUserName(control[1])
|
|
# Create a dummy sensor
|
|
sensor = sensors.provideSensor('IS:DSCT:' + str(0))
|
|
sensor.setUserName("DummyControlSensor")
|
|
sensor = sensors.provideSensor('IS:DSCTA:' + str(0))
|
|
sensor.setUserName("Jdialog_closed") # used when setting nonmodal dialogs closed
|
|
sensor = sensors.provideSensor('IS:DSCTB:' + str(0))
|
|
sensor.setUserName("stoppingDistanceSet") # used when setting stopping distances
|
|
|
|
# Create the stop sensors
|
|
index = 0
|
|
for stop in self.list_of_stopping_points:
|
|
block = blocks.getBlock(stop)
|
|
if block is not None:
|
|
index += 1
|
|
moveto = sensors.provideSensor('IS:DSMT:' + str(index))
|
|
if moveto is not None:
|
|
moveto.setUserName('MoveTo' + block.getDisplayName().replace(" ","_") + '_stored')
|
|
inproc = sensors.provideSensor('IS:DSMP:' + str(index))
|
|
if inproc is not None:
|
|
inproc.setUserName('MoveInProgress' + block.getDisplayName().replace(" ","_"))
|
|
|
|
# **************************************************
|
|
# generate SML
|
|
# **************************************************
|
|
def generateSML(self):
|
|
layoutblocks.enableAdvancedRouting(True)
|
|
layoutblocks.setRoutingStabilised()
|
|
if self.logLevel > 0: print "Generating Signal Mast Logic"
|
|
smlManager = jmri.InstanceManager.getDefault(jmri.SignalMastLogicManager)
|
|
smlManager.automaticallyDiscoverSignallingPairs()
|
|
if self.logLevel > 0: print "Signal Mast Logic Generated"
|
|
|
|
# **************************************************
|
|
# generate sections
|
|
# **************************************************
|
|
def generateSections(self):
|
|
if self.logLevel > 0: print "Generating Sections"
|
|
smlManager = jmri.InstanceManager.getDefault(jmri.SignalMastLogicManager)
|
|
# generate sections()
|
|
smlManager.generateSection()
|
|
if self.logLevel > 0: print "Sections Generated"
|
|
self.show_progress(80)
|
|
# print "+++++++++++++++++++++++ generate block sections ++++++++++++++++++++++++++++++"
|
|
sections.generateBlockSections()
|
|
# print "+++++++++++++++++++++++ end generate block sections ++++++++++++++++++++++++++++++"
|
|
|
|
# **************************************************
|
|
# add Logix
|
|
# **************************************************
|
|
def addLogix(self):
|
|
lgxManager = jmri.InstanceManager.getDefault(jmri.LogixManager)
|
|
cdlManager = jmri.InstanceManager.getDefault(jmri.ConditionalManager)
|
|
lgx = lgxManager.createNewLogix('IX:DSLX:1', 'Run Dispatcher')
|
|
cdl = cdlManager.createNewConditional('IX:DSLX:1C1', 'Run Dispatcher')
|
|
lgx.addConditional('IX:DSLX:1C1', 0)
|
|
if cdl is not None:
|
|
cdl.setUserName('Run Dispatcher')
|
|
vars = []
|
|
vars.append(jmri.ConditionalVariable(False, jmri.Conditional.Operator.AND, jmri.Conditional.Type.SENSOR_ACTIVE, 'startDispatcherSensor', True))
|
|
cdl.setStateVariables(vars)
|
|
actions = []
|
|
actions.append(jmri.implementation.DefaultConditionalAction(1, jmri.Conditional.Action.RUN_SCRIPT, '', -1, 'program:jython/DispatcherSystem/Startup.py'))
|
|
cdl.setAction(actions)
|
|
lgx.activateLogix()
|
|
|
|
# **************************************************
|
|
# add Icons
|
|
# **************************************************
|
|
def addIcons(self):
|
|
for panel in self.editorManager.getAll(jmri.jmrit.display.layoutEditor.LayoutEditor):
|
|
self.getBlockCenterPoints(panel)
|
|
|
|
self.addStopIcons(panel)
|
|
self.addOccupancyIconsAndLabels(panel)
|
|
#add control icons in separate editor panel
|
|
self.addControlIconsAndLabels()
|
|
|
|
def getCenterPointOfNearestBlockToMid(self, panel):
|
|
if self.logLevel > 0: print "in getCenterPointOfNearestBlockToMid"
|
|
self.index = 0
|
|
self.blockPoints.clear()
|
|
blocks_with_track_segments = set()
|
|
|
|
# reassign the blockpoints to the nearest track segment to mid if one exists
|
|
for tsv in panel.getTrackSegmentViews():
|
|
|
|
blk = tsv.getBlockName()
|
|
|
|
|
|
pt1 = panel.getCoords(tsv.getConnect1(), tsv.getType1())
|
|
pt2 = panel.getCoords(tsv.getConnect2(), tsv.getType2())
|
|
|
|
[x1,y1] = [pt1.getX(), pt1.getY()]
|
|
[x2,y2] = [pt2.getX(), pt2.getY()]
|
|
|
|
|
|
if blk in self.list_of_stopping_points:
|
|
if abs(float(y1)-float(y2)) < 15.0: # East-West place icon to right of circle
|
|
x_reqd = int((float(x1)+float(x2))/2.0)+25 # to put to right of circle
|
|
y_reqd = int((float(y1)+float(y2))/2.0) # to put just under track
|
|
else: # North south place icon under circle
|
|
x_reqd = int((float(x1)+float(x2))/2.0)-20 # to centralise
|
|
y_reqd = int((float(y1)+float(y2))/2.0)+15 # to put under circle
|
|
blocks_with_track_segments.add(blk)
|
|
else:
|
|
x_reqd = int((float(x1)+float(x2))/2.0) # to put to right of circle
|
|
y_reqd = int((float(y1)+float(y2))/2.0)
|
|
|
|
pt_to_try = Point2D.Double(x_reqd, y_reqd)
|
|
if blk in self.blockPoints1:
|
|
pt_mid = self.blockPoints1[blk]
|
|
self.updateCoords1(blk, pt_to_try, pt_mid)
|
|
|
|
|
|
|
|
# Handle turntables
|
|
for turntableView in panel.getLayoutTurntableViews():
|
|
turntable = turntableView.getTurntable()
|
|
layoutBlock = turntable.getLayoutBlock()
|
|
if layoutBlock is not None:
|
|
blk = layoutBlock.getUserName()
|
|
if blk in self.blockPoints1:
|
|
pt_mid = self.blockPoints1[blk]
|
|
# For a turntable, the icon position is calculated relative to its own center
|
|
[x_reqd, y_reqd] = self.get_turntable_icon_position(turntable, turntableView)
|
|
pt_to_try = Point2D.Double(x_reqd, y_reqd)
|
|
self.updateCoords1(blk, pt_to_try, pt_mid)
|
|
|
|
# Handle traversers
|
|
for traverserView in panel.getLayoutTraverserViews():
|
|
traverser = traverserView.getTraverser()
|
|
layoutBlock = traverser.getLayoutBlock()
|
|
if layoutBlock is not None:
|
|
blk = layoutBlock.getUserName()
|
|
if blk in self.blockPoints1:
|
|
pt_mid = self.blockPoints1[blk]
|
|
# For a traverser, the icon position is calculated relative to its own center
|
|
[x_reqd, y_reqd] = self.get_traverser_icon_position(traverser, traverserView)
|
|
pt_to_try = Point2D.Double(x_reqd, y_reqd)
|
|
self.updateCoords1(blk, pt_to_try, pt_mid)
|
|
|
|
# Handle turnouts
|
|
for turnoutView in panel.getLayoutTurnoutViews():
|
|
turnout = turnoutView.getTurnout()
|
|
layoutBlock = turnoutView.getLayoutBlock()
|
|
if layoutBlock is not None:
|
|
blk = layoutBlock.getUserName()
|
|
if blk in blocks_with_track_segments:
|
|
continue
|
|
if blk in self.blockPoints1:
|
|
pt_mid = self.blockPoints1[blk]
|
|
coords = turnoutView.getCoordsCenter()
|
|
pt_to_try = Point2D.Double(coords.getX(), coords.getY())
|
|
self.updateCoords1(blk, pt_to_try, pt_mid)
|
|
|
|
def get_turntable_icon_position(self, turntable, turntableView):
|
|
import math
|
|
# print "--- Calculating icon position for turntable:", turntable.getName(), "---"
|
|
turntable_center = turntableView.getCoordsCenter()
|
|
radius = turntable.getRadius()
|
|
rays = turntable.getRayTrackList()
|
|
|
|
if len(rays) < 2:
|
|
# Fallback for turntables with 0 or 1 ray: place icon bottom-right
|
|
# print " Fewer than 2 rays, using fallback position."
|
|
x_reqd = int(turntable_center.getX()) + 30
|
|
y_reqd = int(turntable_center.getY()) + 25
|
|
return [x_reqd, y_reqd]
|
|
|
|
# Get all ray angles in degrees and sort them
|
|
angles = sorted([ray.getAngle() for ray in rays])
|
|
# print " Sorted ray angles (degrees):", angles
|
|
|
|
# Calculate angular gaps between adjacent rays
|
|
gaps = []
|
|
for i in range(len(angles) - 1):
|
|
gap = angles[i+1] - angles[i]
|
|
gaps.append(gap)
|
|
|
|
# Add the wrap-around gap between the last and first ray
|
|
wrap_around_gap = (360.0 - angles[-1]) + angles[0]
|
|
gaps.append(wrap_around_gap)
|
|
# print " Calculated gaps:", gaps
|
|
|
|
max_gap = max(gaps)
|
|
# print " Max gap found:", max_gap
|
|
|
|
# Find all gaps that are the largest
|
|
best_mid_angle = -1
|
|
min_angle_diff = 361 # Larger than any possible angle difference
|
|
|
|
# Define a preferred angle for tie-breaking (bottom-right quadrant)
|
|
preferred_angle = math.degrees(math.atan2(25, 30)) # atan2(y, x)
|
|
# print " Preferred angle for tie-breaking:", preferred_angle
|
|
|
|
for i in range(len(gaps)):
|
|
if abs(gaps[i] - max_gap) < 1e-6: # Compare floats with a tolerance
|
|
# print " Found a max gap at index", i
|
|
if i < len(angles) - 1:
|
|
mid_angle = angles[i] + max_gap / 2.0
|
|
else: # Wrap-around case
|
|
mid_angle = (angles[-1] + max_gap / 2.0) % 360.0
|
|
# print " Mid-angle of this gap:", mid_angle
|
|
|
|
# Normalize angle difference for tie-breaking
|
|
angle_diff = abs(mid_angle - preferred_angle)
|
|
# print " Difference from preferred angle:", angle_diff
|
|
if angle_diff < min_angle_diff:
|
|
# print " This is the new best candidate."
|
|
min_angle_diff = angle_diff
|
|
best_mid_angle = mid_angle
|
|
|
|
# print " Final chosen mid-angle:", best_mid_angle
|
|
# Convert the final angle to radians for trig functions
|
|
final_angle_rad = math.radians(best_mid_angle)
|
|
if best_mid_angle > 180.0 and best_mid_angle < 360.0:
|
|
icon_distance = radius + 70 # Place icon 20 pixels out from the turntable radius plus a bit to allow for the icon length
|
|
else:
|
|
icon_distance = radius + 30 # Place icon 20 pixels out from the turntable radius
|
|
x_reqd = int(turntable_center.getX() + icon_distance * math.sin(final_angle_rad))
|
|
y_reqd = int(turntable_center.getY() - icon_distance * math.cos(final_angle_rad))
|
|
# print " Turntable Centre (x, y):", int(turntable_center.getX()), ",", int(turntable_center.getY())
|
|
# print " Calculated position (x, y):", x_reqd, ",", y_reqd
|
|
# print "----------------------------------------------------"
|
|
return [x_reqd, y_reqd]
|
|
|
|
def get_traverser_icon_position(self, traverser, traverserView):
|
|
import math
|
|
if self.logLevel > 0: print "--- Calculating icon position for traverser:", traverser.getName(), "---"
|
|
traverser_center = traverserView.getCoordsCenter()
|
|
if self.logLevel > 0: print "traverser_center", traverser_center
|
|
slotOffset = traverser.getSlotOffset()
|
|
numberOfSlots = traverser.getNumberSlots()
|
|
if self.logLevel > 0: print "numberOfSlots", numberOfSlots
|
|
deckWidth = traverser.getDeckWidth()
|
|
# deck_height = ((deckWidth/4.0) + (slotOffset * numberOfSlots))/4.0
|
|
deck_height = traverser.getDeckLength()
|
|
# offset = -1.5 * deckWidth/4.0
|
|
offset = 0.0
|
|
|
|
# Check if all RHS (even index) slots are disabled
|
|
rhs_disabled = True
|
|
slots = traverser.getSlotList()
|
|
for i in range(len(slots)):
|
|
if i % 2 == 0: # Even index = RHS
|
|
if not slots[i].isDisabled():
|
|
rhs_disabled = False
|
|
break
|
|
|
|
# Check if all LHS (odd index) slots are disabled
|
|
lhs_disabled = True
|
|
for i in range(len(slots)):
|
|
if i % 2 != 0: # Odd index = LHS
|
|
if not slots[i].isDisabled():
|
|
lhs_disabled = False
|
|
break
|
|
if rhs_disabled:
|
|
if traverser.getOrientation() == traverser.HORIZONTAL:
|
|
x_reqd = int(traverser_center.getX() - deckWidth/2.0 - 70.0 )
|
|
y_reqd = int(traverser_center.getY())
|
|
else:
|
|
x_reqd = int(traverser_center.getX() - 25.0)
|
|
y_reqd = int(traverser_center.getY() - deckWidth/2.0 - 25.0)
|
|
elif lhs_disabled:
|
|
if traverser.getOrientation() == traverser.HORIZONTAL:
|
|
x_reqd = int(traverser_center.getX() + deckWidth/2.0 + 20.0)
|
|
y_reqd = int(traverser_center.getY())
|
|
else:
|
|
x_reqd = int(traverser_center.getX() - 25.0)
|
|
y_reqd = int(traverser_center.getY() + deckWidth/2.0 + 15.0)
|
|
else:
|
|
if traverser.getOrientation() == traverser.HORIZONTAL:
|
|
x_reqd = int(traverser_center.getX()) - 25
|
|
y_reqd = int(traverser_center.getY()) + deck_height/2.0 + offset
|
|
else:
|
|
x_reqd = int(traverser_center.getX()) + deck_height/2.0 + 20.0
|
|
y_reqd = int(traverser_center.getY())
|
|
if self.logLevel > 0: print "finished calculating icon position"
|
|
return [x_reqd, y_reqd]
|
|
|
|
def updateCoords1(self, blk, pt_to_try, pt_mid):
|
|
if blk is not None:
|
|
if blk in self.blockPoints:
|
|
if (jmri.util.MathUtil.distance(pt_mid, pt_to_try) < \
|
|
jmri.util.MathUtil.distance(pt_mid, self.blockPoints[blk])):
|
|
self.blockPoints[blk] = pt_to_try
|
|
else:
|
|
self.blockPoints[blk] = pt_to_try
|
|
|
|
def updateCoords(self, blk, xy):
|
|
if blk is not None:
|
|
if blk in self.blockPoints1:
|
|
self.blockPoints1[blk] = jmri.util.MathUtil.midPoint(self.blockPoints1[blk], xy)
|
|
else:
|
|
self.blockPoints1[blk] = xy
|
|
|
|
def getBlockCenterPoints(self, panel):
|
|
self.index = 0
|
|
self.blockPoints1.clear()
|
|
for tsv in panel.getTrackSegmentViews():
|
|
blk = tsv.getBlockName()
|
|
pt1 = panel.getCoords(tsv.getConnect1(), tsv.getType1())
|
|
pt2 = panel.getCoords(tsv.getConnect2(), tsv.getType2())
|
|
|
|
mid = jmri.util.MathUtil.midPoint(pt1, pt2)
|
|
|
|
self.updateCoords(blk, mid)
|
|
|
|
for tov in panel.getLayoutTurnoutAndSlipViews():
|
|
blkA = tov.getBlockName()
|
|
blkB = tov.getBlockBName()
|
|
blkC = tov.getBlockCName()
|
|
blkD = tov.getBlockDName()
|
|
|
|
xyA = tov.getCoordsA()
|
|
xyB = tov.getCoordsB()
|
|
xyC = tov.getCoordsC()
|
|
xyD = tov.getCoordsD()
|
|
|
|
self.updateCoords(blkA, xyA)
|
|
self.updateCoords(blkB, xyB)
|
|
self.updateCoords(blkC, xyC)
|
|
self.updateCoords(blkD, xyD)
|
|
|
|
for lxv in panel.getLevelXingViews():
|
|
blkAC = lxv.getBlockNameAC()
|
|
blkBD = lxv.getBlockNameBD()
|
|
|
|
# A level crossing has 4 points but only two blocks. To prevent both points being in the
|
|
# middle, use the A and D points.
|
|
xyA = lxv.getCoordsA()
|
|
xyD = lxv.getCoordsD()
|
|
|
|
self.updateCoords(blkAC, xyA)
|
|
self.updateCoords(blkBD, xyD)
|
|
|
|
# Handle turntables
|
|
for turntableView in panel.getLayoutTurntableViews():
|
|
turntable = turntableView.getTurntable()
|
|
layoutBlock = turntable.getLayoutBlock()
|
|
if layoutBlock is not None:
|
|
blockName = layoutBlock.getUserName()
|
|
# The center of the turntable is its main coordinate, get it from the View
|
|
centerCoords = turntableView.getCoordsCenter()
|
|
self.updateCoords(blockName, centerCoords)
|
|
|
|
# Handle traversers
|
|
for traverserView in panel.getLayoutTraverserViews():
|
|
traverser = traverserView.getTraverser()
|
|
layoutBlock = traverser.getLayoutBlock()
|
|
if layoutBlock is not None:
|
|
blockName = layoutBlock.getUserName()
|
|
# The center of the traverser is its main coordinate, get it from the View
|
|
centerCoords = traverserView.getCoordsCenter()
|
|
self.updateCoords(blockName, centerCoords)
|
|
|
|
# place the stations at the block nearest the mid-point
|
|
|
|
self.getCenterPointOfNearestBlockToMid(panel)
|
|
|
|
# **************************************************
|
|
# stop icons
|
|
# **************************************************
|
|
def addStopIcons(self, panel):
|
|
for blockName in self.list_of_stopping_points:
|
|
if blockName in self.blockPoints.keys():
|
|
|
|
# print "addStopIcons blockName", blockName
|
|
x = self.blockPoints[blockName].getX()
|
|
y = self.blockPoints[blockName].getY()
|
|
mtSensor = sensors.getSensor('MoveTo' + blockName.replace(" ","_") + '_stored')
|
|
if mtSensor is not None:
|
|
self.addMarkerIcon(panel, mtSensor, blockName, x, y)
|
|
|
|
mpSensor = sensors.getSensor('MoveInProgress' + blockName.replace(" ","_"))
|
|
if mpSensor is not None:
|
|
self.addSmallIcon(panel, mpSensor.getDisplayName(), x - 10, y)
|
|
|
|
# **************************************************
|
|
# occupancy sensor icons and block content labels
|
|
# **************************************************
|
|
def addOccupancyIconsAndLabels(self, panel):
|
|
for blockName in self.blockPoints.keys():
|
|
x = self.blockPoints[blockName].getX() - 10
|
|
y = self.blockPoints[blockName].getY() + 10
|
|
block = blocks.getBlock(blockName)
|
|
if block is not None:
|
|
sensor = block.getSensor()
|
|
if sensor is not None:
|
|
self.addSmallIcon(panel, sensor.getDisplayName(), x, y)
|
|
|
|
y = int(y) - 30 if int(y) > 35 else 5
|
|
self.addBlockContentLabel(panel, block, x, y)
|
|
|
|
# **************************************************
|
|
# control sensor icons and label
|
|
# **************************************************
|
|
def addControlIconsAndLabels(self):
|
|
if (not self.version_number_changed()) and self.dispatcher_system_panel_exists():
|
|
if self.logLevel > 0: print "not adding control Icons and labels"
|
|
return
|
|
|
|
# Create the Dispatcher System control panel
|
|
panel = jmri.jmrit.display.layoutEditor.LayoutEditor("Dispatcher System")
|
|
self.editorManager.add(panel)
|
|
for control in self.controlSensors:
|
|
sensor = sensors.getSensor('IS:DSCT:' + str(control[0]))
|
|
if sensor is not None:
|
|
x = 20 + control[3]
|
|
y = (control[0] * 20) + 0 + control[4]
|
|
self.addMediumIcon(panel, sensor, x, y)
|
|
|
|
x += 20
|
|
self.addTextLabel(panel, control[2], x, y)
|
|
|
|
panel.setSize(300,600)
|
|
panel.setAllEditable(False)
|
|
panel.setVisible(True)
|
|
|
|
def dispatcher_system_panel_exists(self):
|
|
for frame1 in java.awt.Frame.getFrames():
|
|
# print "frame", frame1.getName()
|
|
if frame1.getName() == "Dispatcher System":
|
|
if frame1.isVisible():
|
|
return True
|
|
# print "Dispatcher System Panel does not exist"
|
|
return False
|
|
|
|
# **************************************************
|
|
# small icon
|
|
# **************************************************
|
|
def addSmallIcon(self, panel, sensorName, x, y):
|
|
icn = jmri.jmrit.display.SensorIcon(panel)
|
|
icn.setIcon("SensorStateActive", jmri.jmrit.catalog.NamedIcon("resources/icons/smallschematics/tracksegments/circuit-occupied.gif", "active"));
|
|
icn.setIcon("SensorStateInactive", jmri.jmrit.catalog.NamedIcon("resources/icons/smallschematics/tracksegments/circuit-empty.gif", "inactive"));
|
|
icn.setIcon("BeanStateInconsistent", jmri.jmrit.catalog.NamedIcon("resources/icons/smallschematics/tracksegments/circuit-error.gif", "incons"));
|
|
icn.setIcon("BeanStateUnknown", jmri.jmrit.catalog.NamedIcon("resources/icons/smallschematics/tracksegments/circuit-error.gif", "unknown"));
|
|
|
|
# Assign the sensor and set the location
|
|
icn.setSensor(sensorName)
|
|
icn.setLocation(int(x), int(y))
|
|
|
|
# Add the icon to the layout editor panel
|
|
panel.putSensor(icn)
|
|
|
|
# **************************************************
|
|
# medium icon
|
|
# **************************************************
|
|
def addMediumIcon(self, panel, sensor, x, y):
|
|
icn = jmri.jmrit.display.SensorIcon(panel)
|
|
icn.setIcon("SensorStateActive", jmri.jmrit.catalog.NamedIcon("resources/icons/mediumschematics/LEDs/AMBERLED.gif", "active"));
|
|
icn.setIcon("SensorStateInactive", jmri.jmrit.catalog.NamedIcon("resources/icons/mediumschematics/LEDs/GRAYLED.gif", "inactive"));
|
|
icn.setIcon("BeanStateInconsistent", jmri.jmrit.catalog.NamedIcon("resources/icons/mediumschematics/LEDs/REDLED.gif", "incons"));
|
|
icn.setIcon("BeanStateUnknown", jmri.jmrit.catalog.NamedIcon("resources/icons/mediumschematics/LEDs/REDLED.gif", "unknown"));
|
|
|
|
# Assign the sensor and set the location
|
|
icn.setSensor(sensor.getDisplayName())
|
|
icn.setLocation(int(x), int(y))
|
|
|
|
# Add the icon to the layout editor panel
|
|
panel.putSensor(icn)
|
|
|
|
# **************************************************
|
|
# marker icon
|
|
# **************************************************
|
|
def addMarkerIcon(self, panel, sensor, blockName, x, y):
|
|
icn = jmri.jmrit.display.SensorIcon(panel)
|
|
icn.setIcon("SensorStateActive", jmri.jmrit.catalog.NamedIcon("resources/icons/markers/loco-green.gif", "active"));
|
|
icn.setIcon("SensorStateInactive", jmri.jmrit.catalog.NamedIcon("resources/icons/markers/loco-red.gif", "inactive"));
|
|
icn.setIcon("BeanStateInconsistent", jmri.jmrit.catalog.NamedIcon("resources/icons/markers/loco-yellow.gif", "incons"));
|
|
icn.setIcon("BeanStateUnknown", jmri.jmrit.catalog.NamedIcon("resources/icons/markers/loco-gray.gif", "unknown"));
|
|
if len(blockName) > 9:
|
|
icn.setText(blockName[:11])
|
|
icn.getPopupUtility().setFontSize(9)
|
|
else:
|
|
icn.setText(blockName[:9])
|
|
icn.getPopupUtility().setFontSize(11)
|
|
|
|
|
|
icn.setTextActive(Color.RED)
|
|
icn.setTextInActive(Color.YELLOW)
|
|
icn.setTextInconsistent(Color.BLACK)
|
|
icn.setTextUnknown(Color.BLUE)
|
|
|
|
|
|
|
|
# Assign the sensor and set the location
|
|
icn.setSensor(sensor.getDisplayName())
|
|
icn.setLocation(int(x), int(y))
|
|
|
|
# Add the icon to the layout editor panel
|
|
panel.putSensor(icn)
|
|
|
|
# **************************************************
|
|
# text label
|
|
# **************************************************
|
|
def addTextLabel(self, panel, text, x, y):
|
|
label = jmri.jmrit.display.PositionableLabel(text, panel)
|
|
label.setLocation(int(x), int(y))
|
|
label.setSize(label.getPreferredSize().width, label.getPreferredSize().height);
|
|
label.setDisplayLevel(4)
|
|
panel.putItem(label)
|
|
|
|
# **************************************************
|
|
# block content label
|
|
# **************************************************
|
|
def addBlockContentLabel(self, panel, block, x, y):
|
|
label = jmri.jmrit.display.BlockContentsIcon(block.getDisplayName(), panel)
|
|
label.setBlock(block.getDisplayName())
|
|
label.setLocation(int(x), int(y))
|
|
panel.putItem(label)
|
|
|
|
def saveForwardStoppingSensors(self):
|
|
forward_stop_sensors = \
|
|
[["section: " , str(section.getUserName()), " stop sensor: " , str(section.getForwardStoppingSensor().getUserName())] \
|
|
for section in sections.getNamedBeanSet() if section.getForwardStoppingSensor() != None]
|
|
self.write_list(forward_stop_sensors)
|
|
|
|
def retrieveForwardStoppingSensors(self):
|
|
forward_stop_sensors = self.read_list()
|
|
if forward_stop_sensors != []:
|
|
[sections.getSection(section_name).setForwardStoppingSensorName(forward_stopping_sensor_name) \
|
|
for [sn_prompt, section_name, fss_prompt, forward_stopping_sensor_name] in forward_stop_sensors \
|
|
if forward_stop_sensors is not [] and sections.getSection(section_name) is not None]
|
|
|
|
def directory(self):
|
|
path = jmri.util.FileUtil.getUserFilesPath() + "dispatcher" + java.io.File.separator + "forwardStoppingSensors"
|
|
if not os.path.exists(path):
|
|
os.makedirs(path)
|
|
return path + java.io.File.separator
|
|
def write_list(self, a_list):
|
|
# store list in binary file so 'wb' mode
|
|
file = self.directory() + "forwardStoppingSensors.txt"
|
|
#print "block_info" , a_list
|
|
#print "file" +file
|
|
with open(file, 'wb') as fp:
|
|
for items in a_list:
|
|
i = 0
|
|
for item in items:
|
|
fp.write('%s' %item)
|
|
if i < 3 : fp.write(",")
|
|
i+=1
|
|
fp.write('\n')
|
|
|
|
# Read list to memory
|
|
def read_list(self):
|
|
# for reading also binary mode is important
|
|
file = self.directory() + "forwardStoppingSensors.txt"
|
|
n_list = []
|
|
try:
|
|
with open(file, 'rb') as fp:
|
|
for line in fp:
|
|
x = line[:-1]
|
|
#print x
|
|
y = x.split(",")
|
|
#print "y" , y
|
|
n_list.append(y)
|
|
return n_list
|
|
except:
|
|
return []
|
|
|
|
class DisplayProgress:
|
|
def __init__(self):
|
|
#labels don't seem to work. This is the only thing I could get to work. Improvements welcome
|
|
self.frame1 = JFrame('Starting Processing!', defaultCloseOperation=JFrame.DISPOSE_ON_CLOSE, size=(500, 50), locationRelativeTo=None)
|
|
self.frame1.setVisible(True)
|
|
|
|
def Update(self,msg):
|
|
self.frame1.setTitle(msg)
|
|
|
|
def killLabel(self):
|
|
self.frame1.setVisible(False)
|
|
self.frame1 = None
|
|
|
|
|
|
class Query:
|
|
def customQuestionMessage2str(self, msg, title, opt1, opt2):
|
|
self.CLOSED_OPTION = False
|
|
options = [opt1, opt2]
|
|
s = JOptionPane.showOptionDialog(None,
|
|
msg,
|
|
title,
|
|
JOptionPane.YES_NO_OPTION,
|
|
JOptionPane.QUESTION_MESSAGE,
|
|
None,
|
|
options,
|
|
options[1])
|
|
if s == JOptionPane.CLOSED_OPTION:
|
|
self.CLOSED_OPTION = True
|
|
return
|
|
if s == JOptionPane.YES_OPTION:
|
|
s1 = opt1
|
|
else:
|
|
s1 = opt2
|
|
return s1
|
|
|
|
def displayMessage(self, msg, title = ""):
|
|
self.CLOSED_OPTION = False
|
|
s = JOptionPane.showOptionDialog(None,
|
|
msg,
|
|
title,
|
|
JOptionPane.YES_NO_OPTION,
|
|
JOptionPane.PLAIN_MESSAGE,
|
|
None,
|
|
["OK"],
|
|
None)
|
|
#JOptionPane.showMessageDialog(None, msg, 'Message', JOptionPane.WARNING_MESSAGE)
|
|
if s == JOptionPane.CLOSED_OPTION:
|
|
self.CLOSED_OPTION = True
|
|
return
|
|
return s
|