001package jmri.jmrit.beantable;
002
003import java.awt.BorderLayout;
004import java.awt.Color;
005import java.awt.FlowLayout;
006import java.awt.event.ActionEvent;
007import java.awt.event.ActionListener;
008import java.util.ArrayList;
009import java.util.HashSet;
010import java.util.List;
011import java.util.ResourceBundle;
012import java.util.Set;
013import javax.swing.BoxLayout;
014import javax.swing.ButtonGroup;
015import javax.swing.DefaultCellEditor;
016import javax.swing.JButton;
017import javax.swing.JCheckBox;
018import javax.swing.JComboBox;
019import javax.swing.JDialog;
020import javax.swing.JLabel;
021import javax.swing.JMenu;
022import javax.swing.JMenuBar;
023import javax.swing.JMenuItem;
024import javax.swing.JOptionPane;
025import javax.swing.JPanel;
026import javax.swing.JRadioButton;
027import javax.swing.JScrollPane;
028import javax.swing.JSeparator;
029import javax.swing.JTable;
030import javax.swing.JTextField;
031import javax.swing.table.TableColumn;
032import javax.swing.table.TableColumnModel;
033import jmri.Block;
034import jmri.BlockManager;
035import jmri.EntryPoint;
036import jmri.InstanceManager;
037import jmri.Manager;
038import jmri.Path;
039import jmri.Section;
040import jmri.SectionManager;
041import jmri.Sensor;
042import jmri.Transit;
043import jmri.NamedBean.DisplayOptions;
044import jmri.jmrit.display.EditorManager;
045import jmri.jmrit.display.layoutEditor.LayoutEditor;
046import jmri.util.JmriJFrame;
047import jmri.swing.NamedBeanComboBox;
048import jmri.util.swing.JComboBoxUtil;
049import org.slf4j.Logger;
050import org.slf4j.LoggerFactory;
051
052/**
053 * Swing action to create and register a SectionTable GUI.
054 * <p>
055 * This file is part of JMRI.
056 * <p>
057 * JMRI is open source software; you can redistribute it and/or modify it under
058 * the terms of version 2 of the GNU General Public License as published by the
059 * Free Software Foundation. See the "COPYING" file for a copy of this license.
060 * <p>
061 * JMRI is distributed in the hope that it will be useful, but WITHOUT ANY
062 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
063 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
064 *
065 * @author Dave Duchamp Copyright (C) 2008, 2011
066 * @author GT 2009
067 */
068public class SectionTableAction extends AbstractTableAction<Section> {
069
070    /**
071     * Create an action with a specific title.
072     * <p>
073     * Note that the argument is the Action title, not the title of the
074     * resulting frame. Perhaps this should be changed?
075     *
076     * @param actionName title of the action
077     */
078    public SectionTableAction(String actionName) {
079        super(actionName);
080        // set manager - no need to use InstanceManager here
081        sectionManager = jmri.InstanceManager.getNullableDefault(jmri.SectionManager.class);
082        // disable ourself if there is no Section manager available
083        if (sectionManager == null) {
084            setEnabled(false);
085        }
086    }
087
088    public SectionTableAction() {
089        this(Bundle.getMessage("TitleSectionTable"));
090    }
091
092    static final ResourceBundle rbx = ResourceBundle.getBundle("jmri.jmrit.beantable.SectionTransitTableBundle");
093
094    /**
095     * Create the JTable DataModel, along with the changes for the specific case
096     * of Section objects.
097     */
098    @Override
099    protected void createModel() {
100        m = new BeanTableDataModel<Section>() {
101
102            static public final int BEGINBLOCKCOL = NUMCOLUMN;
103            static public final int ENDBLOCKCOL = BEGINBLOCKCOL + 1;
104            static public final int EDITCOL = ENDBLOCKCOL + 1;
105
106            @Override
107            public String getValue(String name) {
108                return "";
109            }
110
111            @Override
112            public Manager<Section> getManager() {
113                return jmri.InstanceManager.getDefault(jmri.SectionManager.class);
114            }
115
116            @Override
117            public Section getBySystemName(String name) {
118                return jmri.InstanceManager.getDefault(jmri.SectionManager.class).getBySystemName(name);
119            }
120
121            @Override
122            public Section getByUserName(String name) {
123                return jmri.InstanceManager.getDefault(jmri.SectionManager.class).getByUserName(name);
124            }
125
126            @Override
127            protected String getMasterClassName() {
128                return getClassName();
129            }
130
131            @Override
132            public void clickOn(Section t) {
133            }
134
135            @Override
136            public int getColumnCount() {
137                return EDITCOL + 1;
138            }
139
140            @Override
141            public Object getValueAt(int row, int col) {
142                // some error checking
143                if (row >= sysNameList.size()) {
144                    log.debug("row is greater than name list");
145                    return "";
146                }
147                if (col == BEGINBLOCKCOL) {
148                    Section z = getBySystemName(sysNameList.get(row));
149                    if (z != null) {
150                        return z.getBeginBlockName();
151                    }
152                    return "  ";
153                } else if (col == ENDBLOCKCOL) {
154                    Section z = getBySystemName(sysNameList.get(row));
155                    if (z != null) {
156                        return z.getEndBlockName();
157                    }
158                    return "  ";
159                } else if (col == VALUECOL) {
160                    Section z = getBySystemName(sysNameList.get(row));
161                    if (z == null) {
162                        return "";
163                    } else {
164                        int state = z.getState();
165                        if (state == Section.FREE) {
166                            return (rbx.getString("SectionFree"));
167                        } else if (state == Section.FORWARD) {
168                            return (rbx.getString("SectionForward"));
169                        } else if (state == Section.REVERSE) {
170                            return (rbx.getString("SectionReverse"));
171                        }
172                    }
173                } else if (col == EDITCOL) {
174                    return Bundle.getMessage("ButtonEdit");
175                } else {
176                    return super.getValueAt(row, col);
177                }
178                return null;
179            }
180
181            @Override
182            public void setValueAt(Object value, int row, int col) {
183                if ((col == BEGINBLOCKCOL) || (col == ENDBLOCKCOL)) {
184                    return;
185                } else if (col == EDITCOL) {
186                    class WindowMaker implements Runnable {
187
188                        int row;
189
190                        WindowMaker(int r) {
191                            row = r;
192                        }
193
194                        @Override
195                        public void run() {
196                            String sName = ((Section) getValueAt(row, SYSNAMECOL)).getSystemName();
197                            editPressed(sName);
198                        }
199                    }
200                    WindowMaker t = new WindowMaker(row);
201                    javax.swing.SwingUtilities.invokeLater(t);
202                } else if (col == DELETECOL) {
203                    deleteSectionPressed(sysNameList.get(row));
204                } else {
205                    super.setValueAt(value, row, col);
206                }
207            }
208
209            @Override
210            public String getColumnName(int col) {
211                if (col == BEGINBLOCKCOL) {
212                    return (rbx.getString("SectionFirstBlock"));
213                }
214                if (col == ENDBLOCKCOL) {
215                    return (rbx.getString("SectionLastBlock"));
216                }
217                if (col == EDITCOL) {
218                    return "";   // no namne on Edit column
219                }
220                return super.getColumnName(col);
221            }
222
223            @Override
224            public Class<?> getColumnClass(int col) {
225                if (col == VALUECOL) {
226                    return String.class;  // not a button
227                }
228                if (col == BEGINBLOCKCOL) {
229                    return String.class;  // not a button
230                }
231                if (col == ENDBLOCKCOL) {
232                    return String.class;  // not a button
233                }
234                if (col == EDITCOL) {
235                    return JButton.class;
236                } else {
237                    return super.getColumnClass(col);
238                }
239            }
240
241            @Override
242            public boolean isCellEditable(int row, int col) {
243                if (col == BEGINBLOCKCOL) {
244                    return false;
245                }
246                if (col == ENDBLOCKCOL) {
247                    return false;
248                }
249                if (col == VALUECOL) {
250                    return false;
251                }
252                if (col == EDITCOL) {
253                    return true;
254                } else {
255                    return super.isCellEditable(row, col);
256                }
257            }
258
259            @Override
260            public int getPreferredWidth(int col) {
261                // override default value for SystemName and UserName columns
262                if (col == SYSNAMECOL) {
263                    return new JTextField(9).getPreferredSize().width;
264                }
265                if (col == USERNAMECOL) {
266                    return new JTextField(17).getPreferredSize().width;
267                }
268                if (col == VALUECOL) {
269                    return new JTextField(6).getPreferredSize().width;
270                }
271                // new columns
272                if (col == BEGINBLOCKCOL) {
273                    return new JTextField(15).getPreferredSize().width;
274                }
275                if (col == ENDBLOCKCOL) {
276                    return new JTextField(15).getPreferredSize().width;
277                }
278                if (col == EDITCOL) {
279                    return new JTextField(6).getPreferredSize().width;
280                } else {
281                    return super.getPreferredWidth(col);
282                }
283            }
284
285            @Override
286            public void configValueColumn(JTable table) {
287                // value column isn't button, so config is null
288            }
289
290            @Override
291            protected boolean matchPropertyName(java.beans.PropertyChangeEvent e) {
292                return true;
293                // return (e.getPropertyName().indexOf("alue")>=0);
294            }
295
296            @Override
297            protected String getBeanType() {
298                return "Section";
299            }
300        };
301    }
302
303    @Override
304    protected void setTitle() {
305        f.setTitle(Bundle.getMessage("TitleSectionTable"));
306    }
307
308    @Override
309    protected String helpTarget() {
310        return "package.jmri.jmrit.beantable.SectionTable";
311    }
312
313    // instance variables
314    ArrayList<Block> blockList = new ArrayList<>();
315    BlockTableModel blockTableModel = null;
316    EntryPointTableModel entryPointTableModel = null;
317    SectionManager sectionManager = null;
318    BlockManager blockManager = jmri.InstanceManager.getDefault(jmri.BlockManager.class);
319    boolean editMode = false;
320    Section curSection = null;
321    boolean addCreateActive = true;
322    ArrayList<LayoutEditor> lePanelList = null;
323    LayoutEditor curLayoutEditor = null;
324    Block beginBlock = null;
325    Block endBlock = null;
326    Sensor fSensor = null;
327    Sensor rSensor = null;
328    Sensor fStopSensor = null;
329    Sensor rStopSensor = null;
330    ArrayList<EntryPoint> entryPointList = new ArrayList<EntryPoint>();
331    boolean manualEntryPoints = true;
332
333    // add/create variables
334    JmriJFrame addFrame = null;
335    JTextField sysName = new JTextField(15);
336    JLabel sysNameFixed = new JLabel("");
337    JTextField userName = new JTextField(17);
338    JLabel sysNameLabel = new JLabel(Bundle.getMessage("LabelSystemName"));
339    JLabel userNameLabel = new JLabel(Bundle.getMessage("LabelUserName"));
340    JCheckBox _autoSystemName = new JCheckBox(Bundle.getMessage("LabelAutoSysName"));
341    jmri.UserPreferencesManager pref;
342    JButton create = null;
343    JButton update = null;
344    JButton addBlock = null;
345    JButton deleteBlocks = null;
346    JComboBox<String> layoutEditorBox = new JComboBox<String>();
347    NamedBeanComboBox<Block> blockBox;
348    NamedBeanComboBox<Sensor> forwardSensorBox;
349    NamedBeanComboBox<Sensor> reverseSensorBox;
350    NamedBeanComboBox<Sensor> forwardStopSensorBox;
351    NamedBeanComboBox<Sensor> reverseStopSensorBox;
352    JRadioButton manually = new JRadioButton(rbx.getString("SetManually"), true);
353    JRadioButton automatic = new JRadioButton(rbx.getString("UseConnectivity"), false);
354    ButtonGroup entryPointOptions = null;
355    String systemNameAuto = this.getClass().getName() + ".AutoSystemName";
356    JLabel generationStateLabel = new JLabel();
357
358    /**
359     * Responds to the Add... button and the Edit buttons in the Section Table
360     */
361    @Override
362    protected void addPressed(ActionEvent e) {
363        editMode = false;
364        if ((blockManager.getNamedBeanSet().size()) > 0) {
365            addEditPressed();
366        } else {
367            JOptionPane.showMessageDialog(null, rbx
368                    .getString("Message1"), Bundle.getMessage("ErrorTitle"),
369                    JOptionPane.ERROR_MESSAGE);
370        }
371    }
372
373    void editPressed(String sName) {
374        curSection = sectionManager.getBySystemName(sName);
375        if (curSection == null) {
376            // no section - should never happen, but protects against a $%^#@ exception
377            return;
378        }
379        sysNameFixed.setText(sName);
380        editMode = true;
381        addEditPressed();
382    }
383
384    void addEditPressed() {
385        pref = jmri.InstanceManager.getDefault(jmri.UserPreferencesManager.class);
386        if (addFrame == null) {
387            addFrame = new JmriJFrame(Bundle.getMessage("TitleAddSection"));
388            addFrame.addHelpMenu("package.jmri.jmrit.beantable.SectionAddEdit", true);
389            addFrame.getContentPane().setLayout(new BoxLayout(addFrame.getContentPane(), BoxLayout.Y_AXIS));
390            // add system name
391            JPanel p = new JPanel();
392            p.setLayout(new FlowLayout());
393            p.add(sysNameLabel);
394            sysNameLabel.setLabelFor(sysName);
395            p.add(sysNameFixed);
396            p.add(sysName);
397            p.add(_autoSystemName);
398            _autoSystemName.addActionListener(new ActionListener() {
399                @Override
400                public void actionPerformed(ActionEvent e) {
401                    autoSystemName();
402                }
403            });
404            if (pref.getSimplePreferenceState(systemNameAuto)) {
405                _autoSystemName.setSelected(true);
406            }
407            sysName.setToolTipText(rbx.getString("SectionSystemNameHint"));
408            addFrame.getContentPane().add(p);
409            // add user name
410            JPanel pu = new JPanel();
411            pu.setLayout(new FlowLayout());
412            pu.add(userNameLabel);
413            userNameLabel.setLabelFor(userName);
414            pu.add(userName);
415            userName.setToolTipText(rbx.getString("SectionUserNameHint"));
416            addFrame.getContentPane().add(pu);
417
418            JPanel pa = new JPanel();
419            pa.setLayout(new FlowLayout());
420            pa.add(generationStateLabel);
421            addFrame.getContentPane().add(pa);
422            addFrame.getContentPane().add(new JSeparator());
423            JPanel p1 = new JPanel();
424            p1.setLayout(new BoxLayout(p1, BoxLayout.Y_AXIS));
425            JPanel p11 = new JPanel();
426            p11.setLayout(new FlowLayout());
427            p11.add(new JLabel(rbx.getString("BlockTableMessage")));
428            p1.add(p11);
429            JPanel p12 = new JPanel();
430            // initialize table of Blocks
431            blockTableModel = new BlockTableModel();
432            JTable blockTable = new JTable(blockTableModel);
433            blockTable.setRowSelectionAllowed(false);
434            blockTable.setPreferredScrollableViewportSize(new java.awt.Dimension(350, 100));
435            TableColumnModel blockColumnModel = blockTable.getColumnModel();
436            TableColumn sNameColumn = blockColumnModel.getColumn(BlockTableModel.SNAME_COLUMN);
437            sNameColumn.setResizable(true);
438            sNameColumn.setMinWidth(90);
439            sNameColumn.setMaxWidth(130);
440            TableColumn uNameColumn = blockColumnModel.getColumn(BlockTableModel.UNAME_COLUMN);
441            uNameColumn.setResizable(true);
442            uNameColumn.setMinWidth(210);
443            uNameColumn.setMaxWidth(260);
444            JScrollPane blockTableScrollPane = new JScrollPane(blockTable);
445            p12.add(blockTableScrollPane, BorderLayout.CENTER);
446            p1.add(p12);
447            JPanel p13 = new JPanel();
448            p13.setLayout(new FlowLayout());
449            p13.add(deleteBlocks = new JButton(rbx.getString("DeleteAllBlocksButton")));
450            deleteBlocks.addActionListener(new ActionListener() {
451                @Override
452                public void actionPerformed(ActionEvent e) {
453                    deleteBlocksPressed(e);
454                }
455            });
456            deleteBlocks.setToolTipText(rbx.getString("DeleteAllBlocksButtonHint"));
457            p13.add(new JLabel("     "));
458            initializeBlockCombo();
459            p13.add(blockBox);
460            blockBox.setToolTipText(rbx.getString("BlockBoxHint"));
461            p13.add(addBlock = new JButton(rbx.getString("AddBlockButton")));
462            addBlock.addActionListener(new ActionListener() {
463                @Override
464                public void actionPerformed(ActionEvent e) {
465                    addBlockPressed(e);
466                }
467            });
468            addBlock.setToolTipText(rbx.getString("AddBlockButtonHint"));
469            p1.add(p13);
470            addFrame.getContentPane().add(p1);
471            // add hint for order of blocks irt direction of travel
472            JPanel p34 = new JPanel();
473            p34.setLayout(new FlowLayout());
474            JLabel direction = new JLabel(rbx.getString("DirectionNote")); // placed below first table
475            direction.setFont(direction.getFont().deriveFont(0.9f * blockBox.getFont().getSize())); // a bit smaller
476            direction.setForeground(Color.gray);
477            p34.add(direction);
478            addFrame.getContentPane().add(p34);
479            addFrame.getContentPane().add(new JSeparator());
480            JPanel p31 = new JPanel();
481            p31.setLayout(new FlowLayout());
482            p31.add(new JLabel(rbx.getString("EntryPointTable")));
483            addFrame.getContentPane().add(p31);
484            JPanel p32 = new JPanel();
485            p32.setLayout(new FlowLayout());
486            entryPointOptions = new ButtonGroup();
487            p32.add(manually);
488            entryPointOptions.add(manually);
489            manually.addActionListener(new ActionListener() {
490                @Override
491                public void actionPerformed(ActionEvent e) {
492                    manualEntryPoints = true;
493                }
494            });
495            manually.setToolTipText(rbx.getString("SetManuallyHint"));
496            p32.add(new JLabel("   "));
497            p32.add(automatic);
498            entryPointOptions.add(automatic);
499            automatic.addActionListener(new ActionListener() {
500                @Override
501                public void actionPerformed(ActionEvent e) {
502                    manualEntryPoints = false;
503                }
504            });
505            automatic.setToolTipText(rbx.getString("SetAutomaticHint"));
506            p32.add(layoutEditorBox);
507            layoutEditorBox.setToolTipText(rbx.getString("LayoutEditorBoxHint"));
508            layoutEditorBox.addActionListener(new ActionListener() {
509                @Override
510                public void actionPerformed(ActionEvent e) {
511                    layoutEditorSelectionChanged();
512                }
513            });
514            // djd debugging - temporarily hide these items until the automatic setting of entry point direction is ready
515            //   addFrame.getContentPane().add(p32);
516            // end djd debugging
517            JPanel p33 = new JPanel();
518            // initialize table of entry points
519            entryPointTableModel = new EntryPointTableModel();
520            JTable entryPointTable = new JTable(entryPointTableModel);
521            entryPointTable.setRowSelectionAllowed(false);
522            entryPointTable.setPreferredScrollableViewportSize(new java.awt.Dimension(550, 100));
523            TableColumnModel entryPointColumnModel = entryPointTable.getColumnModel();
524            // From-Block
525            TableColumn fromBlockColumn = entryPointColumnModel.getColumn(EntryPointTableModel.BLOCK_COLUMN);
526            fromBlockColumn.setResizable(true);
527            fromBlockColumn.setMinWidth(250);
528            fromBlockColumn.setMaxWidth(310);
529            // To-Block
530            TableColumn toBlockColumn = entryPointColumnModel.getColumn(EntryPointTableModel.TO_BLOCK_COLUMN);
531            toBlockColumn.setResizable(true);
532            toBlockColumn.setMinWidth(150);
533            toBlockColumn.setMaxWidth(210);
534
535            JComboBox<String> directionCombo = new JComboBox<String>();
536            directionCombo.addItem(rbx.getString("SectionForward"));
537            directionCombo.addItem(rbx.getString("SectionReverse"));
538            directionCombo.addItem(Bundle.getMessage("BeanStateUnknown"));
539            TableColumn directionColumn = entryPointColumnModel.getColumn(EntryPointTableModel.DIRECTION_COLUMN);
540            directionColumn.setCellEditor(new DefaultCellEditor(directionCombo));
541            entryPointTable.setRowHeight(directionCombo.getPreferredSize().height);
542            directionColumn.setPreferredWidth(directionCombo.getPreferredSize().width);
543            directionColumn.setResizable(false);
544            JScrollPane entryPointTableScrollPane = new JScrollPane(entryPointTable);
545            p33.add(entryPointTableScrollPane, BorderLayout.CENTER);
546            addFrame.getContentPane().add(p33);
547            p33.setVisible(true);
548            // hint p34 is displayed 1 table up
549            addFrame.getContentPane().add(new JSeparator());
550            // set up pane for direction sensors
551            forwardSensorBox = new NamedBeanComboBox<>(InstanceManager.sensorManagerInstance());
552            forwardSensorBox.setAllowNull(true);
553            forwardSensorBox.setSelectedItem(null);
554            reverseSensorBox = new NamedBeanComboBox<>(InstanceManager.sensorManagerInstance());
555            reverseSensorBox.setAllowNull(true);
556            reverseSensorBox.setSelectedItem(null);
557            JComboBoxUtil.setupComboBoxMaxRows(forwardSensorBox);
558            JComboBoxUtil.setupComboBoxMaxRows(reverseSensorBox);
559            JPanel p20 = new JPanel();
560            p20.setLayout(new FlowLayout());
561            p20.add(new JLabel(rbx.getString("DirectionSensorLabel")));
562            addFrame.getContentPane().add(p20);
563            JPanel p21 = new JPanel();
564            p21.setLayout(new FlowLayout());
565            p21.add(new JLabel(rbx.getString("ForwardSensor")));
566            p21.add(forwardSensorBox);
567            forwardSensorBox.setToolTipText(rbx.getString("ForwardSensorHint"));
568            p21.add(new JLabel("     "));
569            p21.add(new JLabel(rbx.getString("ReverseSensor")));
570            p21.add(reverseSensorBox);
571            reverseSensorBox.setToolTipText(rbx.getString("ReverseSensorHint"));
572            addFrame.getContentPane().add(p21);
573            addFrame.getContentPane().add(new JSeparator());
574            // set up for stopping sensors
575            forwardStopSensorBox = new NamedBeanComboBox<>(InstanceManager.sensorManagerInstance());
576            forwardStopSensorBox.setAllowNull(true);
577            forwardStopSensorBox.setSelectedItem(null);
578            reverseStopSensorBox = new NamedBeanComboBox<>(InstanceManager.sensorManagerInstance());
579            reverseStopSensorBox.setAllowNull(true);
580            reverseStopSensorBox.setSelectedItem(null);
581            JComboBoxUtil.setupComboBoxMaxRows(forwardStopSensorBox);
582            JComboBoxUtil.setupComboBoxMaxRows(reverseStopSensorBox);
583            JPanel p40 = new JPanel();
584            p40.setLayout(new FlowLayout());
585            p40.add(new JLabel(rbx.getString("StoppingSensorLabel")));
586            addFrame.getContentPane().add(p40);
587            JPanel p41 = new JPanel();
588            p41.setLayout(new FlowLayout());
589            p41.add(new JLabel(rbx.getString("ForwardStopSensor")));
590            p41.add(forwardStopSensorBox);
591            forwardStopSensorBox.setToolTipText(rbx.getString("ForwardStopSensorHint"));
592            p41.add(new JLabel("     "));
593            p41.add(new JLabel(rbx.getString("ReverseStopSensor")));
594            p41.add(reverseStopSensorBox);
595            reverseStopSensorBox.setToolTipText(rbx.getString("ReverseStopSensorHint"));
596            addFrame.getContentPane().add(p41);
597            addFrame.getContentPane().add(new JSeparator());
598            // set up bottom row of buttons
599            JButton cancel = null;
600            JPanel pb = new JPanel();
601            pb.setLayout(new FlowLayout());
602            pb.add(cancel = new JButton(Bundle.getMessage("ButtonCancel")));
603            cancel.addActionListener(new ActionListener() {
604                @Override
605                public void actionPerformed(ActionEvent e) {
606                    cancelPressed(e);
607                }
608            });
609            cancel.setToolTipText(rbx.getString("CancelButtonHint"));
610            pb.add(create = new JButton(Bundle.getMessage("ButtonCreate")));
611            create.addActionListener(new ActionListener() {
612                @Override
613                public void actionPerformed(ActionEvent e) {
614                    createPressed(e);
615                }
616            });
617            create.setToolTipText(rbx.getString("SectionCreateButtonHint"));
618            pb.add(update = new JButton(Bundle.getMessage("ButtonUpdate")));
619            update.addActionListener(new ActionListener() {
620                @Override
621                public void actionPerformed(ActionEvent e) {
622                    updatePressed(e);
623                }
624            });
625            update.setToolTipText(rbx.getString("SectionUpdateButtonHint"));
626            addFrame.getContentPane().add(pb);
627        }
628        if (editMode) {
629            // setup for edit window
630            _autoSystemName.setVisible(false);
631            sysNameLabel.setEnabled(true);
632            create.setVisible(false);
633            update.setVisible(true);
634            sysName.setVisible(true);
635            sysName.setVisible(false);
636            sysNameFixed.setVisible(true);
637            initializeEditInformation();
638            addFrame.setTitle(Bundle.getMessage("TitleEditSection"));
639        } else {
640            // setup for create window
641            _autoSystemName.setVisible(true);
642            create.setVisible(true);
643            update.setVisible(false);
644            sysName.setVisible(true);
645            sysNameFixed.setVisible(false);
646            autoSystemName();
647            clearForCreate();
648            addFrame.setTitle(Bundle.getMessage("TitleAddSection"));
649        }
650        // initialize layout editor panels
651        if (initializeLayoutEditorCombo(layoutEditorBox)) {
652            manually.setVisible(true);
653            automatic.setVisible(true);
654            layoutEditorBox.setVisible(true);
655        } else {
656            manually.setVisible(false);
657            automatic.setVisible(false);
658            layoutEditorBox.setVisible(false);
659        }
660        // initialize block combo - first time
661        initializeBlockCombo();
662        addFrame.pack();
663        addFrame.setVisible(true);
664    }
665
666    private void initializeEditInformation() {
667        userName.setText(curSection.getUserName());
668        switch (curSection.getSectionType()) {
669            case Section.SIGNALMASTLOGIC:
670                generationStateLabel.setText(rbx.getString("SectionTypeSMLLabel"));
671                break;
672            case Section.DYNAMICADHOC:
673                generationStateLabel.setText(rbx.getString("SectionTypeDynLabel"));
674                break;
675            case Section.USERDEFINED:
676            default:
677                generationStateLabel.setText("");
678                break;
679        }
680
681        deleteBlocksPressed(null);
682        int i = 0;
683        while (curSection.getBlockBySequenceNumber(i) != null) {
684            Block b = curSection.getBlockBySequenceNumber(i);
685            blockList.add(b);
686            i++;
687            if (blockList.size() == 1) {
688                beginBlock = b;
689            }
690            endBlock = b;
691        }
692        forwardSensorBox.setSelectedItem(curSection.getForwardBlockingSensor());
693        reverseSensorBox.setSelectedItem(curSection.getReverseBlockingSensor());
694        forwardStopSensorBox.setSelectedItem(curSection.getForwardStoppingSensor());
695        reverseStopSensorBox.setSelectedItem(curSection.getReverseStoppingSensor());
696        List<EntryPoint> list = curSection.getForwardEntryPointList();
697        if (list.size() > 0) {
698            for (int j = 0; j < list.size(); j++) {
699                entryPointList.add(list.get(j));
700            }
701        }
702        list = curSection.getReverseEntryPointList();
703        if (list.size() > 0) {
704            for (int j = 0; j < list.size(); j++) {
705                entryPointList.add(list.get(j));
706            }
707        }
708    }
709
710    private void clearForCreate() {
711        deleteBlocksPressed(null);
712        curSection = null;
713        forwardSensorBox.setSelectedItem(null);
714        reverseSensorBox.setSelectedItem(null);
715        forwardStopSensorBox.setSelectedItem(null);
716        reverseStopSensorBox.setSelectedItem(null);
717        generationStateLabel.setText("");
718    }
719
720    void createPressed(ActionEvent e) {
721        if (!checkSectionInformation()) {
722            return;
723        }
724        String uName = userName.getText();
725        if (uName.equals("")) {
726            uName = null;
727        }
728
729        // attempt to create the new Section
730        String sName = sysName.getText();
731        try {
732            if (_autoSystemName.isSelected()) {
733                curSection = sectionManager.createNewSection(uName);
734            } else {
735                curSection = sectionManager.createNewSection(sName, uName);
736            }
737        } catch (NumberFormatException ex) {
738            // user input no good
739            if (_autoSystemName.isSelected()) {
740                handleCreateException(uName);
741            } else {
742                handleCreateException(sName);
743            }
744            return; // without creating any
745        }
746        if (curSection == null) {
747            JOptionPane.showMessageDialog(addFrame, rbx
748                    .getString("Message2"), Bundle.getMessage("ErrorTitle"),
749                    JOptionPane.ERROR_MESSAGE);
750            return;
751        }
752        sysName.setText(curSection.getSystemName());
753        setSectionInformation();
754        addFrame.setVisible(false);
755        addFrame.dispose();
756        addFrame = null;
757        pref.setSimplePreferenceState(systemNameAuto, _autoSystemName.isSelected());
758    }
759
760    void handleCreateException(String sysName) {
761        JOptionPane.showMessageDialog(addFrame,
762                Bundle.getMessage("ErrorSectionAddFailed", sysName) + "\n" + Bundle.getMessage("ErrorAddFailedCheck"),
763                Bundle.getMessage("ErrorTitle"),
764                JOptionPane.ERROR_MESSAGE);
765    }
766
767    void cancelPressed(ActionEvent e) {
768        addFrame.setVisible(false);
769        addFrame.dispose();
770        addFrame = null;
771    }
772
773    void updatePressed(ActionEvent e) {
774        if (!checkSectionInformation()) {
775            return;
776        }
777        // check if user name has been changed
778        String uName = userName.getText();
779        if (uName.equals("")) {
780            uName = null;
781        }
782        if ((uName != null) && (!uName.equals(curSection.getUserName()))) {
783            // check that new user name is unique
784            Section tSection = sectionManager.getByUserName(uName);
785            if (tSection != null) {
786                JOptionPane.showMessageDialog(addFrame,
787                        rbx.getString("Message2"),
788                        Bundle.getMessage("ErrorTitle"),
789                        JOptionPane.ERROR_MESSAGE);
790                return;
791            }
792        }
793        curSection.setUserName(uName);
794        if (setSectionInformation()) {
795            // successful update
796            addFrame.setVisible(false);
797            addFrame.dispose();
798            addFrame = null;
799        }
800    }
801
802    private boolean checkSectionInformation() {
803        if (blockList.size() == 0) {
804            JOptionPane.showMessageDialog(addFrame, rbx
805                    .getString("Message6"), Bundle.getMessage("ErrorTitle"),
806                    JOptionPane.ERROR_MESSAGE);
807            return false;
808        }
809        // check entry points
810        boolean unknownPresent = false;
811        for (int i = 0; i < entryPointList.size(); i++) {
812            if (entryPointList.get(i).isUnknownType()) {
813                unknownPresent = true;
814            }
815        }
816        if (unknownPresent) {
817            JOptionPane.showMessageDialog(addFrame, rbx
818                    .getString("Message10"), Bundle.getMessage("ErrorTitle"),
819                    JOptionPane.ERROR_MESSAGE);
820            return false;
821        }
822
823        // check direction sensors
824        fSensor = forwardSensorBox.getSelectedItem();
825        rSensor = reverseSensorBox.getSelectedItem();
826        if ((fSensor != null) && (fSensor.equals(rSensor))) {
827            JOptionPane.showMessageDialog(addFrame, rbx
828                    .getString("Message9"), Bundle.getMessage("ErrorTitle"),
829                    JOptionPane.ERROR_MESSAGE);
830            return false;
831        }
832
833        // check stopping sensors
834        fStopSensor = forwardStopSensorBox.getSelectedItem();
835        rStopSensor = reverseStopSensorBox.getSelectedItem();
836
837        return true;
838    }
839
840    /**
841     * Copy the user input to the Section.
842     *
843     * @return true if completed
844     */
845    private boolean setSectionInformation() {
846        curSection.removeAllBlocksFromSection();
847        for (int i = 0; i < blockList.size(); i++) {
848            if (!curSection.addBlock(blockList.get(i))) {
849                JOptionPane.showMessageDialog(addFrame, rbx
850                        .getString("Message4"), Bundle.getMessage("ErrorTitle"),
851                        JOptionPane.ERROR_MESSAGE);
852            }
853        }
854        curSection.setForwardBlockingSensorName(forwardSensorBox.getSelectedItemDisplayName());
855        curSection.setReverseBlockingSensorName(reverseSensorBox.getSelectedItemDisplayName());
856        curSection.setForwardStoppingSensorName(forwardStopSensorBox.getSelectedItemDisplayName());
857        curSection.setReverseStoppingSensorName(reverseStopSensorBox.getSelectedItemDisplayName());
858        for (int j = 0; j < entryPointList.size(); j++) {
859            EntryPoint ep = entryPointList.get(j);
860            if (ep.isForwardType()) {
861                curSection.addToForwardList(ep);
862            } else if (ep.isReverseType()) {
863                curSection.addToReverseList(ep);
864            }
865        }
866        return true;
867    }
868
869    void deleteBlocksPressed(ActionEvent e) {
870        for (int j = blockList.size(); j > 0; j--) {
871            blockList.remove(j - 1);
872        }
873        beginBlock = null;
874        endBlock = null;
875        initializeBlockCombo();
876        initializeEntryPoints();
877        blockTableModel.fireTableDataChanged();
878    }
879
880    void addBlockPressed(ActionEvent e) {
881        if (blockBox.getItemCount() == 0) {
882            JOptionPane.showMessageDialog(addFrame, rbx
883                    .getString("Message5"), Bundle.getMessage("ErrorTitle"),
884                    JOptionPane.ERROR_MESSAGE);
885            return;
886        }
887        Block b = blockBox.getSelectedItem();
888        if (b != null) {
889            blockList.add(b);
890            if (blockList.size() == 1) {
891                beginBlock = b;
892            }
893            endBlock = b;
894            initializeBlockCombo();
895            initializeEntryPoints();
896            blockTableModel.fireTableDataChanged();
897        }
898    }
899
900    private boolean initializeLayoutEditorCombo(JComboBox<String> box) {
901        // get list of Layout Editor panels
902        lePanelList = new ArrayList<>(InstanceManager.getDefault(EditorManager.class).getAll(LayoutEditor.class));
903        if (lePanelList.isEmpty()) {
904            return false;
905        }
906        box.removeAllItems();
907        box.addItem("<" + Bundle.getMessage("None").toLowerCase() + ">");
908        for (int i = 0; i < lePanelList.size(); i++) {
909            box.addItem(lePanelList.get(i).getTitle());
910        }
911        box.setSelectedIndex(1);
912        return true;
913    }
914
915    private void layoutEditorSelectionChanged() {
916        int i = layoutEditorBox.getSelectedIndex();
917        if ((i <= 0) || (i > lePanelList.size())) {
918            curLayoutEditor = null;
919        } else {
920            curLayoutEditor = lePanelList.get(i - 1);
921        }
922    }
923
924    /**
925     * Build a combo box to select Blocks for this Section.
926     */
927    private void initializeBlockCombo() {
928        if (blockBox == null) {
929            blockBox = new NamedBeanComboBox<>(InstanceManager.getDefault(BlockManager.class));
930        }
931        if (blockList.size() == 0) {
932            // No blocks selected, all blocks are eligible
933            blockBox.setExcludedItems(new HashSet<Block>());
934        } else {
935            // limit combo list to Blocks bonded to the currently selected Block that are not already in the Section
936            Set<Block> excludes = new HashSet<>(InstanceManager.getDefault(jmri.BlockManager.class).getNamedBeanSet());
937            for (Block b : blockManager.getNamedBeanSet()) {
938                if ((!inSection(b)) && connected(b, endBlock)) {
939                    excludes.remove(b);
940                }
941            }
942            blockBox.setExcludedItems(excludes);
943        }
944        if (blockBox.getItemCount()> 0) {
945            blockBox.setSelectedIndex(0);
946            JComboBoxUtil.setupComboBoxMaxRows(blockBox);
947        }
948    }
949
950    private boolean inSection(Block b) {
951        for (int i = 0; i < blockList.size(); i++) {
952            if (blockList.get(i) == b) {
953                return true;
954            }
955        }
956        return false;
957    }
958
959    private boolean connected(Block b1, Block b2) {
960        if ((b1 != null) && (b2 != null)) {
961            List<Path> paths = b1.getPaths();
962            for (int i = 0; i < paths.size(); i++) {
963                if (paths.get(i).getBlock() == b2) {
964                    return true;
965                }
966            }
967        }
968        return false;
969    }
970
971    private void initializeEntryPoints() {
972        // Copy old Entry Point List, if there are entries, and clear it.
973        ArrayList<EntryPoint> oldList = new ArrayList<EntryPoint>();
974        for (int i = 0; i < entryPointList.size(); i++) {
975            oldList.add(entryPointList.get(i));
976        }
977        entryPointList.clear();
978        if (blockList.size() > 0) {
979            // cycle through Blocks to find Entry Points
980            for (int i = 0; i < blockList.size(); i++) {
981                Block sb = blockList.get(i);
982                List<Path> paths = sb.getPaths();
983                for (int j = 0; j < paths.size(); j++) {
984                    Path p = paths.get(j);
985                    if (!inSection(p.getBlock())) {
986                        // this is path to an outside block, so need an Entry Point
987                        String pbDir = Path.decodeDirection(p.getFromBlockDirection());
988                        EntryPoint ep = getEntryPointInList(oldList, sb, p.getBlock(), pbDir);
989                        if (ep == null) {
990                            ep = new EntryPoint(sb, p.getBlock(), pbDir);
991                        }
992                        entryPointList.add(ep);
993                    }
994                }
995            }
996            // Set directions where possible
997            ArrayList<EntryPoint> epList = getBlockEntryPointsList(beginBlock);
998            if ((epList.size() == 2) && (blockList.size() == 1)) {
999                if (((epList.get(0)).isUnknownType())
1000                        && ((epList.get(1)).isUnknownType())) {
1001                    (epList.get(0)).setTypeForward();
1002                    (epList.get(1)).setTypeReverse();
1003                }
1004            } else if (epList.size() == 1) {
1005                (epList.get(0)).setTypeForward();
1006            }
1007            epList = getBlockEntryPointsList(endBlock);
1008            if (epList.size() == 1) {
1009                (epList.get(0)).setTypeReverse();
1010            }
1011        }
1012// djd debugging
1013// here add code to use Layout Editor connectivity if desired in the future
1014/*  if (!manualEntryPoints) {
1015         // use Layout Editor connectivity to set directions of Entry Points that have UNKNOWN direction
1016         // check entry points for first Block
1017         ArrayList<EntryPoint> tEPList = getSubEPListForBlock(beginBlock);
1018         EntryPoint firstEP = null;
1019         int numUnknown = 0;
1020         for (int i = 0; i<tEPList.size(); i++) {
1021         if (tEPList.get(i).getDirection==EntryPoint.UNKNOWN) numUnknown ++;
1022         else if (firstEP==null) firstEP = tEPList.get(i);
1023         }
1024         if (numUnknown>0) {
1025         // first Block has unknown entry point(s)
1026         if ( (firstEP!=null) && (blockList.getSize()==1) ) {
1027         firstEP = tEPList.get(0);
1028         firstEP.setTypeForward();
1029         }
1030         else if (firstEP==null) {
1031         // find connection from the second Block
1032         }
1033         }   */
1034        entryPointTableModel.fireTableDataChanged();
1035    }
1036    /* private ArrayList<EntryPoint> getSubEPListForBlock(Block b) {
1037     ArrayList<EntryPoint> tList = new ArrayList<EntryPoint>0;
1038     for (int i=0; i<eplist.size(); i++) {
1039     EntryPoint tep = epList.get(i);
1040     if (epList.getBlock()==b) {
1041     tList.add(tep);
1042     }
1043     }
1044     return tList;
1045     } */
1046// end djd debugging
1047
1048    private EntryPoint getEntryPointInList(ArrayList<EntryPoint> list, Block b, Block pb, String pbDir) {
1049        for (int i = 0; i < list.size(); i++) {
1050            EntryPoint ep = list.get(i);
1051            if ((ep.getBlock() == b) && (ep.getFromBlock() == pb)
1052                    && (pbDir.equals(ep.getFromBlockDirection()))) {
1053                return ep;
1054            }
1055        }
1056        return null;
1057    }
1058
1059    private ArrayList<EntryPoint> getBlockEntryPointsList(Block b) {
1060        ArrayList<EntryPoint> list = new ArrayList<EntryPoint>();
1061        for (int i = 0; i < entryPointList.size(); i++) {
1062            EntryPoint ep = entryPointList.get(i);
1063            if (ep.getBlock() == b) {
1064                list.add(ep);
1065            }
1066        }
1067        return list;
1068    }
1069
1070    /**
1071     * Special processing when user requests deletion of a Section.
1072     * <p>
1073     * Standard BeanTable processing results in misleading information.
1074     */
1075    private void deleteSectionPressed(String sName) {
1076        final Section s = jmri.InstanceManager.getDefault(jmri.SectionManager.class).getBySystemName(sName);
1077        if (s == null){
1078            throw new IllegalArgumentException("Not deleting Section :" + sName + ": , Not Found.");
1079        }
1080        String fullName = s.getDisplayName(DisplayOptions.USERNAME_SYSTEMNAME);
1081        ArrayList<Transit> affectedTransits = jmri.InstanceManager.getDefault(jmri.TransitManager.class).getListUsingSection(s);
1082        final JDialog dialog = new JDialog();
1083        String msg;
1084        dialog.setTitle(Bundle.getMessage("WarningTitle"));
1085        dialog.setDefaultCloseOperation(javax.swing.JFrame.DISPOSE_ON_CLOSE);
1086        dialog.getContentPane().setLayout(new BoxLayout(dialog.getContentPane(), BoxLayout.Y_AXIS));
1087        JPanel p1 = new JPanel();
1088        p1.setLayout(new FlowLayout());
1089        if (affectedTransits.size() > 0) {
1090            // special warning if Section is used in Transits
1091            JLabel iLabel = new JLabel(java.text.MessageFormat.format(rbx.getString("Message17"), fullName));
1092            p1.add(iLabel);
1093            dialog.add(p1);
1094            for (int i = 0; i < affectedTransits.size(); i++) {
1095                Transit aTransit = affectedTransits.get(i);
1096                String tFullName = aTransit.getDisplayName(DisplayOptions.USERNAME_SYSTEMNAME);
1097                p1 = new JPanel();
1098                p1.setLayout(new FlowLayout());
1099                iLabel = new JLabel("   " + tFullName);
1100                p1.add(iLabel);
1101                dialog.add(p1);
1102            }
1103            dialog.add(p1);
1104            JPanel p3 = new JPanel();
1105            p3.setLayout(new FlowLayout());
1106            JLabel question = new JLabel(rbx.getString("Message18"));
1107            p3.add(question);
1108            dialog.add(p3);
1109            JPanel p4 = new JPanel();
1110            p4.setLayout(new FlowLayout());
1111            question = new JLabel(rbx.getString("Message18a"));
1112            p4.add(question);
1113            dialog.add(p4);
1114        } else {
1115            msg = java.text.MessageFormat.format(rbx.getString("Message19"), fullName);
1116            JLabel question = new JLabel(msg);
1117            p1.add(question);
1118            dialog.add(p1);
1119        }
1120        JPanel p6 = new JPanel();
1121        p6.setLayout(new FlowLayout());
1122        JLabel quest = new JLabel(rbx.getString("Message20"));
1123        p6.add(quest);
1124        dialog.add(p6);
1125        JButton yesButton = new JButton(rbx.getString("YesDeleteIt"));
1126        JButton noButton = new JButton(rbx.getString("NoCancel"));
1127        JPanel button = new JPanel();
1128        button.add(yesButton);
1129        button.add(noButton);
1130        dialog.add(button);
1131
1132        noButton.addActionListener(new ActionListener() {
1133            @Override
1134            public void actionPerformed(ActionEvent e) {
1135                // user cancelled delete request
1136                dialog.dispose();
1137            }
1138        });
1139
1140        yesButton.addActionListener(new ActionListener() {
1141            @Override
1142            public void actionPerformed(ActionEvent e) {
1143                jmri.InstanceManager.getDefault(jmri.SectionManager.class).deregister(s);
1144                s.dispose();
1145                dialog.dispose();
1146            }
1147        });
1148        dialog.pack();
1149        dialog.setModal(true);
1150        dialog.setVisible(true);
1151    }
1152
1153    /**
1154     * Insert 2 table specific menus.
1155     * Account for the Window and Help menus, which are already added to the menu bar
1156     * as part of the creation of the JFrame, by adding the menus 2 places earlier
1157     * unless the table is part of the ListedTableFrame, that adds the Help menu later on.
1158     *
1159     * @param f the JFrame of this table
1160     */
1161    @Override
1162    public void setMenuBar(BeanTableFrame<Section> f) {
1163        frame = f;
1164        JMenuBar menuBar = f.getJMenuBar();
1165        int pos = menuBar.getMenuCount() -1; // count the number of menus to insert the TableMenu before 'Window' and 'Help'
1166        int offset = 1;
1167        log.debug("setMenuBar number of menu items = {}", pos);
1168        for (int i = 0; i <= pos; i++) {
1169            if (menuBar.getComponent(i) instanceof JMenu) {
1170                if (((JMenu) menuBar.getComponent(i)).getText().equals(Bundle.getMessage("MenuHelp"))) {
1171                    offset = -1; // correct for use as part of ListedTableAction where the Help Menu is not yet present
1172                }
1173            }
1174        }
1175        JMenu toolsMenu = new JMenu(Bundle.getMessage("MenuTools"));
1176        menuBar.add(toolsMenu, pos + offset);
1177        JMenuItem validate = new JMenuItem(rbx.getString("ValidateAllSections") + "...");
1178        toolsMenu.add(validate);
1179        validate.addActionListener(new ActionListener() {
1180            @Override
1181            public void actionPerformed(ActionEvent e) {
1182                if (sectionManager != null) {
1183                    initializeLayoutEditor(false);
1184                    int n = sectionManager.validateAllSections(frame, panel);
1185                    if (n > 0) {
1186                        JOptionPane.showMessageDialog(frame, java.text.MessageFormat.format(
1187                                rbx.getString("Message14"), new Object[]{"" + n}),
1188                                Bundle.getMessage("ErrorTitle"), JOptionPane.ERROR_MESSAGE);
1189                    } else if (n == -2) {
1190                        JOptionPane.showMessageDialog(frame, rbx.getString("Message16"),
1191                                Bundle.getMessage("ErrorTitle"), JOptionPane.ERROR_MESSAGE);
1192                    } else if (n == 0) {
1193                        JOptionPane.showMessageDialog(frame, rbx.getString("Message15"),
1194                                Bundle.getMessage("MessageTitle"), JOptionPane.INFORMATION_MESSAGE);
1195                    }
1196                }
1197            }
1198        });
1199        JMenuItem setDirSensors = new JMenuItem(rbx.getString("SetupDirectionSensors") + "...");
1200        toolsMenu.add(setDirSensors);
1201        setDirSensors.addActionListener(new ActionListener() {
1202            @Override
1203            public void actionPerformed(ActionEvent e) {
1204                if (sectionManager != null) {
1205                    if (initializeLayoutEditor(true)) {
1206                        int n = sectionManager.setupDirectionSensors(panel);
1207                        if (n > 0) {
1208                            JOptionPane.showMessageDialog(frame, java.text.MessageFormat.format(
1209                                    rbx.getString("Message27"), new Object[]{"" + n}),
1210                                    Bundle.getMessage("ErrorTitle"), JOptionPane.ERROR_MESSAGE);
1211                        } else if (n == -2) {
1212                            JOptionPane.showMessageDialog(frame, rbx.getString("Message30"),
1213                                    Bundle.getMessage("ErrorTitle"), JOptionPane.ERROR_MESSAGE);
1214                        } else if (n == 0) {
1215                            JOptionPane.showMessageDialog(frame, rbx.getString("Message28"),
1216                                    Bundle.getMessage("MessageTitle"), JOptionPane.INFORMATION_MESSAGE);
1217                        }
1218                    }
1219                }
1220            }
1221        });
1222        JMenuItem removeDirSensors = new JMenuItem(rbx.getString("RemoveDirectionSensors") + "...");
1223        toolsMenu.add(removeDirSensors);
1224        removeDirSensors.addActionListener(new ActionListener() {
1225            @Override
1226            public void actionPerformed(ActionEvent e) {
1227                if (sectionManager != null) {
1228                    if (initializeLayoutEditor(true)) {
1229                        int n = sectionManager.removeDirectionSensorsFromSSL(panel);
1230                        if (n > 0) {
1231                            JOptionPane.showMessageDialog(frame, java.text.MessageFormat.format(
1232                                    rbx.getString("Message33"), new Object[]{"" + n}),
1233                                    Bundle.getMessage("ErrorTitle"), JOptionPane.ERROR_MESSAGE);
1234                        } else if (n == -2) {
1235                            JOptionPane.showMessageDialog(frame, rbx.getString("Message32"),
1236                                    Bundle.getMessage("ErrorTitle"), JOptionPane.ERROR_MESSAGE);
1237                        } else if (n == 0) {
1238                            JOptionPane.showMessageDialog(frame, rbx.getString("Message31"),
1239                                    Bundle.getMessage("MessageTitle"), JOptionPane.INFORMATION_MESSAGE);
1240                        }
1241                    }
1242                }
1243            }
1244        });
1245    }
1246
1247    JmriJFrame frame = null;
1248    LayoutEditor panel = null;
1249
1250    private boolean initializeLayoutEditor(boolean required) {
1251        // Get a Layout Editor panel. Choose Layout Editor panel if more than one.
1252        ArrayList<LayoutEditor> layoutEditorList
1253                = new ArrayList<>(InstanceManager.getDefault(EditorManager.class).getAll(LayoutEditor.class));
1254        if (panel == null || !layoutEditorList.isEmpty()) {
1255            if (layoutEditorList.size() > 1) {
1256                // initialize for choosing between layout editors
1257                Object choices[] = new Object[layoutEditorList.size()];
1258                int index = 0;
1259                for (int i = 0; i < layoutEditorList.size(); i++) {
1260                    String txt = layoutEditorList.get(i).getTitle();
1261                    choices[i] = txt;
1262                    if (panel == layoutEditorList.get(i)) {
1263                        index = i;
1264                    }
1265                }
1266                // choose between Layout Editors
1267                Object panelName = JOptionPane.showInputDialog(frame,
1268                        (rbx.getString("Message11")), rbx.getString("ChoiceTitle"),
1269                        JOptionPane.QUESTION_MESSAGE, null, choices, choices[index]);
1270                if ((panelName == null) && required) {
1271                    JOptionPane.showMessageDialog(frame, rbx.getString("Message12"));
1272                    panel = null;
1273                    return false;
1274                }
1275                if (panelName != null) {
1276                    for (int j = 0; j < layoutEditorList.size(); j++) {
1277                        if (panelName.equals(choices[j])) {
1278                            panel = layoutEditorList.get(j);
1279                            return true;
1280                        }
1281                    }
1282                } else {
1283                    log.error("panelName is null!");
1284                }
1285                return false;
1286            } else if (layoutEditorList.size() == 1) {
1287                panel = layoutEditorList.get(0);
1288                return true;
1289            } else {
1290                if (required) {
1291                    JOptionPane.showMessageDialog(frame, rbx.getString("Message13"));
1292                    panel = null;
1293                }
1294                return false;
1295            }
1296        }
1297        return true;
1298    }
1299
1300    /**
1301     * Table model for Blocks in Create/Edit Section window
1302     */
1303    public class BlockTableModel extends javax.swing.table.AbstractTableModel implements
1304            java.beans.PropertyChangeListener {
1305
1306        public static final int SNAME_COLUMN = 0;
1307
1308        public static final int UNAME_COLUMN = 1;
1309
1310        public BlockTableModel() {
1311            super();
1312            blockManager.addPropertyChangeListener(this);
1313        }
1314
1315        @Override
1316        public void propertyChange(java.beans.PropertyChangeEvent e) {
1317            if (e.getPropertyName().equals("length")) {
1318                // a new NamedBean is available in the manager
1319                fireTableDataChanged();
1320            }
1321        }
1322
1323        @Override
1324        public Class<?> getColumnClass(int c) {
1325            return String.class;
1326        }
1327
1328        @Override
1329        public int getColumnCount() {
1330            return 2;
1331        }
1332
1333        @Override
1334        public int getRowCount() {
1335            return (blockList.size());
1336        }
1337
1338        @Override
1339        public boolean isCellEditable(int r, int c) {
1340            return (false);
1341        }
1342
1343        @Override
1344        public String getColumnName(int col) {
1345            switch (col) {
1346                case SNAME_COLUMN:
1347                    return Bundle.getMessage("LabelSystemName");
1348                case UNAME_COLUMN:
1349                    return Bundle.getMessage("LabelUserName");
1350                default:
1351                    return "";
1352            }
1353        }
1354
1355        public int getPreferredWidth(int col) {
1356            switch (col) {
1357                case SNAME_COLUMN:
1358                    return new JTextField(8).getPreferredSize().width;
1359                case UNAME_COLUMN:
1360                    return new JTextField(17).getPreferredSize().width;
1361                default:
1362                    return new JTextField(5).getPreferredSize().width;
1363            }
1364        }
1365
1366        @Override
1367        public Object getValueAt(int r, int c) {
1368            int rx = r;
1369            if (rx > blockList.size()) {
1370                return null;
1371            }
1372            switch (c) {
1373                case SNAME_COLUMN:
1374                    return blockList.get(rx).getSystemName();
1375                case UNAME_COLUMN: //
1376                    return blockList.get(rx).getUserName();
1377                default:
1378                    return Bundle.getMessage("BeanStateUnknown");
1379            }
1380        }
1381
1382        @Override
1383        public void setValueAt(Object value, int row, int col) {
1384            return;
1385        }
1386    }
1387
1388    private void autoSystemName() {
1389        if (_autoSystemName.isSelected()) {
1390            sysName.setEnabled(false);
1391            sysName.setText("");
1392            sysNameLabel.setEnabled(false);
1393        } else {
1394            sysName.setEnabled(true);
1395            sysNameLabel.setEnabled(true);
1396        }
1397    }
1398
1399    /**
1400     * Table model for Entry Points in Create/Edit Section window.
1401     */
1402    public class EntryPointTableModel extends javax.swing.table.AbstractTableModel {
1403
1404        public static final int BLOCK_COLUMN = 0;
1405
1406        public static final int TO_BLOCK_COLUMN = 1;
1407
1408        public static final int DIRECTION_COLUMN = 2;
1409
1410        public EntryPointTableModel() {
1411            super();
1412        }
1413
1414        @Override
1415        public Class<?> getColumnClass(int c) {
1416            if (c == DIRECTION_COLUMN) {
1417                return JComboBox.class;
1418            }
1419            return String.class;
1420        }
1421
1422        @Override
1423        public int getColumnCount() {
1424            return 3;
1425        }
1426
1427        @Override
1428        public int getRowCount() {
1429            return (entryPointList.size());
1430        }
1431
1432        @Override
1433        public boolean isCellEditable(int r, int c) {
1434            if (c == DIRECTION_COLUMN) {
1435                if (!manualEntryPoints) {
1436                    return (false);
1437                } else if (r < entryPointList.size()) {
1438                    return (!entryPointList.get(r).isFixed());
1439                }
1440                return (true);
1441            }
1442            return (false);
1443        }
1444
1445        @Override
1446        public String getColumnName(int col) {
1447            switch (col) {
1448                case BLOCK_COLUMN:
1449                    return rbx.getString("FromBlock");
1450
1451                case TO_BLOCK_COLUMN:
1452                    return rbx.getString("ToBlock");
1453
1454                case DIRECTION_COLUMN:
1455                    return rbx.getString("TravelDirection");
1456                default:
1457                    return "";
1458            }
1459        }
1460
1461        public int getPreferredWidth(int col) {
1462            if (col == BLOCK_COLUMN || col == TO_BLOCK_COLUMN)
1463            {
1464                return new JTextField(37).getPreferredSize().width;
1465            }
1466            if (col == DIRECTION_COLUMN) {
1467                return new JTextField(9).getPreferredSize().width;
1468            }
1469            return new JTextField(5).getPreferredSize().width;
1470        }
1471
1472        @Override
1473        public Object getValueAt(int r, int c) {
1474            int rx = r;
1475            if (rx >= entryPointList.size()) {
1476                return null;
1477            }
1478            switch (c) {
1479                case BLOCK_COLUMN:
1480                    return entryPointList.get(rx).getFromBlockName();
1481
1482                case TO_BLOCK_COLUMN:
1483                    return entryPointList.get(rx).getBlock().getDisplayName();
1484
1485                case DIRECTION_COLUMN: //
1486                    if (entryPointList.get(rx).isForwardType()) {
1487                        return rbx.getString("SectionForward");
1488                    } else if (entryPointList.get(rx).isReverseType()) {
1489                        return rbx.getString("SectionReverse");
1490                    } else {
1491                        return Bundle.getMessage("BeanStateUnknown");
1492                    }
1493                default:
1494                    // fall through
1495                    break;
1496            }
1497            return null;
1498        }
1499
1500        @Override
1501        public void setValueAt(Object value, int row, int col) {
1502            if (col == DIRECTION_COLUMN) {
1503                if (((String) value).equals(rbx.getString("SectionForward"))) {
1504                    entryPointList.get(row).setTypeForward();
1505                } else if (((String) value).equals(rbx.getString("SectionReverse"))) {
1506                    entryPointList.get(row).setTypeReverse();
1507                } else if (((String) value).equals(Bundle.getMessage("BeanStateUnknown"))) {
1508                    entryPointList.get(row).setTypeUnknown();
1509                }
1510            }
1511            return;
1512        }
1513
1514    }
1515
1516    @Override
1517    protected String getClassName() {
1518        return SectionTableAction.class.getName();
1519    }
1520
1521    @Override
1522    public String getClassDescription() {
1523        return Bundle.getMessage("TitleSectionTable");
1524    }
1525
1526    private final static Logger log = LoggerFactory.getLogger(SectionTableAction.class);
1527
1528}