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}