001package jmri.jmrit.beantable; 002 003import java.awt.event.ActionEvent; 004import java.beans.PropertyChangeEvent; 005import java.beans.PropertyChangeListener; 006 007import javax.swing.*; 008import javax.swing.table.TableRowSorter; 009 010import jmri.*; 011import jmri.jmrit.beantable.signalmast.SignalMastLogicTableDataModel; 012import jmri.jmrit.display.layoutEditor.LayoutBlockManager; 013import jmri.managers.DefaultSignalMastLogicManager; 014import jmri.util.ThreadingUtil; 015import jmri.util.JmriJFrame; 016import jmri.util.swing.JmriJOptionPane; 017 018public class SignalMastLogicTableAction extends AbstractTableAction<SignalMastLogic> { 019 020 /** 021 * Create an action with a specific title. 022 * <p> 023 * Note that the argument is the Action title, not the title of the 024 * resulting frame. Perhaps this should be changed? 025 * 026 * @param s title of the action 027 */ 028 public SignalMastLogicTableAction(String s) { 029 super(s); 030 } 031 032 public SignalMastLogicTableAction() { 033 this(Bundle.getMessage("TitleSignalMastLogicTable")); 034 } 035 036 @Override 037 public void actionPerformed(ActionEvent e) { 038 // create the JTable model, with changes for specific NamedBean 039 createModel(); 040 TableRowSorter<BeanTableDataModel<SignalMastLogic>> sorter = new TableRowSorter<>(m); 041 JTable dataTable = m.makeJTable(m.getMasterClassName(), m, sorter); 042 // create the frame 043 f = new jmri.jmrit.beantable.BeanTableFrame<SignalMastLogic>(m, helpTarget(), dataTable) { 044 }; 045 setMenuBar(f); 046 setTitle(); 047 addToFrame(f); 048 f.pack(); 049 f.setVisible(true); 050 } 051 052 /** 053 * Insert a table specific Tools menu. Account for the Window and Help 054 * menus, which are already added to the menu bar as part of the creation of 055 * the JFrame, by adding the Tools menu 2 places earlier unless the table is 056 * part of the ListedTableFrame, that adds the Help menu later on. 057 * 058 * @param f the JFrame of this table 059 */ 060 @Override 061 public void setMenuBar(BeanTableFrame<SignalMastLogic> f) { 062 final JmriJFrame finalF = f; // needed for anonymous ActionListener class 063 JMenuBar menuBar = f.getJMenuBar(); 064 int pos = menuBar.getMenuCount() - 1; // count the number of menus to insert the TableMenu before 'Window' and 'Help' 065 int offset = 1; 066 log.debug("setMenuBar number of menu items = {}", pos); 067 for (int i = 0; i <= pos; i++) { 068 if (menuBar.getComponent(i) instanceof JMenu) { 069 if (((AbstractButton) menuBar.getComponent(i)).getText().equals(Bundle.getMessage("MenuHelp"))) { 070 offset = -1; // correct for use as part of ListedTableAction where the Help Menu is not yet present 071 } 072 } 073 } 074 JMenu pathMenu = new JMenu(Bundle.getMessage("MenuTools")); 075 menuBar.add(pathMenu, pos + offset); 076 JMenuItem item = new JMenuItem(Bundle.getMessage("MenuItemAutoGen")); 077 pathMenu.add(item); 078 item.addActionListener((ActionEvent e) -> { 079 autoCreatePairs(finalF); 080 }); 081 item = new JMenuItem(Bundle.getMessage("MenuItemAutoGenSections")); 082 pathMenu.add(item); 083 item.addActionListener((ActionEvent e) -> { 084 ((DefaultSignalMastLogicManager) InstanceManager.getDefault(SignalMastLogicManager.class)).generateSection(); 085 InstanceManager.getDefault(SectionManager.class).generateBlockSections(); 086 JmriJOptionPane.showMessageDialog(finalF, Bundle.getMessage("SectionGenerationComplete")); 087 }); 088 JMenuItem setSMLDirSensors = new JMenuItem(Bundle.getMessage("MenuItemAddDirectionSensors")); 089 pathMenu.add(setSMLDirSensors); 090 setSMLDirSensors.addActionListener((ActionEvent e) -> { 091 int n = InstanceManager.getDefault(SignalMastLogicManager.class).setupSignalMastsDirectionSensors(); 092 if (n > 0) { 093 JmriJOptionPane.showMessageDialog(finalF, java.text.MessageFormat.format( 094 Bundle.getMessage("MenuItemAddDirectionSensorsErrorCount"), n), 095 Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE); 096 } 097 }); 098 099 } 100 101 @Override 102 protected void createModel() { 103 m = new SignalMastLogicTableDataModel(); 104 } 105 106 @Override 107 protected void setTitle() { 108 f.setTitle(Bundle.getMessage("TitleSignalMastLogicTable")); 109 } 110 111 @Override 112 protected String helpTarget() { 113 return "package.jmri.jmrit.beantable.SignalMastLogicTable";// NOI18N 114 } 115 116 @Override 117 protected void addPressed(ActionEvent e) { 118 sigLog.setMast(null, null); 119 sigLog.actionPerformed(e); 120 } 121 122 JmriJFrame signalMastLogicFrame = null; 123 JLabel sourceLabel = new JLabel(); 124 125 void autoCreatePairs(JmriJFrame f) { 126 if (!InstanceManager.getDefault(LayoutBlockManager.class).isAdvancedRoutingEnabled()) { 127 int response = JmriJOptionPane.showConfirmDialog(f, Bundle.getMessage("EnableLayoutBlockRouting"), 128 Bundle.getMessage("TitleBlockRouting"), JmriJOptionPane.YES_NO_OPTION); 129 if (response == 0) { 130 InstanceManager.getDefault(LayoutBlockManager.class).enableAdvancedRouting(true); 131 JmriJOptionPane.showMessageDialog(f, Bundle.getMessage("LayoutBlockRoutingEnabled")); 132 } else { 133 return; 134 } 135 } 136 signalMastLogicFrame = new JmriJFrame(Bundle.getMessage("DiscoverSignalMastPairs"), false, false); 137 signalMastLogicFrame.setPreferredSize(null); 138 JPanel panel1 = new JPanel(); 139 sourceLabel = new JLabel(Bundle.getMessage("DiscoveringSignalMastPairs")); 140 panel1.add(sourceLabel); 141 signalMastLogicFrame.add(panel1); 142 signalMastLogicFrame.pack(); 143 signalMastLogicFrame.setVisible(true); 144 145 final JCheckBox genSect = new JCheckBox(Bundle.getMessage("AutoGenSectionAfterLogic")); 146 genSect.setToolTipText(Bundle.getMessage("AutoGenSectionAfterLogicToolTip")); 147 Object[] params = {Bundle.getMessage("AutoGenSignalMastLogicMessage"), " ", genSect}; 148 int retval = JmriJOptionPane.showConfirmDialog(f, params, Bundle.getMessage("AutoGenSignalMastLogicTitle"), 149 JmriJOptionPane.YES_NO_OPTION); 150 151 if ( retval == JmriJOptionPane.YES_OPTION ) { 152 InstanceManager.getDefault(SignalMastLogicManager.class).addPropertyChangeListener(propertyGenerateListener); 153 // This process can take some time, so we do split it off then return to Swing/AWT 154 Runnable r = () -> { 155 //While the global discovery is taking place we remove the listener as this can result in a race condition. 156 ((SignalMastLogicTableDataModel)m).setSuppressUpdate(true); 157 try { 158 InstanceManager.getDefault(SignalMastLogicManager.class).automaticallyDiscoverSignallingPairs(); 159 } catch (JmriException e) { 160 // Notify of problem 161 try { 162 SwingUtilities.invokeAndWait(() -> { 163 InstanceManager.getDefault(SignalMastLogicManager.class).removePropertyChangeListener(propertyGenerateListener); 164 JmriJOptionPane.showMessageDialog(f, e.toString()); 165 signalMastLogicFrame.setVisible(false); 166 }); 167 } catch (java.lang.reflect.InvocationTargetException ex) { 168 log.error("failed to notify of problem with automaticallyDiscoverSignallingPairs", ex); 169 } catch (InterruptedException ex) { 170 log.error("interrupted while notifying of problem with automaticallyDiscoverSignallingPairs", ex); 171 } 172 } 173 174 // process complete, update GUI 175 try { 176 SwingUtilities.invokeAndWait(() -> { 177 m.updateNameList(); 178 ((SignalMastLogicTableDataModel)m).setSuppressUpdate(false); 179 m.fireTableDataChanged(); 180 if (genSect.isSelected()) { 181 ((DefaultSignalMastLogicManager) InstanceManager.getDefault(SignalMastLogicManager.class)).generateSection(); 182 InstanceManager.getDefault(SectionManager.class).generateBlockSections(); 183 } 184 }); 185 } catch (java.lang.reflect.InvocationTargetException ex) { 186 log.error("failed to update at end of automaticallyDiscoverSignallingPairs", ex); 187 } catch (InterruptedException ex) { 188 log.error("interrupted during update at end of automaticallyDiscoverSignallingPairs", ex); 189 } 190 }; 191 Thread thr = ThreadingUtil.newThread(r, "Discover Signal Mast Logic"); // NOI18N 192 thr.start(); 193 194 } else { 195 signalMastLogicFrame.setVisible(false); 196 } 197 } 198 199 protected transient PropertyChangeListener propertyGenerateListener = new PropertyChangeListener() { 200 @Override 201 public void propertyChange(PropertyChangeEvent evt) { 202 if (evt.getPropertyName().equals("autoGenerateComplete")) {// NOI18N 203 if (signalMastLogicFrame != null) { 204 signalMastLogicFrame.setVisible(false); 205 } 206 InstanceManager.getDefault(SignalMastLogicManager.class).removePropertyChangeListener(this); 207 JmriJOptionPane.showMessageDialog(null, Bundle.getMessage("SignalMastPairGenerationComplete")); 208 } else if (evt.getPropertyName().equals("autoGenerateUpdate")) {// NOI18N 209 sourceLabel.setText((String) evt.getNewValue()); 210 signalMastLogicFrame.pack(); 211 signalMastLogicFrame.repaint(); 212 } 213 } 214 }; 215 216 private final jmri.jmrit.signalling.SignallingAction sigLog = new jmri.jmrit.signalling.SignallingAction(); 217 218 @Override 219 protected String getClassName() { 220 return SignalMastLogicTableAction.class.getName(); 221 } 222 223 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(SignalMastLogicTableAction.class); 224}