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)