############################################################################### # # class MoveTrain # Calls dispatcher to e train from one station to another # given engine and start and end positions # ############################################################################### import os import java import jmri import math import time from javax.swing import JTable, JScrollPane, JFrame, JPanel, JComboBox, BorderFactory, DefaultCellEditor, JLabel, UIManager, SwingConstants, JFileChooser from javax.swing.table import TableCellRenderer, DefaultTableCellRenderer from java.awt.event import MouseAdapter,MouseEvent, WindowListener, WindowEvent from java.awt import GridLayout, Dimension, BorderLayout, Color from javax.swing.table import AbstractTableModel, DefaultTableModel from java.lang.Object import getClass from jmri.jmrit.logix import WarrantPreferences import jarray from javax.swing.event import TableModelListener, TableModelEvent from javax.swing.filechooser import FileNameExtensionFilter from org.apache.commons.io import FilenameUtils from java.io import File #, defaultTableModel global MoveTrain_index MoveTrain_index = 0 class MoveTrain(jmri.jmrit.automat.AbstractAutomaton): global trains_dispatched global trains global time_last_train def __init__(self, station_from_name, station_to_name, train_name, graph, stop_mode = None, mode = "not_scheduling", route = None): self.logLevel = 0 if self.logLevel > 0: print "station_from_name", station_from_name, "station_to_name",station_to_name, "train_name", train_name, "stop_mode", stop_mode self.station_from_name = station_from_name self.station_to_name = station_to_name self.train_name = train_name self.graph = graph self.route = route # if there is a stop sensor at the last station, get the stop mode at the last station if it has been set up if self.route != None: self.stop_mode = self.get_route_location_stop_mode(station_to_name) else: self.stop_mode = "" self.mode = mode def setup(self): return True def handle(self): # move between stations in the thread if self.logLevel > 1: print"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" if self.logLevel > 1: print "move between stations in the thread" if self.logLevel > 1: print"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" result = self.move_between_stations(self.station_from_name, self.station_to_name, self.train_name, self.graph, self.mode) return False def get_route_location_stop_mode(self, station_to_name): route_location = self.route.getLastLocationByName(station_to_name) if self.logLevel > 0: print "get_stop_mode" , "route location", route_location comment = route_location.getComment() stop_mode = self.find_between(comment, "[stopMode-", "-stopMode]") if self.logLevel > 0: print "routeLocation stop_mode", stop_mode return stop_mode def find_between(self, s, first, last): try: start = s.index(first) + len(first) end = s.index(last, start) return s[start:end] except ValueError: return "" def move_between_stations(self, station_from_name, station_to_name, train_name, graph, mode = "not_scheduling"): global trains global scheduling_margin_gbl global fast_clock_rate global MoveTrain_index global trains_dispatched MoveTrain_index += 1 self.index = MoveTrain_index strindex = str(self.index) + " " * 5 #make debugging easier to understand by indenting and prefixing by the train index if self.logLevel > 0: print "" if self.logLevel > 0: print "" if self.logLevel > 0: print strindex + "&&&&&&&&&&&&&&&&& start move_between_stations &&&&&&&&&&&&&&&&&" , strindex if self.logLevel > 0: print strindex + "*********************************************" if self.logLevel > 0: print strindex + "move_between_stations" if self.logLevel > 0: print strindex + "Moving from " + station_from_name + " to " + station_to_name if self.logLevel > 0: print strindex + "*********************************************" i = 0 if self.logLevel > 0: print strindex + "checking train in start block" # print strindex + "move_between_stations a" if self.logLevel > 0: print strindex + "train is in start block" #need to look up the required transit in the graph StateVertex_start = station_from_name StateVertex_end = station_to_name for e in graph.edgeSet(): if self.logLevel > 1: print (graph.getEdgeSource(e) + " --> " + graph.getEdgeTarget(e)) if self.logLevel > 0: print strindex + "calling shortest path", StateVertex_start, StateVertex_end # List all vertices if self.logLevel > 0: for vertex in graph.vertexSet(): print("Vertex:", vertex) paths = DijkstraShortestPath.findPathBetween(graph, StateVertex_start, StateVertex_end) # print strindex + "move_between_stations b" if paths == None: if self.logLevel > 0: print strindex + "cannot find shortest path, paths found is empty" # print strindex + "end of move between ", station_from_name, station_to_name return if self.logLevel > 1: print strindex + "graph", graph if self.logLevel > 1: print strindex + "paths", paths if self.logLevel > 1: print strindex + "returned from shortest path" if self.logLevel > 0: print strindex + "in move_between_stations trains = ", trains, "train_name = ", train_name if train_name in trains: train = trains[train_name] else: if self.logLevel > 0: print strindex + "in case of key error: trains", trains if self.logLevel > 0: print strindex + "******" if self.logLevel > 0: print strindex + "train_name", train_name, "trains", trains if self.logLevel > 0: print strindex + "************Not Moving Train************" return if self.logLevel > 1: print strindex + "train" , train, "train_name", train_name penultimate_block_name = train["penultimate_block_name"] if self.logLevel > 1: print strindex + "penultimate_block_name" , penultimate_block_name previous_edge = train["edge"] if self.logLevel > 2: print 'move_between_stations train["direction"]' , train["direction"] previous_direction_from = train["direction"] count_path = 0 # print strindex + "move_between_stations c" if paths == None or paths == []: if self.logLevel > 0: print strindex + "1Error cannot find shortest path. restart the system. " + \ "The stop dispatcher system routine does not work properly with multiple layout panels. Sorry" return # if we have a problem in one of the paths we set the following to False, and jump out of for statement call_next_edge_in_paths = True for e in paths: if call_next_edge_in_paths == False: break # print strindex + "move_between_stations d" # need to check whether: # last block of previous edge and current first block # are the same # if the same the train must change direction. as we are going in and out the same path # if self.logLevel > 0: print strindex + "********************************" previous_edge = train["edge"] penultimate_block_name = train["penultimate_block_name"] current_edge = e neighbor_name = e.getItem("neighbor_name") if self.logLevel > 0: print train if self.logLevel > 0: print strindex + "neighbor_name = ", neighbor_name if self.logLevel > 0: print strindex + "train penultimate_block_name" , penultimate_block_name BlockManager = jmri.InstanceManager.getDefault(jmri.BlockManager) previous_direction_from = train["direction"] # print strindex + "previous direction from", previous_direction_from # wait for the allocated time speech_reqd = self.speech_required_flag() # print strindex + "move_between_stations e" # wait in station and announce the wait time (announcement only for debugging) transit_direction = previous_direction_from time_to_stop_in_station = self.get_time_to_stop_in_station(e, transit_direction) t = time_to_stop_in_station / 1000 msg = "started waiting for " + str(int(t)) + " seconds" if self.logLevel > 0: self.speak(msg) self.waitMsec(int(time_to_stop_in_station)) msg = "finished waiting for " + str(int(t)) + " seconds" if self.logLevel > 0: self.speak(msg) iter = 0 result = False # try to call dispatch until success (result of calling dispatch is True (success) or False (failure)) while result == False: # in case the train moves since the last try of calling for the dispatch (and we have a failure) # get the current location of the train at the beginning of the while loop # if str(train_name) in trains_dispatched: # print strindex + "train is dispatching trying again" + "trains_dispatched", trains_dispatched: # self.waitMsec(500) # continue # else: # print strindex + "train is not dispatching continuing" train = trains[train_name] previous_edge = train["edge"] if self.logLevel > 0: print strindex + "previous_edge " + str(previous_edge) penultimate_block_name = train["penultimate_block_name"] previous_block = BlockManager.getBlock(previous_edge.getItem("penultimate_block_name")) # print strindex + "previous_block", previous_block.getUserName() current_block = BlockManager.getBlock(previous_edge.getItem("last_block_name")) # print strindex + "current_block", current_block.getUserName() next_block = BlockManager.getBlock(current_edge.getItem("second_block_name")) # print strindex + "next_block", next_block.getUserName() previous_direction_from = train["direction"] transit_direction = previous_direction_from # move_between_stations if self.logLevel > 0: print strindex + "previous transit_direction ", transit_direction if self.logLevel > 0: print strindex + "setting direction iterno", iter [train["direction"], transit_instruction] = self.set_direction(train, previous_block, current_block, next_block, transit_direction, self.index) # get the new train_direction_from transit_direction = train["direction"] # need to store if we change direction in case we have to redo the command if transit_direction != previous_direction_from: stored_transit_instruction = "change" else: stored_transit_instruction = "no_change" if self.logLevel > 0: print strindex + "new transit_direction " + transit_direction if self.logLevel > 0: print strindex + "+++++++++++++++++++++++++++" if self.logLevel > 0: print strindex + "calling self.move iterno", iter result = self.move(e, transit_direction, transit_instruction, train_name, mode, self.index) if self.logLevel > 0: print strindex + "called self.move iterno", iter, "result", result # result is True (success) or False (failure) # if result is false we will try again as we are in a loop # if we are not scheduling, we will try once before allowing the operator to specify whether we are giving up # if we are scheduling we try until the scheduling margin is reached if self.logLevel > 0: print strindex + "returned from self.move, result = ", result if result == False: # we will repeat, sot put everything back to original state if stored_transit_instruction == "change": if self.logLevel > 0: print strindex + "reverting changed direction iterno", iter if train["direction"] == "forward": train["direction"] = "reverse" else: train["direction"] = "forward" if self.logLevel > 0: print strindex + "mode", mode if mode == "not_scheduling": if iter >= 1: #allow one retry without prompting msg = "Failure1 to dispatch train " + train_name + " retrying moving from " + station_from_name + " to " + station_to_name title = "" opt1 = "try again" opt2 = "cancel" reply = OptionDialog().customQuestionMessage2str(msg, title, opt1, opt2) if opt1: iter = 0 else: result = True # break from while loop else: # print strindex + "--" + self.train_name + " calling doDispatch" self.waitMsec(1000) # wait 1 sec # wait for the scheduling margin (specified in fast minutes) # convert scheduling margin to seconds scheduling_margin_sec = int((float(scheduling_margin_gbl) / float(str(fast_clock_rate))) * 60.0) # fast minutes # print strindex + "scheduling_margin_sec", scheduling_margin_sec if iter > scheduling_margin_sec: if self.logLevel > 0: print strindex + "waited", iter+1, "secs, could not schedule train and gave up" result = True # break from while loop # we do not want to call the next edge in the paths call_next_edge_in_paths = False else: if self.logLevel > 0: print strindex + "waited", iter+1, "secs but could not schedule train", train # end of while. repeat again if result is false and call dispatch again if self.logLevel > 0: print strindex + "called self.move iterno", iter if self.logLevel > 0: print strindex + "++++++++++++++++++++++++++++++++++" # store the current edge for next move #store current edge information in train train["edge"] = e train["penultimate_block_name"] = e.getItem("penultimate_block_name") # count the paths in count_path +=1 if self.logLevel > 0: print strindex + "transit finished, removing train from dispatch list" + str(trains_dispatched) if str(train_name) in trains_dispatched: # print "str(train_name) in trains_dispatched" trains_dispatched.remove(str(train_name)) if self.logLevel > 0: print strindex + "removed from trains_dispatched", str(trains_dispatched) if self.logLevel > 0: print strindex + "&&&&&&&&&&&&&&&&& end move_between_stations &&&&&&&&&&&&&&&&&", self.index def set_direction(self, train, previous_block, current_block, next_block, previous_direction_from, index = 0): # global train strindex = str(index) + " " * 10 #make debugging easier to understand by indenting if self.logLevel > 2: print "set_direction1: previous_direction_from", previous_direction_from # We have two cases for the direction to be changed: # 1) we have a back and forth situation where we can check that the previous_block == next_block # 2) we reverse and go through a point. there will be no through path from the previous_block to the next next_block # # these two cases are not exclusive. # print "set_direction" transit_instruction = "same" if self.logLevel > 0: print strindex + "previous_block", previous_block.getUserName(), "current", current_block.getUserName(), "next", next_block.getUserName() if previous_block == next_block: if self.logLevel > 0: print strindex + "previous_block == next_block", previous_block == next_block, "so changing direction" transit_instruction = "change" # check if current block is a turntable for panel in jmri.util.JmriJFrame.getFrameList(): if isinstance(panel, jmri.jmrit.display.layoutEditor.LayoutEditor): for turntable in panel.getLayoutTurntables(): if turntable.getLayoutBlock() is not None: if (turntable.getLayoutBlock().getBlock() == current_block) and (current_block != next_block): if self.logLevel > 0: print strindex + "current_block is a turntable, so changing direction" transit_instruction = "change" break # check if current block is a traverser for panel in jmri.util.JmriJFrame.getFrameList(): if isinstance(panel, jmri.jmrit.display.layoutEditor.LayoutEditor): for traverser in panel.getLayoutTraversers(): if traverser.getLayoutBlock() is not None: if (traverser.getLayoutBlock().getBlock() == current_block) and (current_block != next_block): # Found the traverser object entry_slot_index = -1 exit_slot_index = -1 slot_list = traverser.getSlotList() for i in range(len(slot_list)): slot = slot_list[i] ts = slot.getConnect() if ts is not None and ts.getLayoutBlock() is not None: connected_block = ts.getLayoutBlock().getBlock() if connected_block == previous_block: entry_slot_index = i if connected_block == next_block: exit_slot_index = i if entry_slot_index != -1 and exit_slot_index != -1 and ((entry_slot_index % 2) == (exit_slot_index % 2)): if self.logLevel > 0: print strindex + "current_block is a traverser and slots are on the same side, so changing direction" transit_instruction = "change" break # Found the traverser, no need to check others LayoutBlockManager=jmri.InstanceManager.getDefault(jmri.jmrit.display.layoutEditor.LayoutBlockManager) current_layout_block = LayoutBlockManager.getLayoutBlock(current_block) # don't need this as previous block == next block is sufficient # if not current_layout_block.validThroughPath(previous_block, next_block): # print ("current_layout_block.validThroughPath", # current_layout_block.validThroughPath(previous_block, next_block), "so changing direction") # transit_instruction = "change" if transit_instruction == "change": if previous_direction_from == "forward": transit_direction = "reverse" else: transit_direction = "forward" if self.logLevel > 2: print strindex + "set_direction1: transit_direction", transit_direction else: transit_direction = previous_direction_from if self.logLevel > 2: print strindex + "set_direction1: transit_direction2", transit_direction train["direction"] = transit_direction # print "transit_direction", transit_direction previous_direction_from = transit_direction return [transit_direction, transit_instruction] def check_train_in_start_block(self, train_to_move, blockName): # print "check_train_in_start_block" # print "checking " , train_to_move, " in " , blockName block = blocks.getBlock(blockName) if self.blockOccupied(block): # print " block Occupied ", self.blockOccupied(block), " value ", block.getValue() if block.getValue() == train_to_move: return True else: startBlock = block.getUserName() # print "trying to move from blockName" , blockName, "but not occupied by", "train_to_move", train_to_move blockName = [block.getUserName() for block in blocks.getNamedBeanSet() if block.getValue() == train_to_move] if blockName != []: blockName = blockName[0] # print "train", train_to_move, "actually in" , blockName return False else: blockName = "train not in any block" #as the block block.setValue(train_to_move) # print "train", train_to_move, "reset in" , blockName return True else: # print "train_to_move", train_to_move, "not in" , blockName blockName = [block for block in blocks.getNamedBeanSet() if block.getValue() == train_to_move] if blockName != []: blockName = blockName[0] else: blockName = "train not in any block" # print "train_to_move", train_to_move, "in" , blockName return False def blockOccupied(self, block): # print "blockOccupied" if block.getState() == ACTIVE: state = True else: state = False return state def get_time_to_stop_in_station(self, edge, direction): if direction == "forward": filename_fwd = self.get_filename(edge, "fwd") trainInfo_fwd = jmri.jmrit.dispatcher.TrainInfoFile().readTrainInfo(filename_fwd) if trainInfo_fwd is None: OptionDialog().displayMessage("Route graph out of date. Regenerate Dispatcher System") return 0 # print "type trainInfo_fwd", type (trainInfo_fwd) station_wait_time = trainInfo_fwd.getWaitTime() else: filename_rvs = self.get_filename(edge, "rvs") # print "filename_rvs", filename_rvs, "edge", edge trainInfo_rvs = jmri.jmrit.dispatcher.TrainInfoFile().readTrainInfo(filename_rvs) if trainInfo_rvs is None: OptionDialog().displayMessage("Route graph out of date. Regenerate Dispatcher System") return 0 # print "type trainInfo_rvs", type (trainInfo_rvs) station_wait_time = trainInfo_rvs.getWaitTime() if station_wait_time != None: return math.floor(float(station_wait_time+0)) * 1000 # set in milli secs else: return 0 def is_integer(self, n): try: if n == None: return False float(n) except ValueError: return False else: return float(n).is_integer() def announce1(self, e, direction, instruction, train): # print "announce1" to_name = e.getTarget() from_name = e.getSource() speech_reqd = self.speech_required_flag() self.announce( from_name, to_name, speech_reqd, direction, instruction) def move(self, e, direction, instruction, train_name, mode="not_scheduling" , index = 0): strindex = str(index) + " " * 10 # make debugging easier to understand by indenting # print strindex +"move" if self.logLevel > 0: print strindex +"++++++++++++++++++++++++" if self.logLevel > 0: print strindex +"path" , e if self.logLevel > 0: print strindex +"calling move: Target", e.getTarget(), "Source", e.getSource(),"Train", train_name if self.logLevel > 0: print strindex +"++++++++++++++++++++++++" to_name = e.getTarget() from_name = e.getSource() sensor_move_name = "MoveInProgress"+to_name.replace(" ","_") self.set_sensor(sensor_move_name, "active") speech_reqd = self.speech_required_flag() #self.announce( from_name, to_name, speech_reqd, direction, instruction) # now done when train arrives in platfor instead of when leaving if self.logLevel > 0: print strindex +"calling move", train, from_name, to_name if mode == "not_scheduling": self.waitMsec(1000) # wait for train to stop dispatching we don't want to start another train before it has stopped properly if self.train_is_dispatching(train_name, index): self.wait_till_train_stops_dispatching(train_name, index) if self.logLevel > 0: print strindex + "waited till train stops dispatching, trying again with new position" # print strindex + "train is dispatching, trying again with new position" # self.waitMsec(500) return False else: if self.logLevel > 0: print strindex + "train is not dispatching" else: if self.logLevel > 0: print "train is scheduling" # if mode == "scheduling": # waited_till_train_stops_dispatching = self.wait_till_train_stops_dispatching(train_name, index) #it might be already doing a dispatch # if waited_till_train_stops_dispatching: # # need to try again with new train position # print strindex +"waited_till_train_stops_dispatching not calling dispatch" # return False if self.logLevel > 0: print strindex +"calling dispatch" if self.logLevel > 0: print strindex + "trains_dispatched", trains_dispatched result = self.call_dispatch(e, direction, train_name, mode, index) if self.logLevel > 0: print strindex +"exit call_dispatch" , result if self.logLevel > 0: print strindex + "trains_dispatched", trains_dispatched self.set_sensor(sensor_move_name, "inactive") if result == True: # print strindex +"result from calling move is True!!", train, from_name, to_name # Wait for the Active Trains List to not have the train we wish to start in it self.wait_till_train_stops_dispatching(train_name, index) self.set_sensor(sensor_move_name, "inactive") self.report_train_state(train_name) # just for debugging if self.logLevel > 0: print strindex +("+++++ sensor " + sensor_move_name + " inactive") else: # print strindex +"result from calling move is False!!", train, from_name, to_name self.set_sensor(sensor_move_name, "inactive") if self.logLevel > 0: print strindex +"****** finished moving train: called move *******" return result def report_train_state(self, train_name): train = trains[train_name] direction = train["direction"] if self.logLevel > 1: print "train direction" , direction def train_is_dispatching(self, train_name, index): strindex = str(index) + " " * 10 #make debugging easier to understand by indenting if self.logLevel > 0: print strindex + "checking if train is dispatching", train_name DF = jmri.InstanceManager.getDefault(jmri.jmrit.dispatcher.DispatcherFrame) java_active_trains_list = DF.getActiveTrainsList() java_active_trains_Arraylist= java.util.ArrayList(java_active_trains_list) active_train_names_list = [str(t.getTrainName()) for t in java_active_trains_Arraylist] if train_name in active_train_names_list: return True else: return False def wait_till_train_stops_dispatching(self, train_name, index = 0): strindex = str(index) + " " * 10 #make debugging easier to understand by indenting # print strindex + "wait_till_train_stops_dispatching", train_name DF = jmri.InstanceManager.getDefault(jmri.jmrit.dispatcher.DispatcherFrame) java_active_trains_list = DF.getActiveTrainsList() java_active_trains_Arraylist= java.util.ArrayList(java_active_trains_list) active_train_names_list = [str(t.getTrainName()) for t in java_active_trains_Arraylist] while train_name in active_train_names_list: self.waitMsec(500) # print strindex + train_name + "in active train list" java_active_trains_list = DF.getActiveTrainsList() java_active_trains_Arraylist= java.util.ArrayList(java_active_trains_list) active_train_names_list = [str(t.getTrainName()) for t in java_active_trains_Arraylist] if self.logLevel > 0: print (strindex + "+++++ train " + train_name + " stopped dispatching" ) return def speech_required_flag(self): # print "speech_required_flag" self.sound_sensor = sensors.getSensor("soundSensor") if self.sound_sensor is None: OptionDialog().displayMessage("No sound Sensor set up") return None sound_state = self.sound_sensor.getKnownState() if self.logLevel > 1: print sound_state,ACTIVE if sound_state == ACTIVE: sound_flag = True else: sound_flag = False return sound_flag def call_dispatch(self, e, direction, train, mode="not_scheduling", index = 0): global scheduling_margin_gbl, fast_clock_rate global check_action_route_flag global check_route_flag global trains_dispatched strindex = str(index) + " " * 15 #make debugging easier to understand by indenting if self.logLevel > 0: print strindex + "+++++++++++++++call_dispatch++++++++++++++++ mode:", train, mode # for information only if self.logLevel > 1: print strindex + " in dispatch" to_name = e.getTarget() from_name = e.getSource() if self.logLevel > 1: print ("in call_dispatch: move from " + from_name + " to " + to_name) # set traininfo filename if direction == "forward": filename = self.get_filename(e, "fwd") else: filename = self.get_filename(e, "rvs") if self.logLevel > 1: print strindex + "filename = ", filename, "direction = " , direction # print strindex + "call_dispatch a" check_route_active_flag = sensors.getSensor("checkRouteSensor").getKnownState() if check_route_active_flag == ACTIVE: check_route_flag = True else: check_route_flag = False if self.logLevel > 0: print strindex + "check_route_flag", check_route_flag # initialise globals to False if not set if 'check_action_route_flag' not in globals(): check_action_route_flag = False # wait for blocks to be clear before allocating (if required) if check_route_flag == True or check_action_route_flag == True: # can ask for route to be checked globally or in action # print strindex + "call_dispatch b1" # print strindex + "checking route is clear", from_name self.wait_route_is_clear(filename, from_name, train) t = trains[train] #train is train_name t["allocating"] = True if self.logLevel > 0: print self.train_name, "route", filename, "is clear" if self.logLevel > 0: print strindex + "appending trains_dispatched", trains_dispatched if str(train) not in trains_dispatched: #have to checl because added each transit of route trains_dispatched.append(str(train)) if self.logLevel > 0: print strindex + "trains_dispatched", trains_dispatched # run dispatch if self.logLevel > 0: print strindex + "%%%%%%%%%calling doDispatch" result = self.doDispatch(filename, "ROSTER", train, mode, index) if self.logLevel > 0: print strindex + "%%%%%%%%%exiting doDispatch A" if self.logLevel > 0: print strindex + "trains_dispatched", trains_dispatched # # when scheduling the dispatch is normally not called until the previous dispatch is complete # # we will keep this in for now even though better in calling routine # # definitely cannot recall doDispatch from here in non-scheduling mode # # if mode != "not_scheduling and result == False": # i.e. if scheduling # print strindex + "scheduling mode code" # print strindex + "mode" , mode # # keep repeating until the scheduling margin is reached # iter = 0 # while result == False: # # print strindex + "--" + self.train_name + " calling doDispatch" # self.waitMsec(1000) # wait 1 sec # # wait for the scheduling margin (specified in fast minutes) # # convert scheduling margin to seconds # scheduling_margin_sec = int((float(scheduling_margin_gbl) / float(str(fast_clock_rate))) * 60.0) # fast minutes # # print strindex + "scheduling_margin_sec", scheduling_margin_sec # if iter > scheduling_margin_sec: # if self.logLevel > 0: print strindex + "waited", iter+1, "secs, could not schedule train and gave up" # return result # else: # if self.logLevel > 0: print strindex + "waited", iter+1, "secs but could not schedule train", train # # result = self.doDispatch(filename, "ROSTER", train, mode, index) # if self.logLevel > 0: print strindex + "exiting doDispatch B" # iter += 1 #return result if self.logLevel > 0: print strindex + "+++++++++++++exit call_dispatch+++++++++++++++++ result", result if self.logLevel > 0: print strindex + "trains_dispatched", trains_dispatched return result def initialise_if_not_set(self, global_name, state): if 'global_name' not in globals(): global_name = state def get_filename(self, e, suffix): # print "get_filename" # suffix is "fwd" or "rvs" # e is edge from_station_name = g.g_express.getEdgeSource(e) to_station_name = g.g_express.getEdgeTarget(e) neighbor_name = e.getItem("neighbor_name") index = e.getItem("index") filename = "From " + str(from_station_name) + " To " + str(to_station_name) + " Via " + str(neighbor_name) + " " + str(index) filename = filename.replace(" ", "_") filename = filename + "_" + suffix + ".xml" return filename # Dispatch (, [USER | ROSTER | OPERATIONS >, def doDispatch(self, traininfoFileName, type, train_name, mode = "not_scheduling", index = 0): global trains_dispatched strindex = str(index) + " " * 20 #make debugging easier to understand by indenting if self.logLevel > 0: print strindex + "doDispatch" if self.logLevel > 0: print strindex + "trains_dispatched", trains_dispatched DF = jmri.InstanceManager.getDefault(jmri.jmrit.dispatcher.DispatcherFrame) if self.logLevel > 1: print strindex + "traininfoFileName",traininfoFileName if train_name in trains: train = trains[train_name] else: if self.logLevel > 0: print strindex + "train", train_name , "cannot be dispatched", "trains", trains return False self.trainInfo = jmri.jmrit.dispatcher.TrainInfoFile().readTrainInfo(traininfoFileName) self.modify_trainInfo(train_name) # sets the speed factor and other train dependent factors transit_name = self.trainInfo.getTransitName() self.transit_name = transit_name # allow calling routine to use transit_name #print strindex + "traininfoFileName", traininfoFileName jmri.jmrit.dispatcher.TrainInfoFile().writeTrainInfo(self.trainInfo, traininfoFileName) # print strindex + "__" + train_name + " calling loadTrainFromTrainInfo" # print strindex + "DF.dispatcherSystemSchedulingInOperation before", DF.dispatcherSystemSchedulingInOperation DF.dispatcherSystemSchedulingInOperation = True # to inhibit error message when train started but not in station # print strindex + "DF.dispatcherSystemSchedulingInOperation", DF.dispatcherSystemSchedulingInOperation if mode != "not_scheduling": # == scheduling # if self.logLevel > 0: print strindex + "__________________________Start__" + self.train_name + "__transit: " + transit_name if self.logLevel > 0: print "__________________________Start__" + self.train_name + "__transit: " + transit_name else: if self.logLevel > 0: print strindex + "_Start__" + self.train_name + "__transit: " + transit_name # run the train, setting the flag that the train is doing a dispatch result = DF.loadTrainFromTrainInfo(self.trainInfo, type, train_name) if self.logLevel > 0: print strindex + "loaded returning with code ", result if self.logLevel > 0: print strindex + "trains_dispatched", trains_dispatched if result == 0: # print strindex + "--" + self.train_name + " called doDispatch; transit name: " + transit_name self.set_whether_to_stop_at_sensor(DF) train["allocating"] = False # this flag is used when checking to see whether path for dispatch is clear if result == -1: if self.logLevel > 0: print strindex + "did not run train ", train_name , "aborting: result from loading train:" , result # did not work properly # # delete the transit so can try loading the transit again # self.trainInfo = jmri.jmrit.dispatcher.TrainInfoFile().readTrainInfo(traininfoFileName) # transit_name = self.trainInfo.getTransitName() # active_train_list = [active_train for active_train in DF.getActiveTrainsList() \ # if active_train.getTransitName() == transit_name] # if active_train_list == []: # active_train = None # else: # active_train = active_train_list[0] # print strindex + "terminating active_train", active_train, "train", train_name, "active_train_list", active_train_list # DF.terminateActiveTrain(active_train, True, False) # if train_name in trains: # trains.pop(train_name) return False #No train allocated else: DF = None if mode != "not_scheduling": # == scheduling if self.logLevel > 0: print strindex + "__________________________End____" + self.train_name + "__transit: " + transit_name else: if self.logLevel > 0: print strindex + "_End____" + self.train_name + "__transit: " + transit_name return True def get_train_length(self, new_train_name): # print "get_train_length" EngineManager=jmri.InstanceManager.getDefault(jmri.jmrit.operations.rollingstock.engines.EngineManager) engineRoad = "Set by Dispatcher System" engineNumber = new_train_name engine = EngineManager.newRS(engineRoad, engineNumber) # get the current length of the engine default = "10" current_length = engine.getLength() if current_length == "0": current_length = default return [engine, current_length] def get_train_speed_factor(self, new_train_name): # print "get_train_speed_factor" EngineManager=jmri.InstanceManager.getDefault(jmri.jmrit.operations.rollingstock.engines.EngineManager) engineRoad = "Set by Dispatcher System" engineNumber = new_train_name engine = EngineManager.newRS(engineRoad, engineNumber) # get the current speed factor of the engine default = "100" # percentage comment = engine.getComment() split_comment = [] if "speed factor" in comment: split_comment = comment.split(" ") index = split_comment.index("speed") # print "len(split_comment)", len(split_comment), "index + 2", index + 2 if len(split_comment) > index + 2: speed_factor = split_comment[index+2] else: speed_factor = default else: speed_factor = default return [engine, speed_factor] def get_stopping_length_fraction(self): transit_name = self.trainInfo.getTransitName() # this has _fwd or _rvs at end. Remove these to get edge edge = transit_name.replace("_fwd","").replace("rvs", "") # trainInfo_fwd = jmri.jmrit.dispatcher.TrainInfoFile().readTrainInfo(filename_fwd) # filename_fwd = self.get_filename(edge, "fwd") dm = DispatchMaster() last_section = dm.last_section_of_transit(self.trainInfo) length_of_last_section = float(dm.length_of_last_section(last_section))/10.0 # length in cm overall_stopping_position = ResetButtonMaster().get_overall_stopping_distance() [_, individual_stopping_position] = dm.get_stopping_position(edge) # the stopping position is made up of one for a particular transit # plus an overall one affecting all transits total_stopping_position = individual_stopping_position + overall_stopping_position stopping_length_fraction = 1.0-(float(total_stopping_position)/float(length_of_last_section)) return stopping_length_fraction def modify_trainInfo(self, train_name): # print "modify_trainInfo" # setTrainLengthUnits to scalemetres tlu = jmri.jmrit.dispatcher.ActiveTrain(None,None,0).TrainLengthUnits # x = tlu.TRAINLENGTH_SCALEMETERS # print "TRAINLENGTH_SCALEMETERS= ", x self.trainInfo.setTrainLengthUnits(tlu.TRAINLENGTH_SCALEMETERS) #scale metres # setMaxTrainLength (in scale metres) [engine,current_length] = self.get_train_length(train_name) #get the engine name self.trainInfo.setMaxTrainLengthScaleMeters(float(current_length)) # setSpeedFactor # print "in modify_trainInfo1 " [engine,current_speed_factor] = self.get_train_speed_factor(train_name) # print "in modify_trainInfo2 ", current_speed_factor speedFactor = float(current_speed_factor)/100.0 # print "in modify_trainInfo2 speedFactor", speedFactor # print "in modify_trainInfo2 a" if speedFactor >= 2 or speedFactor <=0: speedFactor = 1 msg = "speedFactor set is out of range " + str(current_speed_factor) + "\nSpeed Factor set to 100% " + "for train " + train_name OptionDialog().displayMessage(msg) self.trainInfo.setSpeedFactor(float(speedFactor)) # set the stopbyspeedprofileadjust (stopping length) stopbyspeedprofileadjust = self.get_stopping_length_fraction() self.trainInfo.setStopBySpeedProfileAdjust(stopbyspeedprofileadjust) # setMinReliableOperatingSpeed percentage = 10.0 self.trainInfo.setMinReliableOperatingSpeed(percentage/100) # set wait for block to be clear before running transit transit_name = self.trainInfo.getTransitName() folder = "restrictTransits" filename = "restrictTransits.txt" restricted_transits = DispatchMaster().read_list(folder,filename) if restricted_transits[0] != "": filtered_restricted_transits = [ t for t in restricted_transits if t[0] == transit_name] if filtered_restricted_transits != []: [transit_name1, transit_block_name] = filtered_restricted_transits trainInfo_fwd.setBlockName(new_transit_block_name) if self.logLevel > 0: print "self.forward_stopping_sensor_exists(self.trainInfo)",self.forward_stopping_sensor_exists(self.trainInfo) # print "sensors.getSensor('stopAtStopSensor').getKnownState()", sensors.getSensor("stopAtStopSensor").getKnownState(), ACTIVE def set_whether_to_stop_at_sensor(self, DF): # print "set_whether_to_stop_at_sensor" transit_name = self.trainInfo.getTransitName() if self.logLevel > 0: print "transit_name", transit_name active_train_list = [active_train for active_train in DF.getActiveTrainsList() \ if active_train.getTransitName() == transit_name] if self.logLevel > 0: print "active_train_list", active_train_list active_train = active_train_list[0] if self.logLevel > 0: print "active_train", active_train autoActiveTrain = active_train.getAutoActiveTrain() if self.forward_stopping_sensor_exists(self.trainInfo): if self.logLevel > 0: print "forward_stopping_sensor_exists" # set default if sensors.getSensor("stopAtStopSensor").getKnownState() == ACTIVE: if self.logLevel > 0: print "stop at stop sensor active", sensors.getSensor("stopAtStopSensor").getKnownState(), ACTIVE autoActiveTrain.set_useStopSensor(True) else: if self.logLevel > 0: print "stop at stop sensor inactive", sensors.getSensor("stopAtStopSensor").getKnownState(), INACTIVE if self.logLevel > 0: print "before", self.trainInfo.getStopBySpeedProfile(), self.trainInfo.getUseSpeedProfile() autoActiveTrain.set_useStopSensor(False) # overwrite with set values if self.stop_mode is None or self.stop_mode == "" or self.stop_mode == "Use Default": if self.logLevel > 0: print "Use Defailt" pass elif self.stop_mode == "Use Stop Sensor": autoActiveTrain.set_useStopSensor(True) if self.logLevel > 0: print "set stop sensor True" elif self.stop_mode == "Use Speed Profile": autoActiveTrain.set_useStopSensor(False) if self.logLevel > 0: print "set_useStopSensor False" else: print "ERROR incorrect value for stop mode" else: if self.logLevel > 0: print "forward_stopping_sensor does not exist" def forward_stopping_sensor_exists(self, traininfo): # print "forward_stopping_sensor_exists" transit_name = traininfo.getTransitId() transit = transits.getTransit(transit_name) transit_section_list = transit.getTransitSectionList() section_list = transit.getSectionListBySeq(transit.getMaxSequence()) section = section_list[0] forward_stopping_sensor = section.getForwardStoppingSensor() if forward_stopping_sensor != None: return True else: return False def set_sensor(self, sensorName, sensorState): sensor = sensors.getSensor(sensorName) if sensor is None: self.displayMessage('{} - Sensor {} not found'.format(self.threadName, sensorName)) return if sensorState == 'active': newState = ACTIVE elif sensorState == 'inactive': if self.logLevel > 1: print "set_sensor ", sensorName, 'inactive' newState = INACTIVE else: self.displayMessage('{} - Sensor state, {}, is not valid'.format(self.threadName, sensorState)) sensor.setKnownState(newState) return def wait_sensor(self, sensorName, sensorState): # print "wait_sensor" sensor = sensors.getSensor(sensorName) if sensor is None: self.displayMessage('{} - Sensor {} not found'.format(self.threadName, sensorName)) return if sensorState == 'active': self.waitSensorActive(sensor) elif sensorState == 'inactive': self.waitSensorInactive(sensor) else: self.displayMessage('{} - Sensor state, {}, is not valid'.format(self.threadName, sensorState)) ## *********************************************************************************** ## sound routines ## *********************************************************************************** def getOperatingSystem(self): #detecting the operating system using `os.name` System property os = java.lang.System.getProperty("os.name") os = os.lower() if "win" in os: return "WINDOWS" elif "nix" in os or "nux" in os or "aix" in os: return "LINUX" elif "mac" in os: return "MAC" return None def speak(self, msg): os = self.getOperatingSystem() if os == "WINDOWS": self.speak_windows(msg) elif os == "LINUX": self.speak_linux(msg) elif os == "MAC": self.speak_mac(msg) def speak_windows(self,msg) : try: cmd1 = "Add-Type -AssemblyName System.Speech" cmd2 = '$SpeechSynthesizer = New-Object -TypeName System.Speech.Synthesis.SpeechSynthesizer' cmd3 = "$SpeechSynthesizer.Speak('" + msg + "')" cmd = cmd1 + ";" + cmd2 + ";" + cmd3 os.system("powershell " + cmd ) except: msg = "Announcements not working \n Only supported on windows versions with powershell and SpeechSynthesizer" JOptionPane.showMessageDialog(None, msg, "Warning", JOptionPane.WARNING_MESSAGE) def speak_mac(self, msg): try: java.lang.Runtime.getRuntime().exec("say {}".format(msg)) except: msg = "Announcements not working \n say not working on your Mac" JOptionPane.showMessageDialog(None, msg, "Warning", JOptionPane.WARNING_MESSAGE) def speak_linux(self, msg): try: #os.system("""echo %s | spd-say -e -w -t male1""" % (msg,)) #os.system("""echo %s | spd-say -e -w -t female3""" % (msg,)) #os.system("""echo %s | spd-say -e -w -t child_male""" % (msg,)) os.system("""echo %s | spd-say -e -w -t child_female""" % (msg,)) #slightly slower except: msg = "Announcements not working \n spd-say not set up on your linux system" JOptionPane.showMessageDialog(None, msg, "Warning", JOptionPane.WARNING_MESSAGE) def announce(self, fromblockname, toblockname, speak_on, direction, instruction): # print "announce" from_station = self.get_station_name(fromblockname) to_station = self.get_station_name(toblockname) if speak_on == True: if direction == "forward": platform = " platform 1 " else: platform = " platform 2 " self.speak("The train in" + platform + " is due to depart to " + to_station) #self.speak("The train in "+ from_station + " is due to depart to " + to_station ) def get_station_name(self, block_name): # print "get_station_name" BlockManager = jmri.InstanceManager.getDefault(jmri.BlockManager) block = BlockManager.getBlock(block_name) comment = block.getComment() # % is the delimeter for block name delimeter = '"' if delimeter in comment: station_name = self.get_substring_between_delimeters(comment, delimeter) else: station_name = block_name return station_name def get_substring_between_delimeters(self, comment, delimeter): start = delimeter end = delimeter s = comment substring = s[s.find(start)+len(start):s.rfind(end)] return substring def bell(self, bell_on = "True"): # print "bell" if bell_on == "True": snd = jmri.jmrit.Sound("resources/sounds/Bell.wav") snd.play() def do_not_start_trains_simultaneously(self): # print "do_not_start_trains_simultaneously" global time_last_train time_now = int(round(time.time() * 1000)) time_train = math.max(time_now,time_last_train) time_to_wait = time_train - time_now time_last_train = time_train + 1000 #store the time this train will start self.waitMsec(time_to_wait) #make this train wait for 1 sec after previous train def wait_route_is_clear(self, traininfoFileName, startBlockName, train): route_is_occupied = True # occupied i = 0 while route_is_occupied : #require 1 occurrences of route not occupied i = i+1 route_is_occupied = \ self.check_route_is_allocated_or_occupied(traininfoFileName, startBlockName) if route_is_occupied: if i == 1: print train, "waiting for route", traininfoFileName, "to be clear" self.waitMsec(1000) def check_route_is_allocated_or_occupied(self, traininfoFileName, startBlockName): # print "check_route_is_allocated_or_occupied" [transit_name, transit_id] = self.get_transit(traininfoFileName) TransitManager = jmri.InstanceManager.getDefault(jmri.TransitManager) transit = TransitManager.getTransit(transit_name) if self.logLevel > 0: print "transit_name", transit_name, "transit_id", transit_id block_list = [block for block in transit.getInternalBlocksList() if block.getUserName() != startBlockName] if self.logLevel > 0: print "block_list", [block.getUserName() for block in block_list] route_is_occupied = False #add the block that must be clear for the transit to run trainInfo = jmri.jmrit.dispatcher.TrainInfoFile().readTrainInfo(traininfoFileName) transit_block_name = trainInfo.getBlockName() if transit_block_name != "": transit_block = blocks.getBlock(transit_block_name) # print "appending", transit_block_name, transit_block block_list.append(transit_block) index = 0 for block in block_list: index += 1 #getValue is set if the track is occupied if block.getSensor().getKnownState() == ACTIVE: # check if block is occupied route_is_occupied = True if self.logLevel > 0: print block.getUserName() , "is not clear value =", block.getSensor().getKnownState(), index break else: if self.logLevel > 0: print block.getUserName() , "is clear value =", block.getSensor().getKnownState(), index # getExtraColor is set if the block is allocated LayoutBlockManager=jmri.InstanceManager.getDefault(jmri.jmrit.display.layoutEditor.LayoutBlockManager) layoutBlock = LayoutBlockManager.getLayoutBlock(block) if layoutBlock.getUseExtraColor(): route_is_occupied = True if self.logLevel > 0: print block.getUserName() , "is not clear (extracolor) value =", block.getSensor().getKnownState(), index break if self.logLevel > 0: print "route_is_occupied", route_is_occupied; print # DF = jmri.InstanceManager.getDefault(jmri.jmrit.dispatcher.DispatcherFrame) # java_active_trains_list = DF.getActiveTrainsList() # java_active_trains_Arraylist= java.util.ArrayList(java_active_trains_list) # active_train_names_list = [str(t.getTrainName()) for t in java_active_trains_Arraylist] # if self.logLevel > 0: print "active_train_names_list", active_train_names_list # for train_name in active_train_names_list: # # print "trains", trains # # print "train_name", train_name # train = trains[train_name] # if train["allocating"] == True: # route_is_occupied = True # only allow one dispatch to be set up at a time else this routine does not work # # we don't want to check that the route is clear, and then have an allocation take place immediately after # print "route_is_occupied state is:", route_is_occupied return route_is_occupied def set_route_allocated(self, traininfoFileName, startBlockName): # print "set_route_allocated" [transit_name, transit_id] = self.get_transit(traininfoFileName) TransitManager = jmri.InstanceManager.getDefault(jmri.TransitManager) transit = TransitManager.getTransit(transit_name) if self.logLevel > 0: print "transit_name", transit_name, "transit_id", transit_id block_list = [block for block in transit.getInternalBlocksList() if block.getUserName() != startBlockName] for block in block_list: # getExtraColor is set if the block is allocated LayoutBlockManager=jmri.InstanceManager.getDefault(jmri.jmrit.display.layoutEditor.LayoutBlockManager) layoutBlock = LayoutBlockManager.getLayoutBlock(block) layoutBlock.setUseExtraColor(True) if self.train_name == "shunter": print " ", if self.logLevel > 0: print "allocated route", traininfoFileName def get_transit(self, filename): # print "get_transit" trainInfo = jmri.jmrit.dispatcher.TrainInfoFile().readTrainInfo(filename) transit_name = trainInfo.getTransitName() transit_id = trainInfo.getTransitId() return [transit_name, transit_id] class NewTrainMaster(jmri.jmrit.automat.AbstractAutomaton): # responds to the newTrainSensor, and allocates trains available for dispatching # we make the allocated flag global as we will use it in DispatchMaster when we dispatch a train global trains_allocated def init(self): self.logLevel = 0 if self.logLevel > 0: print 'Create Stop Thread' self.od = OptionDialog() def setup(self): global trains_allocated #self.initialise_train() newTrainSensor = "newTrainSensor" self.new_train_sensor = sensors.getSensor(newTrainSensor) if self.new_train_sensor is None: return False self.new_train_sensor.setKnownState(INACTIVE) if 'trains_allocated' not in globals(): trains_allocated = [] self.od = OptionDialog() return True def handle(self): global trains_allocated #this repeats # wait for a sensor requesting to check for new train if self.logLevel > 0: print ("wait for a sensor requesting to check for new train") self.waitSensorActive(self.new_train_sensor) self.new_train_sensor.setKnownState(INACTIVE) #display the allocated trains title = "Setup trains" msg = "setup one or more trains" opt1 = "1 train" opt2 = "several trains" opt3 = "check/swap train direction" opt4 = "modify existing trains" #opt4 = "reset trains" action = self.od.customQuestionMessage4str(msg, title, opt1, opt2, opt3, opt4) if self.od.CLOSED_OPTION == True: #check of optionbox was closed prematurely pass elif action == "1 train": # print "trains_allocated", trains_allocated # msg = "choose" # actions = ["setup 1 train","setup 2+ trains"] # action = self.od.List(msg, actions) # if action == "setup 1 train": station_block_name, new_train_name = self.check_new_train_in_siding() if self.logLevel > 0: print "station_block_name",station_block_name, "existing train name", new_train_name if station_block_name != None: # take actions for new train # if new_train_name == None: if True: all_trains = self.get_all_roster_entries_with_speed_profile() sections_to_choose = self.get_non_allocated_trains_sections() if all_trains == []: msg = "There are no engines with speed profiles, cannot operate without any" JOptionPane.showMessageDialog(None,msg) elif len(sections_to_choose)>1: # msg = self.get_all_trains_msg() # title = None # opt1 = "Select section" # s = self.od.customMessage(msg, title, opt1) # if self.logLevel > 0: print "station_block_name",station_block_name, "s", s # if self.od.CLOSED_OPTION == False: msg = "Select section" sections_to_choose = self.get_non_allocated_trains_sections() new_section_name = self.od.List(msg, sections_to_choose) if self.od.CLOSED_OPTION == False: msg = "Select the train in " + new_section_name trains_to_choose = self.get_non_allocated_trains() if trains_to_choose == []: s = OptionDialog().displayMessage("no more trains with speed profiles \nto select") else: new_train_name = self.od.List(msg, trains_to_choose) if self.od.CLOSED_OPTION == False: if new_train_name not in trains_allocated: trains_allocated.append(new_train_name) # print "trains allocated", trains_allocated #print "*****", "new_train_name", new_train_name, "new_section_name", new_section_name self.add_to_train_list_and_set_new_train_location(new_train_name, new_section_name) if self.od.CLOSED_OPTION == False: #only do this if have not closed a frame in add_to_train_list_and_set_new_train_location self.set_blockcontents(new_section_name, new_train_name) self.set_length(new_train_name) self.set_speed_factor(new_train_name) else: if self.logLevel > 0 : print "!!!!5" trains_to_choose = self.get_non_allocated_trains() title = "In " + station_block_name + " Select train roster" list_items = trains_to_choose new_train_name = self.od.List(title, list_items, preferred_size = "default") if new_train_name not in trains_allocated: trains_allocated.append(new_train_name) self.add_to_train_list_and_set_new_train_location(new_train_name, station_block_name) self.set_blockcontents(station_block_name, new_train_name) self.set_length(new_train_name) self.set_speed_factor(new_train_name) else: if self.logLevel > 0: print "about to show message no new train in siding" msg = self.get_all_trains_msg() msg += "\nPut a train in a section so it can be allocated!\n" title = "All trains allocated" opt1 = "Continue" opt2 = "Delete the trains already set up and start again" ans = self.od.customQuestionMessage2str(msg, title, opt1, opt2) if self.od.CLOSED_OPTION == True: pass elif ans == opt2: self.reset_allocation1() elif action == "several trains": self.hideGui() createandshowGUI(self, action) elif action == "modify existing trains": self.hideGui() createandshowGUI(self, action) elif action == "check/swap train direction": self.check_swap_train_direction() return True def check_swap_train_direction(self): trains_to_choose = self.get_allocated_trains() # print "trains_to_choose", trains_to_choose if trains_to_choose == []: s = OptionDialog().displayMessage("no allocated trains to select") else: msg = "Select the required train" new_train_name = self.od.List(msg, trains_to_choose) self.swap_train_direction1(new_train_name) def swap_train_direction1(self, train_name): train_block_array = \ [block.getUserName() for block in blocks.getNamedBeanSet() if block.getValue() == train_name] if train_block_array == []: OptionDialog().displayMessage(train_name + " is not allocated") return train_block = \ [block.getUserName() for block in blocks.getNamedBeanSet() if block.getValue() == train_name][0] if train_block is not None: self.check_train_direction(train_name, train_block) def hideGui(self): global CreateAndShowGUI_frame if "CreateAndShowGUI_frame" in globals(): CreateAndShowGUI_frame.setVisible(False) def check_train_direction(self, train_name, station_block_name): global train if train_name in trains: train = trains[train_name] direction = train["direction"] penultimate_layout_block = self.get_penultimate_layout_block(station_block_name) saved_state = penultimate_layout_block.getUseExtraColor() in_siding = self.in_siding(station_block_name) closed = False while closed == False: penultimate_layout_block.setUseExtraColor(True) direction = train["direction"] msg = "train travelling " + self.swap_direction(direction) + " towards highlighted block" title = "swap directions of " + train_name opt1 = "swap direction" opt2 = "Close" s = OptionDialog().customQuestionMessage2str(msg, title, opt1, opt2) if s == JOptionPane.CLOSED_OPTION: closed = True if s == opt1: self.swap_train_direction(train_name) closed = False if s == opt2: closed = True penultimate_layout_block.setUseExtraColor(saved_state) def swap_train_direction(self, train_name): global train if train_name in trains: train = trains[train_name] direction = train["direction"] train["direction"] = self.swap_direction(direction) def swap_direction(self, direction): if direction == "reverse": direction = "forward" else: direction = "reverse" return direction def get_train_length(self, new_train_name): EngineManager=jmri.InstanceManager.getDefault(jmri.jmrit.operations.rollingstock.engines.EngineManager) engineRoad = "Set by Dispatcher System" engineNumber = new_train_name engine = EngineManager.newRS(engineRoad, engineNumber) #get the current length of the engine default = "10" current_length = engine.getLength() # print "current_length", current_length # print "type", type(current_length) , "test", str(current_length) == "0" if str(current_length) == "0" or current_length is None: current_length = default # current length is in unicode engine.setLength(current_length) # print "current_length2", current_length return [engine, current_length] def set_length(self, new_train_name): if new_train_name is None: return title = "Set the length of the engine/train" # msg = str(fred) request = "Change" while request == "Change": [engine,current_length] = self.get_train_length(new_train_name) if current_length == None: return # print "current_length3", current_length # current_length is an integer, and is set to a default of 10 scale metres gauge = WarrantPreferences.getDefault().getLayoutScale() length_in_cm_float = (float(current_length) / gauge) * 100.0 length_in_cm_str = str("{:.2f}".format(length_in_cm_float)) length_in_inches_float = (float(current_length) / gauge / 2.54) * 100.0 length_in_inches_str = str("{:.2f}".format(length_in_inches_float)) msg = "length of " + new_train_name + " = " + str(current_length) + " scale metres" + \ "
gauge : " + "1:" + str(int(gauge)) + \ "
length in cm : " + length_in_cm_str + \ "
length in inches: " + length_in_inches_str opt1 = "OK" opt2 = "Change" request = self.od.customQuestionMessage2str(msg,title,opt1, opt2) if request == "Change": #set the new length msg = "input length of " + new_train_name + " in scale metres" title = "length of " + new_train_name default_value = current_length new_length = self.od.input(msg, title, default_value) engine.setLength(new_length) def set_length0(self, new_train_name): [engine,current_length] = self.get_train_length(new_train_name) engine.setLength(current_length) def get_train_speed_factor(self, new_train_name): EngineManager=jmri.InstanceManager.getDefault(jmri.jmrit.operations.rollingstock.engines.EngineManager) engineRoad = "Set by Dispatcher System" engineNumber = new_train_name engine = EngineManager.newRS(engineRoad, engineNumber) # get the current speed factor of the engine default = "100" # percentage comment = engine.getComment() split_comment = [] if "speed factor" in comment: split_comment = comment.split(" ") index = split_comment.index("speed") # print "len(split_comment)", len(split_comment), "index + 2", index + 2 if len(split_comment) > index + 2: speed_factor = split_comment[index+2] else: speed_factor = default else: speed_factor = default return [engine, speed_factor] def set_speed_factor(self, new_train_name): [engine, current_speed_factor] = self.get_train_speed_factor(new_train_name) # if current_length == "0": # default = "10" # current_speed_factor = default # engine.setSpeedFactor(default) #ask if want to change length title = "Scale the speed of the engine/train" msg = "speed factor of " + new_train_name + " = " + str(current_speed_factor) + "%" opt1 = "OK" opt2 = "Change" request = self.od.customQuestionMessage2str(msg,title,opt1, opt2) if request == "Change": #set the new speed factor msg = "input speed factor % of " + new_train_name title = "speed factor of " + new_train_name default_value = current_speed_factor new_speed_factor= self.od.input(msg, title, default_value) new_speed_factor = "speed factor " + new_speed_factor engine.setComment(new_speed_factor) def set_speed_factor0(self, new_train_name): # used in set several trains [engine, current_speed_factor] = self.get_train_speed_factor(new_train_name) new_speed_factor = "speed factor " + current_speed_factor engine.setComment(new_speed_factor) def get_allocated_trains_msg(self): allocated_trains =[ str(train) + " in block " + str(trains[train]["edge"].getTarget()) for train in trains_allocated] if allocated_trains ==[]: msg = "There are no trains in blocks that are not allocated. \n" else: msg = "The allocated trains are: \n" +'\n'.join(allocated_trains) return msg def get_allocated_trains(self): return trains_allocated def get_non_allocated_trains(self): all_trains = self.get_all_roster_entries_with_speed_profile() non_allocated_trains = copy.copy(all_trains) for train in trains_allocated: if train in non_allocated_trains: non_allocated_trains.remove(train) return non_allocated_trains def get_non_allocated_trains_msg(self): trains_in_sections_allocated1 = self.trains_in_sections_allocated() msg = "the non-allocated trains are in sections: \n\n" + "\n".join([" " + str(train[0]) for train in trains_in_sections_allocated1 if train[2] == "non-allocated"]) return msg def get_all_sections(self): return [section for section in sections.getNamedBeanSet()] def get_all_blocks(self): return [block for block in blocks.getNamedBeanSet()] def get_sections_for_trains_in_table(self, trains_in_table): return [str(train) for train in trains_in_table] def get_non_allocated_trains_sections(self): trains_in_sections_allocated1 = self.trains_in_sections_allocated() # print "trains_in_sections_allocated1", trains_in_sections_allocated1 return [str(train[0]) for train in trains_in_sections_allocated1 if train[2] == "non-allocated"] def get_allocated_trains_sections(self): trains_in_sections_allocated1 = self.trains_in_sections_allocated() return [str(train[0]) for train in trains_in_sections_allocated1 if train[2] == "allocated"] def get_all_trains_msg(self): return self.get_allocated_trains_msg() + "\n" + self.get_non_allocated_trains_msg() def reset_allocation(self): global trains_allocated if trains_allocated == []: if self.logLevel > 0: print ("a") msg = "Nothing to reset" OptionDialog().displayMessage(msg) else: if self.logLevel > 0: print ("b") msg = "Select train to modify" train_name_to_remove = modifiableJComboBox(trains_allocated,msg).return_val() trains_allocated.remove(train_name_to_remove) self.new_train_sensor.setKnownState(ACTIVE) def reset_allocation1(self): global trains_allocated if trains_allocated == []: if self.logLevel > 0: print ("a") msg = "Nothing to reset" OptionDialog().displayMessage(msg) else: if self.logLevel > 0: print ("b") #set trains_allocated to [] for train_name_to_remove in trains_allocated: msg = "Select train to modify" #train_name_to_remove = modifiableJComboBox(trains_allocated,msg).return_val() trains_allocated.remove(train_name_to_remove) #remove the train from trains_allocated self.reset_train_in_blocks(train_name_to_remove) #remove the blockcontents text if self.logLevel > 0: print "trains_allocated",trains_allocated #self.new_train_sensor.setKnownState(ACTIVE) 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 add_to_train_list_and_set_new_train_location(self, train_name, station_block_name): # called by setup 1 train # trains is a dictionary, with keys of the train_name # each value is itself a dictionary with 3 items # edge # penultimate_block_name # direction global train global trains_allocated if train_name not in trains: trains[train_name] = {} train = trains[train_name] train["train_name"] = train_name else: #train_name = self.get_train_name() self.set_train_in_block(station_block_name, train_name) # 2) set the last traversed edge to the edge going into the siding edge = None j = 0 #print "edge_before" , edge #print "g.g_stopping.edgesOf(station_block_name)",g.g_stopping.edgesOf(station_block_name) break1 = False for e in g.g_stopping.edgeSet(): j+=1 LayoutBlockManager=jmri.InstanceManager.getDefault(jmri.jmrit.display.layoutEditor.LayoutBlockManager) station_block = LayoutBlockManager.getLayoutBlock(station_block_name) number_neighbors = station_block.getNumberOfNeighbours() #print "station block number neighbors", number_neighbors in_siding = (number_neighbors == 1) #print "in_siding", in_siding for i in range(station_block.getNumberOfNeighbours()): neighbor_name = station_block.getNeighbourAtIndex(i).getDisplayName() if e.getItem("penultimate_block_name") == neighbor_name and e.getItem("last_block_name") == station_block_name: edge = e break1 = True if break1 == True: break #print "******************************++" if edge == None: print "Error the required block has not been found1. restart and try again. Sorry!" return train["edge"] = edge train["penultimate_block_name"] = edge.getItem("penultimate_block_name") # 3) set direction so can check direction of transit penultimate_block_name = edge.getItem("penultimate_block_name") penultimate_layout_block = LayoutBlockManager.getLayoutBlock(penultimate_block_name) saved_state = penultimate_layout_block.getUseExtraColor() if not in_siding: # highlight the penultimate block penultimate_layout_block.setUseExtraColor(True) penultimate_layout_block.setUseExtraColor(True) # print "set train direction" [train_direction,result] = self.set_train_direction(station_block_name, in_siding) # print "finished set train direction" #check the condition set in set_train_direction train["direction"] = train_direction # print "train['direction']", train["direction"] penultimate_layout_block.setUseExtraColor(saved_state) # print "edge" , edge if self.logLevel > 3: print "penultimate_block_name", penultimate_block_name if self.logLevel > 4: print "train_direction", train_direction # print # 4) add to allocated train list if str(train_name) not in trains_allocated: trains_allocated.append(str(train_name)) if "allocating" not in train: train["allocating"] = False # print "done" def add_to_train_list_and_set_new_train_location0(self, train_name, station_block_name, train_direction, train_length, train_speed_factor): # called by setup several trains # trains is a dictionary, with keys of the train_name # each value is itself a dictionary with 3 items # edge # penultimate_block_name # direction global train global trains_allocated if train_name not in trains: trains[train_name] = {} train = trains[train_name] train["train_name"] = train_name else: #train_name = self.get_train_name() train = trains[train_name] train["train_name"] = train_name self.set_train_in_block(station_block_name, train_name) # 2) set the last traversed edge to the edge going into the siding edge = None j = 0 #print "edge_before" , edge #print "g.g_stopping.edgesOf(station_block_name)",g.g_stopping.edgesOf(station_block_name) break1 = False #print "no edges", g.g_stopping.edgeSet() for e in g.g_stopping.edgeSet(): j+=1 LayoutBlockManager=jmri.InstanceManager.getDefault(jmri.jmrit.display.layoutEditor.LayoutBlockManager) station_block = LayoutBlockManager.getLayoutBlock(station_block_name) number_neighbors = station_block.getNumberOfNeighbours() #print "station block number neighbors", number_neighbors in_siding = (number_neighbors == 1) #print "in_siding", in_siding for i in range(station_block.getNumberOfNeighbours()): neighbor_name = station_block.getNeighbourAtIndex(i).getDisplayName() # print "penultimate_block_name", e.getItem("penultimate_block_name") # print "last_block_name", e.getItem("last_block_name") print "***************" if e.getItem("penultimate_block_name") == neighbor_name and e.getItem("last_block_name") == station_block_name: edge = e break1 = True if break1 == True: break #print "******************************++" if edge == None: print "Error the required block has not been found2. restart and try again. Sorry!" return train["edge"] = edge train["penultimate_block_name"] = edge.getItem("penultimate_block_name") # 3) set direction so can check direction of transit train["direction"] = train_direction # print train_name, 'train["direction"]',train["direction"] # 4) add to allocated train list # if str(train_name) not in trains_allocated: # trains_allocated.append(str(train_name)) [engine,current_length] = self.get_train_length(train_name) #get the engine name engine.setLength(str(train_length)) # save the length provided in the parameter #[engine,current_speed_factor] = self.get_train_speed_factor(train_name) speed_factor_str = "speed factor " + train_speed_factor engine.setComment(speed_factor_str) train["allocating"] = False def highlight_penultimate_block(self, station_block_name): # print("highlight_penultimate_block") # 2) set the last traversed edge to the edge going into the siding edge = None j = 0 #print "edge_before" , edge #print "g.g_stopping.edgesOf(station_block_name)",g.g_stopping.edgesOf(station_block_name) break1 = False #print "no edges", g.g_stopping.edgeSet() # for e in g.g_express.edgeSet(): # print "e" , e for e in g.g_express.edgeSet(): j+=1 LayoutBlockManager=jmri.InstanceManager.getDefault(jmri.jmrit.display.layoutEditor.LayoutBlockManager) station_block = LayoutBlockManager.getLayoutBlock(station_block_name) number_neighbors = station_block.getNumberOfNeighbours() #print "station block number neighbors", number_neighbors in_siding = (number_neighbors == 1) # print "in_siding", in_siding for i in range(station_block.getNumberOfNeighbours()): neighbor_name = station_block.getNeighbourAtIndex(i).getDisplayName() print "neighbor_name", neighbor_name print "station_block_name", station_block_name # print "penultimate_block_name", e.getItem("penultimate_block_name") # print "last_block_name", e.getItem("last_block_name") print "***************" if e.getItem("penultimate_block_name") == neighbor_name and e.getItem("last_block_name") == station_block_name: edge = e break1 = True if break1 == True: break #print "******************************++" if edge == None: print "Error the required block has not been found3. restart and try again. Sorry!" return ["Error", "Error", "Error"] # 3) set direction so can check direction of transit penultimate_block_name = edge.getItem("penultimate_block_name") penultimate_layout_block = LayoutBlockManager.getLayoutBlock(penultimate_block_name) saved_state = penultimate_layout_block.getUseExtraColor() if not in_siding: # highlight the penultimate block penultimate_layout_block.setUseExtraColor(True) penultimate_layout_block.setUseExtraColor(True) [train_direction, result] = self.set_train_direction(station_block_name, in_siding) penultimate_layout_block.setUseExtraColor(saved_state) return [edge, train_direction, result] def get_penultimate_layout_block(self, station_block_name): # get the last traversed edge to the edge of the station_block edge = None j = 0 #print "edge_before" , edge #print "g.g_stopping.edgesOf(station_block_name)",g.g_stopping.edgesOf(station_block_name) break1 = False #print "no edges", g.g_stopping.edgeSet() for e in g.g_stopping.edgeSet(): j+=1 LayoutBlockManager=jmri.InstanceManager.getDefault(jmri.jmrit.display.layoutEditor.LayoutBlockManager) station_block = LayoutBlockManager.getLayoutBlock(station_block_name) number_neighbors = station_block.getNumberOfNeighbours() #print "station block number neighbors", number_neighbors in_siding = (number_neighbors == 1) for i in range(station_block.getNumberOfNeighbours()): neighbor_name = station_block.getNeighbourAtIndex(i).getDisplayName() print "neighbor_name", neighbor_name print "station_block_name", station_block_name # print "penultimate_block_name", e.getItem("penultimate_block_name") # print "last_block_name", e.getItem("last_block_name") print "***************" if e.getItem("penultimate_block_name") == neighbor_name and e.getItem("last_block_name") == station_block_name: edge = e break1 = True if break1 == True: break if edge == None: # print "Error the required block has not been found4. restart and try again. Sorry!" return None penultimate_block_name = edge.getItem("penultimate_block_name") LayoutBlockManager=jmri.InstanceManager.getDefault(jmri.jmrit.display.layoutEditor.LayoutBlockManager) penultimate_layout_block = LayoutBlockManager.getLayoutBlock(penultimate_block_name) return penultimate_layout_block def in_siding(self, station_block_name): LayoutBlockManager=jmri.InstanceManager.getDefault(jmri.jmrit.display.layoutEditor.LayoutBlockManager) station_block = LayoutBlockManager.getLayoutBlock(station_block_name) number_neighbors = station_block.getNumberOfNeighbours() #print "station block number neighbors", number_neighbors in_siding = (number_neighbors == 1) return in_siding def set_train_direction(self, block_name, in_siding): # in_siding = self.in_siding(block_name) options = ["forward", "reverse"] default = "forward" self.od.CLOSED_OPTION = True while self.od.CLOSED_OPTION == True: msg = "In block: " + block_name + "\n" +'What way is train facing\ntowards highlighted block?' title = "Set Train Facing Direction" type = JOptionPane.QUESTION_MESSAGE result = self.od.customQuestionMessage2str(msg, title, "forward", "reverse") if self.od.CLOSED_OPTION == True: OptionDialog().displayMessage("Sorry Can't Cancel at this point") if result == "reverse": train_direction = "forward" else: train_direction = "reverse" # if in_siding: # if result == "reverse": # train_direction = "forward" # else: # train_direction = "reverse" # else: # if result == "forward": # train_direction = "forward" # else: # train_direction = "reverse" return [train_direction, result] def set_train_in_block(self, block_name, train_name): mem_val = train_name self.set_blockcontents(block_name, mem_val) def reset_train_in_blocks(self, train_name): for block in blocks.getNamedBeanSet(): #print "block name", block.getUserName(), "block.getValue()" , block.getValue() if block.getValue() == train_name: #print "yes" block.setValue("") #print "block name yes", block.getUserName(), "block.getValue()" , block.getValue() def trains_in_sections_allocated(self): trains_in_sections_allocated = [] #trains_in_sections_nonallocated = [] for station_block_name in g.station_block_list: block_value = self.get_blockcontents(station_block_name) block_occupied_state = self.check_sensor_state_given_block_name(station_block_name) # print "trains_allocated", trains_allocated # print "block_value", block_value if block_occupied_state == True: if block_value not in trains_allocated: # print "appending non_allocated as block_value not in trains allocated" trains_in_sections_allocated.append([station_block_name, block_value, "non-allocated"]) elif (block_value != None and block_value != "" and block_value != "none"): trains_in_sections_allocated.append([station_block_name, block_value, "allocated"]) else: trains_in_sections_allocated.append([station_block_name, block_value, "other"]) # print "trains_in_sections_allocated", trains_in_sections_allocated if self.logLevel > 0: print str(trains_in_sections_allocated) return trains_in_sections_allocated def occupied_blocks_allocated(self): occupied_blocks = [block for [block, train, state] in self.trains_in_sections_allocated() if state == "allocated"] return occupied_blocks def occupied_blocks_not_allocated(self): occupied_blocks = [block for [block, train, state] in self.trains_in_sections_allocated() if state == "non-allocated"] return occupied_blocks def blocks_allocated(self): occupied_blocks = [block for [block, train, state] in self.trains_in_sections_allocated()] return occupied_blocks def train_blocks(self, train_list, in_list): occupied_blocks = \ [station_block_name for station_block_name in g.station_block_list \ if self.check_sensor_state_given_block_name(station_block_name) == True] # print "occupied_blocks", occupied_blocks # print "train_list", train_list self.get_blockcontents(station_block_name), if in_list: items_in_list = \ [[self.get_blockcontents(block_name), block_name, self.check_sensor_state_given_block_name(block_name)] \ for block_name in occupied_blocks if self.get_blockcontents(block_name) in train_list] # [train_name , block_name, block_state] = items_in_list # for clarity return items_in_list else: items_not_in_list = \ [[self.get_blockcontents(block_name), block_name, self.check_sensor_state_given_block_name(block_name)] \ for block_name in occupied_blocks if self.get_blockcontents(block_name) not in train_list] # [train_name , block_name, block_state] = items_in_list # for clarity return items_not_in_list def train_blocks_in_list(self,train_list): return self.train_blocks(train_list, True) def train_blocks_not_in_list(self,train_list): return self.train_blocks(train_list, False) def check_new_train_in_siding(self): # go through all station global trains_allocated for station_block_name in g.station_block_list: #get a True if the block block_value has the train name in it block_value = self.get_blockcontents(station_block_name) if self.logLevel > 0: print " a trains_allocated:", trains_allocated, ": block_value", block_value #get a True if the block is occupied block_occupied_state = self.check_sensor_state_given_block_name(station_block_name) if self.logLevel > 0: print ("station block name {} : block_value {}". format(station_block_name, str(block_value))) #check if the block is occupied and has the required train in it if (block_value == None or block_value == "" or block_value == "none") and block_occupied_state == True: return [station_block_name, None] elif block_occupied_state == True and (block_value != None and block_value != "" and block_value != "none"): #check if there is already a thread for the train #check if the train has already been allocated #if self.new_train_thread_required(block_value): if block_value not in trains_allocated: return [station_block_name, block_value] else: if self.logLevel > 0: print "block_value in trains_allocated" if self.logLevel > 0: print "b trains_allocated:", trains_allocated, ": block_value", block_value pass else: pass return [None, None] def is_roster_entry(self, v): return type(v) is jmri.jmrit.roster.RosterEntry def train_thread_exists(self, train_name): for thread in instanceList: if thread is not None: if thread.isRunning(): existing_train_name = thread.getName() if existing_train_name == train_name: return True return False def create_new_train_thread(self, train_name): idx = len(instanceList) instanceList.append(RunDispatch()) # Add a new instance instanceList[idx].setName(train_name) # Set the instance name #if instanceList[idx].setup(): # Compile the train actions instanceList[idx].start() # Compile was successful def get_blockcontents(self, block_name): block = blocks.getBlock(block_name) value = block.getValue() return value def set_blockcontents(self, block_name, value): block = blocks.getBlock(block_name) value = block.setValue(value) def check_sensor_state_given_block_name(self, station_block_name): #if self.logLevel > 0: print("station block name {}".format(station_block_name)) layoutBlock = layoutblocks.getLayoutBlock(station_block_name) station_sensor = layoutBlock.getOccupancySensor() if station_sensor is None: OptionDialog().displayMessage(' Sensor in block {} not found'.format(station_block_name)) return currentState = True if station_sensor.getKnownState() == ACTIVE else False return currentState class createandshowGUI(TableModelListener): def __init__(self, super1, mode1): global CreateAndShowGUI_frame self.logLevel = 0 self.super = super1 #Create and set up the window. self.mode = mode1 # "several trains" or "modify existing trains" self.initialise_model(super1) if self.mode == "modify existing trains": CreateAndShowGUI_frame = JFrame("occupied blocks, allocated or not") else: CreateAndShowGUI_frame = JFrame("Set up trains. Any trains shown in blocks are showing on the track but not allocated. Save to allocate") self.frame = CreateAndShowGUI_frame self.frame.setPreferredSize(Dimension(800, 600)); self.frame.setVisible(True) self.completeTablePanel1() self.populate_action(None) self.completeTablePanel() self.cancel = False def completeTablePanel(self): self.tidy() self.frame.pack() self.frame.setVisible(True) return def completeTablePanel1(self): self.topPanel = JPanel(); self.topPanel.setLayout(BoxLayout(self.topPanel, BoxLayout.X_AXIS)) self.self_table() scrollPane = JScrollPane(self.table); scrollPane.setPreferredSize(Dimension(800, 600)); self.topPanel.add(scrollPane); self.buttonPane = JPanel(); self.buttonPane.setLayout(BoxLayout(self.buttonPane, BoxLayout.LINE_AXIS)) self.buttonPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10)) # button_add = JButton("Add Row", actionPerformed = self.add_row_action) # self.buttonPane.add(button_add); # self.buttonPane.add(Box.createRigidArea(Dimension(10, 0))) button_apply = JButton("Save", actionPerformed=self.save_action) self.buttonPane.add(button_apply) # self.buttonPane.add(Box.createHorizontalGlue()) self.buttonPane.add(Box.createRigidArea(Dimension(10, 0))) button_cancel = JButton("Close", actionPerformed=self.cancel_action) self.buttonPane.add(button_cancel) self.buttonPane.add(Box.createHorizontalGlue()) button_populate = JButton("Populate", actionPerformed=self.populate_action) self.buttonPane.add(button_populate) # self.buttonPane.add(Box.createRigidArea(Dimension(10, 0))) # button_tidy = JButton("Tidy", actionPerformed=self.tidy_action) # self.buttonPane.add(button_tidy) self.buttonPane.add(Box.createHorizontalGlue()) self.buttonPane.add(Box.createRigidArea(Dimension(10, 0))) button_savetofile = JButton("Save To File", actionPerformed=self.savetofile_action) self.buttonPane.add(button_savetofile) # self.buttonPane.add(Box.createHorizontalGlue()) self.buttonPane.add(Box.createRigidArea(Dimension(10, 0))) button_loadfromfile = JButton("Load From File", actionPerformed=self.loadfromfile_action) self.buttonPane.add(button_loadfromfile) # self.buttonPane.add(Box.createHorizontalGlue()) self.buttonPane.add(Box.createRigidArea(Dimension(10, 0))) button_deletefromfile = JButton("Delete Saved Files", actionPerformed=self.deletesavedfile_action) self.buttonPane.add(button_deletefromfile) self.buttonPane.add(Box.createHorizontalGlue()) contentPane = self.frame.getContentPane() contentPane.removeAll() contentPane.add(self.topPanel, BorderLayout.CENTER) contentPane.add(self.buttonPane, BorderLayout.PAGE_END) def buttonPanel(self): row1_1_button = JButton("Add Row", actionPerformed = self.add_row_action) row1_2_button = JButton("Save", actionPerformed = self.save_action) row1 = JPanel() row1.setLayout(BoxLayout(row1, BoxLayout.X_AXIS)) row1.add(Box.createVerticalGlue()) row1.add(Box.createRigidArea(Dimension(20, 0))) row1.add(row1_1_button) row1.add(Box.createRigidArea(Dimension(10, 0))) row1.add(row1_2_button) layout = BorderLayout() jPanel = JPanel() jPanel.setLayout(layout); jPanel.add(self.table,BorderLayout.NORTH) jPanel.add(row1,BorderLayout.SOUTH) #return jPanel return topPanel def initialise_model(self, super): self.model = None self.model = MyTableModel() self.table = JTable(self.model) self.model.addTableModelListener(MyModelListener(self, super)) def self_table(self): self.table.setPreferredScrollableViewportSize(Dimension(800, 600)); #table.setFillsViewportHeight(True) #self.table.getModel().addtableModelListener(self) self.table.setFillsViewportHeight(True); self.table.setRowHeight(30); #table.setAutoResizeMode( JTable.AUTO_RESIZE_OFF ); # self.resizeColumnWidth(table) #renderer = DefaultTableCellRenderer() #renderer.setToolTipText("Click for combo box"); # set first 3 cols to combobox # comboBox = [1,2,3] # column = [1,2,3] self.trainColumn = self.table.getColumnModel().getColumn(0) self.trainColumn.setPreferredWidth(100) self.combobox0 = JComboBox() self.all_trains = self.super.get_all_roster_entries_with_speed_profile() self.non_allocated_trains = self.super.get_non_allocated_trains() self.allocated_trains = self.super.get_allocated_trains() if self.mode == "several trains": self.required_trains = self.non_allocated_trains elif self.mode == "modify existing trains": self.required_trains = self.allocated_trains # print "self.non_allocated_trains", self.non_allocated_trains # print "self.allocated_trains", self.allocated_trains for train in self.required_trains: self.combobox0.addItem(train) # print "adding train", train self.trainColumn.setCellEditor(DefaultCellEditor(self.combobox0)); renderer0 = ComboBoxCellRenderer() self.trainColumn.setCellRenderer(renderer0) self.all_sections = self.super.get_all_sections() self.all_blocks = self.super.get_all_blocks() self.sectionColumn = self.table.getColumnModel().getColumn(1); self.sectionColumn.setPreferredWidth(100) self.combobox1 = JComboBox() if self.mode == "several trains": self.sections_to_choose = self.super.get_non_allocated_trains_sections() else: self.sections_to_choose = self.super.get_allocated_trains_sections() for section in self.sections_to_choose: self.combobox1.addItem(section) #self.set_train_selections(combobox0) self.sectionColumn.setCellEditor(DefaultCellEditor(self.combobox1)); renderer1 = ComboBoxCellRenderer() self.sectionColumn.setCellRenderer(renderer1); jpane = JScrollPane(self.table) panel = JPanel() panel.add(jpane) return self.table def add_row_action(self, e): model = e.getSource() data = self.model.getValueAt(0, 0) count = self.model.getRowCount() colcount = self.model.getColumnCount() self.model.add_row() self.completeTablePanel() def populate_action(self, event): # print "populate_action" column = 1 #block all_blocks = [block.getUserName() for block in self.all_blocks] blocks_in_table = [block for block in (self.model.getValueAt(r, column) for r in range(self.table.getRowCount())) if block in all_blocks] if self.mode == "several trains": not_allocated_blocks = self.super.occupied_blocks_not_allocated() blocks_to_put_in_dropdown = [s for s in not_allocated_blocks] self.populate(blocks_to_put_in_dropdown) self.tidy() else: allocated_blocks = self.super.blocks_allocated() # print "allocated_blocks", allocated_blocks blocks_to_put_in_dropdown = [s for s in allocated_blocks] # print "blocks to put in dropdown", blocks_to_put_in_dropdown self.model.populate_existing(blocks_to_put_in_dropdown) self.tidy() # print "COMPLETING TABLE PANEL" self.completeTablePanel() def populate(self, blocks_to_put_in_dropdown): for row in reversed(range(len(self.model.data))): self.model.data.pop(row) # append all blocks to put in dropdown for block in blocks_to_put_in_dropdown: # print "block", block self.model.data.append(["", block, "click ->", False, 10, 100]) # delete rows with no blocks for row in reversed(range(len(self.model.data))): if self.model.data[row][1] == None or self.model.data[row][1] == "": if len(self.model.data)>1: self.model.data.pop(row) self.completeTablePanel() def remove_not_set_row(self): # print "data", self.model.data for row in reversed(range(len(self.model.data))): # print "self.model.data[row][1]", self.model.data[row][1] if self.model.data[row][1] == "": self.model.data.pop(row) def tidy_action(self,e): self.tidy() self.completeTablePanel() def tidy(self): self.remove_not_set_row() size_of_one_row = 30 height = 130 for row in reversed(range(len(self.model.data))): height += size_of_one_row self.frame.setPreferredSize(Dimension(800, height)); def savetofile_action(self, event): #Tidy self.remove_not_set_row() self.completeTablePanel() if self.model.getRowCount() == 0: return dir = self.directory() j = JFileChooser(dir); j.setAcceptAllFileFilterUsed(False) filter = FileNameExtensionFilter("text files txt", ["txt"]) j.addChoosableFileFilter(filter); j.setDialogTitle("Select a .txt file"); ret = j.showSaveDialog(None); if (ret == JFileChooser.APPROVE_OPTION) : file = j.getSelectedFile() if file == "" or file == None: return if FilenameUtils.getExtension(file.getName()).lower() == "txt" : #filename is OK as-is pass else: file = File(file.getParentFile(), FilenameUtils.getBaseName(file.getName())+".txt") # ALTERNATIVELY: remove the extension (if any) and replace it with ".xml" else: return if self.logLevel > 0: print "savetofile action", file my_list = [] [train, block, direction, length, speed_factor] = [0, 1, 2, 4, 5] for row in range(len(self.model.data)): train_name = str(self.model.data[row][train]) block_name = str(self.model.data[row][block]) train_direction = str(self.model.data[row][direction]) train_length = str(self.model.data[row][length]) train_speed_factor = str(self.model.data[row][speed_factor]) row_list = [train_name, block_name, train_direction,train_length,train_speed_factor] if self.logLevel > 0: print "x", row my_list.append(row_list) if self.logLevel > 0: print "y", row if self.logLevel > 0: print "A" self.write_list(my_list,file) def loadfromfile_action(self, event): # load the file dir = self.directory() j = JFileChooser(dir) j.setAcceptAllFileFilterUsed(False) filter = FileNameExtensionFilter("text files txt", ["txt"]) j.setDialogTitle("Select a .txt file") j.addChoosableFileFilter(filter) # Automatically select the first file in the directory files = j.getCurrentDirectory().listFiles() j.setSelectedFile(files[0]) ret = j.showOpenDialog(None) if (ret == JFileChooser.APPROVE_OPTION): file = j.getSelectedFile() if self.logLevel > 0: print "about to read list", file my_list = self.read_list(file) if self.logLevel > 0: print "my_list", my_list for row in reversed(range(len(self.model.data))): self.model.data.pop(row) i = 0 [train, block, direction, length, speed_factor] = [0, 1, 2, 4, 5] for row in my_list: [train_val, block_val, direction_val, length_val, speed_factor_val] = row self.model.add_row() self.model.data[i][train] = train_val.replace('"','') self.model.data[i][block] = block_val.replace('"','') self.model.data[i][direction] = direction_val.replace('"','') self.model.data[i][length] = length_val.replace('"','') self.model.data[i][speed_factor] = speed_factor_val.replace('"','') i += 1 self.completeTablePanel1() self.completeTablePanel() msg = "Deleting invalid rows" result = OptionDialog().displayMessage(msg) if result == JOptionPane.NO_OPTION: return # check the loaded contents # 1) check that the trains are valid # 2) check that the blocks are occupied by valid trains # if either of the above are not valic we blank the entries # 3) Tidy # check the trains are valid b = False trains_to_put_in_dropdown = [t for t in self.non_allocated_trains] for row in reversed(range(len(self.model.data))): #if len(self.model.data) >1: # print "row", row if self.model.data[row][train] not in trains_to_put_in_dropdown: self.model.data.pop(row) not_allocated_blocks = self.super.occupied_blocks_not_allocated() for row in reversed(range(len(self.model.data))): if self.model.data[row][block] not in not_allocated_blocks: self.model.data.pop(row) self.completeTablePanel1() self.completeTablePanel() def deletesavedfile_action(self, event): while True: #Tidy self.remove_not_set_row() self.completeTablePanel() if self.model.getRowCount() == 0: return dir = self.directory() j = JFileChooser(dir); j.setAcceptAllFileFilterUsed(False) filter = FileNameExtensionFilter("text files txt", ["txt"]) j.addChoosableFileFilter(filter); j.setDialogTitle("Delete not wanted files"); ret = j.showDialog(None, "Delete"); if ret == JFileChooser.APPROVE_OPTION: file = j.getSelectedFile() if file == "" or file == None: return if file.exists(): os.remove(file.getAbsolutePath()) # print("File " + file.getName() + " has been deleted successfully.") else: print("The selected file does not exist.") else: print("File selection cancelled.") return def cancel_action(self, event): title = "" msg = "Do you wish to exit without saving?" opt1 = "Exit, don't save" opt2 = "Exit and Save Results" reply = OptionDialog().customQuestionMessage2str(msg, title, opt1, opt2) if reply == opt1: self.frame.dispatchEvent(WindowEvent(self.frame, WindowEvent.WINDOW_CLOSING)) else: #opt2 self.save_action(None) def save_action(self, event): [train, block, direction, length, speed_factor] = [0, 1, 2, 4, 5] # print "save action" for row in reversed(range(len(self.model.data))): train_name = self.model.data[row][train] block_name = self.model.data[row][block] train_direction = self.model.data[row][direction] train_length = self.model.data[row][length] train_speed_factor = self.model.data[row][speed_factor] result = train_direction if result == "forward": train_direction = "reverse" else: train_direction = "forward" if self.logLevel > 3: print "train_name", train_name,"train_direction", train_direction if train_name != "" and train_name != None and block_name != "" and block_name != None: if train_name not in trains_allocated: trains_allocated.append(train_name) self.super.add_to_train_list_and_set_new_train_location0(train_name, block_name, train_direction, train_length, train_speed_factor) self.super.set_blockcontents(block_name, train_name) self.super.set_length0(train_name) self.super.set_speed_factor0(train_name) self.model.data.pop(row) # print "end save action" self.completeTablePanel() if self.model.getRowCount() == 0: self.frame.dispatchEvent(WindowEvent(self.frame, WindowEvent.WINDOW_CLOSING)) def set_train_selections(self, combobox): pass def directory(self): path = jmri.util.FileUtil.getUserFilesPath() + "dispatcher" + java.io.File.separator + "setup_trains" if not os.path.exists(path): os.makedirs(path) return path + java.io.File.separator def write_list(self, a_list, file): # store list in binary file so 'wb' mode #file = self.directory() + "blockDirections.txt" if self.logLevel > 0: print "block_info" , a_list if self.logLevel > 0: print "file" , file file = str(file) with open(file, 'wb') as fp: pass if self.logLevel > 0: print "V" with open(file, 'wb') as fp: if self.logLevel > 0: print "B" for items in a_list: if self.logLevel > 0: print "C", items i = 0 for item in items: if self.logLevel > 0: print "item", item fp.write('"%s"' %item) if i != 4: fp.write(",") i+=1 fp.write('\n') # Read list to memory def read_list(self, file): file = str(file) if self.logLevel > 0: print "read list", file # for reading also binary mode is important #file = self.directory() + "blockDirections.txt" n_list = [] # try: with open(file, 'rb') as fp: for line in fp: if self.logLevel > 0: print "line" , line x = line[:-1] if self.logLevel > 0: print x y = x.split(",") #y = [item.replace('"','') for item in y] if self.logLevel > 0: print "y" , y n_list.append(y) return n_list class MyModelListener(TableModelListener): def __init__(self, class_createandshowGUI, class_NewTrainMaster): self.class_createandshowGUI = class_createandshowGUI self.class_NewTrainMaster = class_NewTrainMaster self.super = super self.cancel = False self.mode = class_createandshowGUI.mode def tableChanged(self, e) : global train_direction_gbl global trains_allocated row = e.getFirstRow() column = e.getColumn() model = e.getSource() columnName = model.getColumnName(column) data = model.getValueAt(row, column) class_createandshowGUI = self.class_createandshowGUI class_NewTrainMaster = self.class_NewTrainMaster tablemodel = class_createandshowGUI.model if column == 0: #trains class_createandshowGUI.combobox0.removeAllItems() #the non_allocated trains are stored in self.non_allocated_trains # each time a cell is edited we regenerate the list if trains in the drop down # we set to the non_allocated_trains less the ones marked ro be allocated in the table trains_in_table = [train for train in (model.getValueAt(r, column) for r in range(class_createandshowGUI.table.getRowCount())) if train in class_createandshowGUI.all_trains] # print "trains in table", trains_in_table # starting with non_allocated_trains remove the ones in my_train_list #trains_to_put_in_dropdown = [t for t in class_createandshowGUI.non_allocated_trains if t not in trains_in_table] if self.mode == "several trains": trains_to_put_in_dropdown = [t for t in class_createandshowGUI.non_allocated_trains] else: trains_to_put_in_dropdown = [t for t in class_createandshowGUI.allocated_trains] # print "trains_to_put_in_dropdown", trains_to_put_in_dropdown class_createandshowGUI.combobox0.removeAllItems() #put the remaining trains in the combo dropdown class_createandshowGUI.combobox0.addItem("") [class_createandshowGUI.combobox0.addItem(train) for train in trains_to_put_in_dropdown] class_createandshowGUI.trainColumn.setCellEditor(DefaultCellEditor(class_createandshowGUI.combobox0)); # populate the length of the engine train_name = model.getValueAt(row, 0) if train_name != "": [engine, train_length] = class_NewTrainMaster.get_train_length(train_name) model.setValueAt(train_length, row,4) #populate the speed factor of the engine train_name = model.getValueAt(row, 0) if train_name != "": [engine, train_speed_factor] = class_NewTrainMaster.get_train_speed_factor(train_name) model.setValueAt(train_speed_factor, row,5) # print "%%%%%%%%%%%%%%%%end col1 %%%%%%%%%%%%%%%%%%%%%%%%" elif column == 1: # sections class_createandshowGUI.combobox1.removeAllItems() # print "%%%%%%%%%%%%%%%%start col2 %%%%%%%%%%%%%%%%%%%%%%%%" # print "class_createandshowGUI.all_sections", class_createandshowGUI.all_sections # print "range class_createandshowGUI.table.getRowCount()", range(class_createandshowGUI.table.getRowCount()) for r in range(class_createandshowGUI.table.getRowCount()): # print "r",r,"column",column # print "r", r, "(model.getValueAt(r, column)", (model.getValueAt(r, column)) pass all_sections = [str(block.getUserName()) for block in class_createandshowGUI.all_sections] all_blocks = [str(block.getUserName()) for block in class_createandshowGUI.all_blocks] # print "all_sections", all_sections trains_in_table = \ [train for train in (model.getValueAt(r, column) for r in range(class_createandshowGUI.table.getRowCount())) if train in class_createandshowGUI.all_trains] X = [str(model.getValueAt(r, column)) for r in range(class_createandshowGUI.table.getRowCount())] # print "X", X blocks_in_table = [block for block in X if block in all_blocks] # print "sections in table", blocks_in_table # starting with non_allocated_trains remove the ones in my_train_list # print "sections to choose", class_createandshowGUI.sections_to_choose # print "trains_in_table",trains_in_table # print "sections True", class_createandshowGUI.train_blocks(trains_in_table, True) # print "sections False", class_createandshowGUI.train_blocks(trains_in_table, False) allocated_blocks = class_createandshowGUI.super.occupied_blocks_allocated() not_allocated_blocks = class_createandshowGUI.super.occupied_blocks_not_allocated() #blocks_to_put_in_dropdown = [s for s in not_allocated_blocks if s not in blocks_in_table] blocks_to_put_in_dropdown = [s for s in not_allocated_blocks] # print("blocks_to_put_in_dropdown", blocks_to_put_in_dropdown) #put the remaining trains in the combo dropdown class_createandshowGUI.combobox1.removeAllItems() class_createandshowGUI.combobox1.addItem("") [class_createandshowGUI.combobox1.addItem(section) for section in blocks_to_put_in_dropdown] # [class_createandshowGUI.combobox1.addItem(section) for section in blocks_to_put_in_dropdown] class_createandshowGUI.sectionColumn.setCellEditor(DefaultCellEditor(class_createandshowGUI.combobox1)); # print "%%%%%%%%%%%%%%%%end col2 %%%%%%%%%%%%%%%%%%%%%%%%" elif column == 3: # show the direction on the layout to enable the facing direction to be chosen # print "cancel on entry", self.cancel if self.cancel == True: self.cancel = False # print "set cancel", self.cancel return station_block_name = model.getValueAt(row, 1) # print "station_block_name", station_block_name if station_block_name != None and station_block_name != "" and station_block_name != "None Available": # print "here" [edge, train_direction_gbl, result] = class_createandshowGUI.super.highlight_penultimate_block(station_block_name) # print [edge, train_direction_gbl, result] self.cancel = True model.setValueAt(result, row, 2) #set the direction box to the result (forwards or reverse) model.setValueAt(False, row, 3) #reset the check box (need the self.cancel code to stop retriggering of the event code) else: OptionDialog().displayMessage("must set Block first") class ComboBoxCellRenderer (TableCellRenderer): def getTableCellRendererComponent(self, jtable, value, isSelected, hasFocus, row, column): combo = JComboBox() combo.setSelectedItem(value) return combo def getTableCellRendererComponent(self, jtable, value, isSelected, hasFocus, row, column) : panel = self.createPanel(value) return panel def createPanel(self, s) : p = JPanel(BorderLayout()) p.add(JLabel(s, JLabel.LEFT), BorderLayout.WEST) icon = UIManager.getIcon("Table.descendingSortIcon"); p.add(JLabel(icon, JLabel.RIGHT), BorderLayout.EAST); p.setBorder(BorderFactory.createLineBorder(Color.blue)); return p; class MyTableModel (DefaultTableModel): columnNames = ["Train", "Block", "Set Direction", "Direction Facing", "Length (scale metres)", "Speed Factor"] def __init__(self): self.data = [] self.add_row() def add_row(self): self.data.append(["", "", "click ->", False, 10, 100]) def populate_existing(self, blocks_to_put_in_dropdown): # print "populate existing" for row in reversed(range(len(self.data))): self.data.pop(row) items_to_put_in_dropdown = [] for block_name in blocks_to_put_in_dropdown: train_name = NewTrainMaster().get_blockcontents(block_name) # if train_name == "" or train_name is None: # continue if train_name == "" or train_name is None: train_direction = "unassigned" train_length = -1 current_speed_factor = -1 else: # print "block_name", block_name, "train_name", train_name [engine,current_length] = NewTrainMaster().get_train_length(train_name) train_length = engine.getLength() [engine, current_speed_factor] = NewTrainMaster().get_train_speed_factor(train_name) # current_speed_factor_str = "speed factor " + current_speed_factor current_speed_factor_str = engine.getComment() train = trains[train_name] result = train["direction"] # print "train[direction] loading to put in dropdown", result if result == "forward": train_direction = "reverse" else: train_direction = "forward" # print "train", train, train_direction items_to_put_in_dropdown.append([train_name,block_name,train_direction, False, train_length, current_speed_factor ]) # print "items_to_put_in_dropdown", items_to_put_in_dropdown for item in items_to_put_in_dropdown: self.data.append(item) # self.completeTablePanel() pass def getColumnCount(self) : return len(self.columnNames) def getRowCount(self) : return len(self.data) def getColumnName(self, col) : return self.columnNames[col] def getValueAt(self, row, col) : return self.data[row][col] def getColumnClass(self, c) : if c <= 1: return java.lang.Boolean.getClass(JComboBox) return java.lang.Boolean.getClass(self.getValueAt(0,c)) #only include if table editable def isCellEditable(self, row, col) : # Note that the data/cell address is constant, # no matter where the cell appears onscreen. if col != 2: return True else: return False # only include if data can change. def setValueAt(self, value, row, col) : self.data[row][col] = value self.fireTableCellUpdated(row, col)