Files
2026-06-17 14:00:51 +02:00

641 lines
28 KiB
Python

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, WindowAdapter
from java.awt import GridLayout, Dimension, BorderLayout, Color
from javax.swing.table import AbstractTableModel, DefaultTableModel
from java.lang.Object import getClass
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
import java.awt.Dimension
from java.beans import PropertyChangeListener
class StopDispatcherWindowListener(WindowAdapter):
def __init__(self, listener, model):
self.listener = listener
self.model = model
def windowClosing(self, event):
# print "StopDispatcherSystem: Window closing, removing ActiveTrainsTableListener."
if self.model is not None:
self.model.removeTableModelListener(self.listener)
class ActiveTrainsTableListener(TableModelListener):
def __init__(self, parent):
self.parent = parent
# print "ActiveTrainsTableListener initialized"
def tableChanged(self, event):
# print "ActiveTrainsTableListener tableChanged event"
self.parent.populate_action(None)
class createandshowGUI3(TableModelListener):
def __init__(self, class_StopMaster):
global DF
global CreateAndShowGUI3_frame
DF = jmri.InstanceManager.getDefault(jmri.jmrit.dispatcher.DispatcherFrame)
#DF.setState(DF.ICONIFIED);
self.activeTrainsList = DF.getActiveTrainsList()
self.logLevel = 0
self.class_StopMaster = class_StopMaster
#Create and set up the window.
self.initialise_model(class_StopMaster)
CreateAndShowGUI3_frame = JFrame("Modify System")
self.frame = CreateAndShowGUI3_frame
self.frame.setSize(600, 600)
self.completeTablePanel1()
self.completeTablePanel()
# print "about to populate"
self.populate_action(None)
self.cancel = False
# print "Adding TableModelListener to DispatcherFrame ActiveTrainsTableModel"
if DF is not None:
self.activeTrainsTableModel = DF.activeTrainsTableModel
if self.activeTrainsTableModel is not None:
self.activeTrainsTableListener = ActiveTrainsTableListener(self)
self.activeTrainsTableModel.addTableModelListener(self.activeTrainsTableListener)
self.frame.addWindowListener(StopDispatcherWindowListener(self.activeTrainsTableListener, self.activeTrainsTableModel))
else:
print "Error: ActiveTrainsTableModel not found."
else:
print "Error: DispatcherFrame not found, listener not attached."
def completeTablePanel1(self):
self.topPanel= JPanel()
self.topPanel.setLayout(BoxLayout(self.topPanel, BoxLayout.X_AXIS))
self.self_table()
self.scrollPane = JScrollPane(self.table)
self.scrollPane.setPreferredSize(Dimension(1500, 300))
self.topPanel.add(self.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_populate = JButton("Refresh", 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.createRigidArea(Dimension(10, 0)))
button_del_trains = JButton("Delete Trains", actionPerformed = self.del_trains_action)
self.buttonPane.add(button_del_trains)
self.buttonPane.add(Box.createHorizontalGlue())
button_del_transits = JButton("Delete Transits", actionPerformed = self.del_transits_action)
self.buttonPane.add(button_del_transits)
self.buttonPane.add(Box.createHorizontalGlue())
button_del_routes = JButton("Delete Routes", actionPerformed = self.del_routes_action)
self.buttonPane.add(button_del_routes)
self.buttonPane.add(Box.createHorizontalGlue())
button_cancel = JButton("Close", actionPerformed = self.cancel_action)
self.buttonPane.add(button_cancel)
self.buttonPane.add(Box.createHorizontalGlue())
contentPane = self.frame.getContentPane()
contentPane.removeAll()
contentPane.add(self.topPanel, BorderLayout.CENTER)
contentPane.add(self.buttonPane, BorderLayout.PAGE_END)
self.frame.pack()
self.frame.setVisible(True)
return
def completeTablePanel(self):
contentPane = self.frame.getContentPane()
contentPane.removeAll()
contentPane.add(self.topPanel, BorderLayout.CENTER)
contentPane.add(self.buttonPane, BorderLayout.PAGE_END)
size_of_one_row = 30
height = 60
for row in reversed(range(len(self.model.data))):
height += size_of_one_row
# print "height" , height
# print "height" , height
height = min(height, 800)
self.scrollPane.setPreferredSize(Dimension(1500, height))
self.frame.pack();
self.frame.setVisible(True)
return
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(20, 0)))
row1.add(row1_2_button)
layout = BorderLayout()
# layout.setHgap(10);
# layout.setVgap(10);
jPanel = JPanel()
jPanel.setLayout(layout);
jPanel.add(self.table,BorderLayout.NORTH)
jPanel.add(row1,BorderLayout.SOUTH)
#return jPanel
return topPanel
def initialise_model(self, class_StopMaster):
self.model = None
self.model = MyTableModel3()
# print "model created MyTableModel3"
self.table = JTable(self.model)
self.model.addTableModelListener(MyModelListener3(self, class_StopMaster));
self.class_StopMaster = class_StopMaster
def self_table(self):
self.table.setFillsViewportHeight(True);
self.table.setRowHeight(30);
columnModel = self.table.getColumnModel();
[setup_train_col, del_setup_train_col, block_col, direction_col, direction_change_col, active_train_col, transit_col, del_transit_col, route_col, del_route_col] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
columnModel.getColumn(setup_train_col).setPreferredWidth(150);
columnModel.getColumn(del_setup_train_col).setPreferredWidth(60);
columnModel.getColumn(block_col).setPreferredWidth(200);
columnModel.getColumn(direction_col).setPreferredWidth(100);
columnModel.getColumn(direction_change_col).setPreferredWidth(60);
columnModel.getColumn(active_train_col).setPreferredWidth(150);
columnModel.getColumn(transit_col).setPreferredWidth(200);
columnModel.getColumn(del_transit_col).setPreferredWidth(60);
columnModel.getColumn(route_col).setPreferredWidth(200);
columnModel.getColumn(del_route_col).setPreferredWidth(60);
jpane = JScrollPane(self.table)
panel = JPanel()
panel.add(jpane)
result = JScrollPane(panel)
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 called"
DF = jmri.InstanceManager.getDefault(jmri.jmrit.dispatcher.DispatcherFrame)
self.activeTrainsList = DF.getActiveTrainsList()
trains_to_put_in_firstcol = self.activeTrainsList
self.model.populate()
self.completeTablePanel()
# def tidy_action(self,e):
# self.model.remove_not_set_row()
# self.completeTablePanel()
def del_trains_action(self, e):
global trains_allocated
# for train_name_to_remove in trains_allocated:
# trains_allocated.remove(train_name_to_remove)
trains_allocated_list = java.util.concurrent.CopyOnWriteArrayList()
for train in trains_allocated:
trains_allocated_list.add(train)
for train in trains_allocated_list:
if self.logLevel > 0: print "train in trains_allocated", train, ": trains_allocated", trains_allocated
trains_allocated.remove(train)
self.model.populate()
self.completeTablePanel()
def delete_transits(self):
global trains
# need to avoid concurrency issues when deleting more that one transit
# use java.util.concurrent.CopyOnWriteArrayList so can iterate through the transits while deleting
DF = jmri.InstanceManager.getDefault(jmri.jmrit.dispatcher.DispatcherFrame)
#DF.setState(DF.ICONIFIED);
activeTrainList = java.util.concurrent.CopyOnWriteArrayList()
for activeTrain in DF.getActiveTrainsList():
activeTrainList.add(activeTrain)
for activeTrain in activeTrainList:
if self.logLevel > 0: print ("active train", activeTrain)
#swap the direction of the train
# (found need to do this as train went off in wrong direction after setting new trainsit)
train_name = activeTrain.getTrainName()
MyModelListener3(self, self.class_StopMaster).swap_direction(train_name)
DF.terminateActiveTrain(activeTrain, True, False)
DF = None
self.model.populate()
self.completeTablePanel()
def del_transits_action(self,e):
self.delete_transits()
self.model.populate()
self.completeTablePanel()
def delete_routes(self):
DF = jmri.InstanceManager.getDefault(jmri.jmrit.dispatcher.DispatcherFrame)
activeTrainList = java.util.concurrent.CopyOnWriteArrayList()
for activeTrain in DF.getActiveTrainsList():
activeTrainList.add(activeTrain)
for activeTrain in activeTrainList:
train_name = activeTrain.getTrainName()
if train_name is not None and train_name != "":
MyModelListener3(self, self.class_StopMaster).delete_route(activeTrain.getTrainName())
self.model.populate()
self.completeTablePanel()
def del_routes_action(self, e):
self.delete_routes()
self.completeTablePanel()
def cancel_action(self, event):
self.frame.dispatchEvent(WindowEvent(self.frame, WindowEvent.WINDOW_CLOSING));
def refresh(self):
self.completeTablePanel()
class MyModelListener3(TableModelListener):
def __init__(self, class_createandshowGUI3, class_StopMaster):
self.class_createandshowGUI3 = class_createandshowGUI3
self.class_StopMaster = class_StopMaster
self.cancel = False
self.logLevel = 0
# DF = jmri.InstanceManager.getDefault(jmri.jmrit.dispatcher.DispatcherFrame)
# self.java_active_trains_list = DF.getActiveTrainsList()
def tableChanged(self, e) :
[setup_train_col, del_setup_train_col, block_col, direction_col, direction_change_col, active_train_col, transit_col, del_transit_col, route_col, del_route_col] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# print "tableChanged event: row={}, col={}, type={}".format(e.getFirstRow(), e.getColumn(), e.getType())
global trains_allocated
row = e.getFirstRow()
column = e.getColumn()
model = e.getSource()
columnName = model.getColumnName(column)
data = model.getValueAt(row, column)
tablemodel = self.class_createandshowGUI3.model
DF = jmri.InstanceManager.getDefault(jmri.jmrit.dispatcher.DispatcherFrame)
self.java_active_trains_list = DF.getActiveTrainsList()
if column == direction_change_col:
train_name = str(model.getValueAt(row, setup_train_col))
self.swap_direction_of_train(train_name) # swap throttle direction
self.swap_direction(train_name) # swap active train direction
self.class_createandshowGUI3.populate_action(None)
if column == del_setup_train_col:
train_name = str(model.getValueAt(row, setup_train_col))
if self.logLevel > 0: print "trains_allocated", trains_allocated
if self.logLevel > 0: print "train_name", train_name
for train in trains_allocated:
if train == train_name:
trains_allocated.remove(train)
self.class_StopMaster.remove_values(train)
# model.fireTableDataChanged()
# self.class_createandshowGUI3.refresh()
# self.class_createandshowGUI3.completeTablePanel()
self.class_createandshowGUI3.populate_action(None)
elif column == del_transit_col:
transit = str(model.getValueAt(row, transit_col))
train_name = [active_train.getTrainName() for active_train in self.java_active_trains_list \
if active_train.getTransit().getUserName() == transit]
if len(train_name) > 0:
self.delete_transit(train_name[0])
#tablemodel.fireTableDataChanged()
#self.class_createandshowGUI3.refresh()
self.class_createandshowGUI3.populate_action(None)
self.class_createandshowGUI3.completeTablePanel()
# train_name = str(model.getValueAt(row, setup_train_col))
# self.delete_transit(train_name)
# #self.class_createandshowGUI3.completeTablePanel()
# model.fireTableDataChanged()
elif column == del_route_col:
transit = str(model.getValueAt(row, transit_col))
train_name = [active_train.getTrainName() for active_train in self.java_active_trains_list \
if active_train.getTransit().getUserName() == transit]
# train_name = str(model.getValueAt(row, setup_train_col))
if len(train_name) > 0:
self.delete_route(train_name[0])
#tablemodel.fireTableDataChanged()
#self.class_createandshowGUI3.refresh()
self.class_createandshowGUI3.populate_action(None)
self.class_createandshowGUI3.completeTablePanel()
else:
pass
def swap_direction_of_train(self, train_name):
# get throttle of train
throttle = self.get_throttle(train_name)
self.swap_throttle_direction(throttle)
def swap_throttle_direction(self, throttle):
if throttle == None:
print "no throttle"
return
if throttle.getIsForward():
throttle.setIsForward(False)
else:
throttle.setIsForward(True)
def get_throttle(self, train_name):
dccAddress = self.get_dcc_address(train_name)
if dccAddress > 127:
isLong = True
else:
isLong = False
if dccAddress != None:
throttle = self.class_StopMaster.getThrottle(dccAddress, isLong)
else:
throttle = None
return throttle
def get_dcc_address(self, train_name):
if train_name != None:
try:
r = jmri.jmrit.roster.Roster.getDefault()
for roster_entry in jmri.jmrit.roster.Roster.getAllEntries(r):
# print "roster_entry.getId", roster_entry.getId()
if str(roster_entry.getId()) == str(train_name):
return int(roster_entry.getDccAddress())
# print roster_entry.getId()
except Exception as e:
# Handle any other exceptions
print("error when getting dcc_address: ", e)
return None
else:
return None
def delete_route(self, train_name):
global instanceList
#stop all threads
activeThreadList = java.util.concurrent.CopyOnWriteArrayList()
for thread in instanceList:
activeThreadList.add(thread)
for thread in activeThreadList:
thread_name = "" + thread.getName()
if thread_name.startswith("running_route_"):
#determine the train nme
thread_train_name = self.class_StopMaster.determine_train_name(thread_name,thread)
#remove the train from the transit
if train_name == thread_train_name:
#remove the train from the list of trains
self.remove_train_name(train_name)
if thread is not None:
if thread.isRunning():
if self.logLevel > 0: print 'Stop "{}" thread'.format(thread.getName())
thread.stop()
instanceList = [instance for instance in instanceList if instance != thread]
else:
#need this for scheduler in wait state
thread.stop()
instanceList = [instance for instance in instanceList if instance != thread]
def remove_train_name(self, train_name):
global trains_allocated
global trains_dispatched
if self.logLevel > 0: print("train to remove", train_name)
# for train in trains_allocated:
# if self.logLevel > 0: print "train in trains_allocated", train, ": trains_allocated", trains_allocated
# if train == train_name:
# trains_allocated.remove(train)
for train in trains_dispatched:
#print "train in trains_allocated", train, ": trains_allocated", trains_allocated
if train == train_name:
trains_dispatched.remove(train)
def delete_transit(self, train_name):
if self.logLevel > 0: print "delete_transit: train_name", train_name
DF = jmri.InstanceManager.getDefault(jmri.jmrit.dispatcher.DispatcherFrame)
activeTrainList = java.util.concurrent.CopyOnWriteArrayList()
for activeTrain in DF.getActiveTrainsList():
activeTrainList.add(activeTrain)
active_train = [activeTrain for activeTrain in activeTrainList \
if activeTrain.getTrainName() == train_name]
if active_train == []:
print "No dispatch to delete"
return
if self.logLevel > 0: print ("active_train", active_train[0].getActiveTrainName())
if len(active_train) > 0:
DF.terminateActiveTrain(active_train[0], True, True)
def swap_direction(self, train_name):
global trains
# train = [trains[t_name] for t_name in trains if t_name == train_name]
train = trains[train_name]
# print "train", train
direction_of_train = train["direction"]
# print "direction_of_train", direction_of_train
if direction_of_train == "forward":
direction_of_train = "reverse"
else:
direction_of_train = "forward"
train["direction"] = direction_of_train
class ComboBoxCellRenderer1 (TableCellRenderer):
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(str(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 MyTableModel3 (DefaultTableModel):
columnNames = ["Train", "Delete Train", "Block", "Direction", "Change Dir", "Active Train", "Transit", "Del Transit", "Route", "Del Route"]
def __init__(self):
l1 = ["", False, "", "", False, "", "", False, "", False]
self.data = [l1]
self.logLevel = 0
def remove_not_set_row(self):
for row in reversed(range(len(self.data))):
if self.data[row][1] == "":
self.data.pop(row)
def populate(self):
# print "populate"
global trains_allocated
global trains_dispatched
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)
# print "Populate called. Active trains count: ", java_active_trains_list.size()
# print "trains_allocated (id={}): {}".format(id(trains_allocated), trains_allocated)
# print "trains_dispatched (id={}): {}".format(id(trains_dispatched), trains_dispatched)
if self.logLevel > 0: print ("populate")
for row in reversed(range(len(self.data))):
self.data.pop(row)
# append all active trains to put in dropdown
active_train_name = ""
transit = ""
transit_name = ""
route_name = ""
# print "trains_allocated", trains_allocated
for setup_train in trains_allocated:
active_train = [active_train for active_train in java_active_trains_list \
if active_train.getTrainName() == setup_train]
# print "Checking setup_train: ", setup_train, ". Found active: ", len(active_train)
if self.logLevel > 0: print "active_train", active_train, "len(active_train)", len(active_train)
block_names = [block.getUserName() for block in blocks.getNamedBeanSet() if block.getValue() == setup_train]
if block_names != []:
block = block_names[0]
else:
block = ""
if len(active_train) > 0 :
active_train = active_train[0]
active_train_name = active_train.getTrainName()
direction = trains[active_train_name]["direction"]
# print "active_train_name", active_train_name, "direction", direction, "trains[active_train_name]['direction']"
# print [block.getUserName() for block in blocks if block.getValue() == active_train_name]
# block = [block.getUserName() for block in blocks if block.getValue() == active_train_name][0]
transit = [active_train.getTransit() for active_train in java_active_trains_list \
if active_train.getTrainName() == active_train_name]
if self.logLevel > 0: print "active_train_name", active_train_name
if self.logLevel > 0: print "transit" , transit
transit_name = transit[0].getUserName()
else:
block_names = [block.getUserName() for block in blocks.getNamedBeanSet() if block.getValue() == setup_train]
if block_names != []:
block = block_names[0]
else:
block = ""
active_train = ""
active_train_name = ""
direction = trains[setup_train]["direction"]
transit_name = ""
if self.logLevel > 0: print("train0", setup_train, "direction", direction)
if self.logLevel > 0: print("transit_name", transit_name)
route_name = self.get_route(active_train_name)
if self.logLevel > 0: print ("route_name", route_name)
if direction == "forward":
train_direction_displayed = "reverse"
else:
train_direction_displayed = "forward"
self.data.append([setup_train, False, block, train_direction_displayed, False, active_train_name, transit_name, False, route_name, False])
active_trains_not_setup = [active_train_name for active_train_name in trains_dispatched \
if active_train_name not in trains_allocated]
for active_train_name in active_trains_not_setup:
active_train = [active_train for active_train in java_active_trains_list \
if active_train.getTrainName() == active_train_name]
if active_train_name != "":
found_blocks = [block.getUserName() for block in blocks.getNamedBeanSet() if block.getValue() == active_train_name]
if found_blocks:
block = found_blocks[0]
else:
block = ""
else:
block = ""
if len(active_train) > 0 :
active_train = active_train[0]
active_train_name = active_train.getTrainName()
direction = trains[active_train_name]["direction"]
transit = [active_train.getTransit() for active_train in java_active_trains_list \
if active_train.getTrainName() == active_train_name]
transit_name = transit[0].getUserName()
else:
active_train = ""
active_train_name = ""
direction = trains[active_train_name]["direction"]
transit_name = ""
if self.logLevel > 0: print("train", active_train_name, "direction", direction)
route_name = self.get_route(active_train_name)
if self.logLevel > 0: print ("route_name", route_name)
self.data.append(["", False, block, direction, False, active_train_name, transit_name, False, route_name, False])
# print "trains", trains
def get_route(self, train_name):
#look at all threads
activeThreadList = java.util.concurrent.CopyOnWriteArrayList()
for thread in instanceList:
activeThreadList.add(thread)
for thread in instanceList:
thread_name = "" + thread.getName()
if thread_name.startswith("running_route_"):
route_name = thread_name.replace("running_route_", "")
thread_train_name = StopMaster().determine_train_name(thread_name,thread)
if self.logLevel > 0: print "thread name", thread_name, "route_name", route_name, "thread_train_name", thread_train_name, "train_name", train_name
# #remove the train from the transit
if train_name == thread_train_name:
return route_name
#return route_name
return ""
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.
return True
# only include if data can change.
def setValueAt(self, value, row, col) :
self.data[row][col] = value
self.fireTableCellUpdated(row, col)