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( e -> autoCreatePairs(finalF));
079        item = new JMenuItem(Bundle.getMessage("MenuItemAutoGenSections"));
080        pathMenu.add(item);
081        item.addActionListener( e -> {
082            ((DefaultSignalMastLogicManager) InstanceManager.getDefault(SignalMastLogicManager.class)).generateSection();
083            InstanceManager.getDefault(SectionManager.class).generateBlockSections();
084            JmriJOptionPane.showMessageDialog(finalF, Bundle.getMessage("SectionGenerationComplete"));
085        });
086        JMenuItem setSMLDirSensors = new JMenuItem(Bundle.getMessage("MenuItemAddDirectionSensors"));
087        pathMenu.add(setSMLDirSensors);
088        setSMLDirSensors.addActionListener( e -> {
089            int n = InstanceManager.getDefault(SignalMastLogicManager.class).setupSignalMastsDirectionSensors();
090            if (n > 0) {
091                JmriJOptionPane.showMessageDialog(finalF, java.text.MessageFormat.format(
092                        Bundle.getMessage("MenuItemAddDirectionSensorsErrorCount"), n),
093                        Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE);
094            }
095        });
096
097    }
098
099    @Override
100    protected void createModel() {
101        m = new SignalMastLogicTableDataModel();
102    }
103
104    @Override
105    protected void setTitle() {
106        f.setTitle(Bundle.getMessage("TitleSignalMastLogicTable"));
107    }
108
109    @Override
110    protected String helpTarget() {
111        return "package.jmri.jmrit.beantable.SignalMastLogicTable";// NOI18N
112    }
113
114    @Override
115    protected void addPressed(ActionEvent e) {
116        sigLog.setMast(null, null);
117        sigLog.actionPerformed(e);
118    }
119
120    private JmriJFrame signalMastLogicFrame = null;
121    private JLabel sourceLabel = new JLabel();
122
123    void autoCreatePairs(JmriJFrame f) {
124        if (!InstanceManager.getDefault(LayoutBlockManager.class).isAdvancedRoutingEnabled()) {
125            int response = JmriJOptionPane.showConfirmDialog(f, Bundle.getMessage("EnableLayoutBlockRouting"),
126                    Bundle.getMessage("TitleBlockRouting"), JmriJOptionPane.YES_NO_OPTION);
127            if (response == 0) {
128                InstanceManager.getDefault(LayoutBlockManager.class).enableAdvancedRouting(true);
129                JmriJOptionPane.showMessageDialog(f, Bundle.getMessage("LayoutBlockRoutingEnabled"));
130            } else {
131                return;
132            }
133        }
134        signalMastLogicFrame = new JmriJFrame(Bundle.getMessage("DiscoverSignalMastPairs"), false, false);
135        signalMastLogicFrame.setPreferredSize(null);
136        JPanel panel1 = new JPanel();
137        sourceLabel = new JLabel(Bundle.getMessage("DiscoveringSignalMastPairs"));
138        panel1.add(sourceLabel);
139        signalMastLogicFrame.add(panel1);
140        signalMastLogicFrame.pack();
141        signalMastLogicFrame.setVisible(true);
142
143        final JCheckBox genSect = new JCheckBox(Bundle.getMessage("AutoGenSectionAfterLogic"));
144        genSect.setToolTipText(Bundle.getMessage("AutoGenSectionAfterLogicToolTip"));
145        Object[] params = {Bundle.getMessage("AutoGenSignalMastLogicMessage"), " ", genSect};
146        int retval = JmriJOptionPane.showConfirmDialog(f, params, Bundle.getMessage("AutoGenSignalMastLogicTitle"),
147                JmriJOptionPane.YES_NO_OPTION);
148
149        if ( retval == JmriJOptionPane.YES_OPTION ) {
150            InstanceManager.getDefault(SignalMastLogicManager.class).addPropertyChangeListener(propertyGenerateListener);
151            // This process can take some time, so we do split it off then return to Swing/AWT
152            Runnable r = () -> {
153                //While the global discovery is taking place we remove the listener as this can result in a race condition.
154                ((SignalMastLogicTableDataModel)m).setSuppressUpdate(true);
155                try {
156                    InstanceManager.getDefault(SignalMastLogicManager.class).automaticallyDiscoverSignallingPairs();
157                } catch (JmriException e) {
158                    // Notify of problem
159                    try {
160                        SwingUtilities.invokeAndWait(() -> {
161                            InstanceManager.getDefault(SignalMastLogicManager.class).removePropertyChangeListener(propertyGenerateListener);
162                            JmriJOptionPane.showMessageDialog(f, e.toString());
163                            signalMastLogicFrame.setVisible(false);
164                        });
165                    } catch (java.lang.reflect.InvocationTargetException ex) {
166                        log.error("failed to notify of problem with automaticallyDiscoverSignallingPairs", ex);
167                    } catch (InterruptedException ex) {
168                        log.error("interrupted while notifying of problem with automaticallyDiscoverSignallingPairs", ex);
169                    }
170                }
171
172                // process complete, update GUI
173                try {
174                    SwingUtilities.invokeAndWait(() -> {
175                        m.updateNameList();
176                        ((SignalMastLogicTableDataModel)m).setSuppressUpdate(false);
177                        m.fireTableDataChanged();
178                        if (genSect.isSelected()) {
179                            ((DefaultSignalMastLogicManager) InstanceManager.getDefault(SignalMastLogicManager.class)).generateSection();
180                            InstanceManager.getDefault(SectionManager.class).generateBlockSections();
181                        }
182                    });
183                } catch (java.lang.reflect.InvocationTargetException ex) {
184                    log.error("failed to update at end of automaticallyDiscoverSignallingPairs", ex);
185                } catch (InterruptedException ex) {
186                    log.error("interrupted during update at end of automaticallyDiscoverSignallingPairs", ex);
187                }
188            };
189            Thread thr = ThreadingUtil.newThread(r, "Discover Signal Mast Logic");  // NOI18N
190            thr.start();
191
192        } else {
193            signalMastLogicFrame.setVisible(false);
194        }
195    }
196
197    private final PropertyChangeListener propertyGenerateListener = new PropertyChangeListener() {
198        @Override
199        public void propertyChange(PropertyChangeEvent evt) {
200            if (SignalMastLogicManager.PROPERTY_AUTO_GENERATE_COMPLETE.equals(evt.getPropertyName())) {
201                if (signalMastLogicFrame != null) {
202                    signalMastLogicFrame.setVisible(false);
203                }
204                InstanceManager.getDefault(SignalMastLogicManager.class).removePropertyChangeListener(this);
205                JmriJOptionPane.showMessageDialog(null, Bundle.getMessage("SignalMastPairGenerationComplete"));
206            } else if (SignalMastLogicManager.PROPERTY_AUTO_GENERATE_UPDATE.equals(evt.getPropertyName())) {
207                sourceLabel.setText((String) evt.getNewValue());
208                signalMastLogicFrame.pack();
209                signalMastLogicFrame.repaint();
210            }
211        }
212    };
213
214    private final jmri.jmrit.signalling.SignallingAction sigLog = new jmri.jmrit.signalling.SignallingAction();
215
216    @Override
217    protected String getClassName() {
218        return SignalMastLogicTableAction.class.getName();
219    }
220
221    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(SignalMastLogicTableAction.class);
222}