001package jmri.jmrit.display;
002
003import java.awt.Component;
004import java.awt.Dimension;
005import java.awt.GridBagConstraints;
006import java.awt.GridBagLayout;
007import java.awt.event.ActionEvent;
008import java.awt.event.WindowEvent;
009import java.text.MessageFormat;
010
011import javax.swing.AbstractAction;
012import javax.swing.JButton;
013import javax.swing.JComponent;
014import javax.swing.JLabel;
015import javax.swing.JSpinner;
016import javax.swing.JTextField;
017import javax.swing.SpinnerNumberModel;
018import javax.swing.event.ChangeListener;
019
020import jmri.util.JmriJFrame;
021import jmri.util.swing.JmriJOptionPane;
022
023/**
024 * Displays and allows user to modify {@literal x & y} coordinates of
025 * positionable labels This class has been generalized to provide popup edit
026 * dialogs for positionable item properties when TextFields are needed to input
027 * data.
028 * <p>
029 * The class name no longer identifies the full purpose of the class, However
030 * the name is retained because coordinate editing was the genesis. The current
031 * list of properties served for editing is:
032 * <ul>
033 * <li>modify {@literal x & y} coordinates modify level modify tooltip modify
034 * border size</li>
035 * <li>modify margin size modify fixed size modify rotation degrees modify
036 * scaling</li>
037 * <li>modify text labels modify zoom scaling modify panel name</li>
038 * </ul>
039 * To use, write a static method that provides the dialog frame. Then write an
040 * initX method that customizes the dialog for the property.
041 *
042 * @author Dan Boudreau Copyright (C) 2007
043 * @author Pete Cressman Copyright (C) 2010
044 */
045public class CoordinateEdit extends JmriJFrame {
046
047    Positionable pl;    // positional label tracked by this frame
048    int oldX;
049    int oldY;
050    double oldD;
051    String oldStr;
052
053    // member declarations
054    JLabel nameText = new JLabel();
055    JLabel textX;
056    JLabel textY;
057
058    // buttons
059    JButton okButton = new JButton();
060    JButton cancelButton = new JButton();
061
062    // text field
063    JTextField xTextField;
064    JTextField yTextField;
065
066    //SpinnerNumberModel _spinModel;
067    JSpinner spinX;
068    JSpinner spinY;
069
070    public static AbstractAction getCoordinateEditAction(final Positionable pos) {
071        return new AbstractAction() {
072            @Override
073            public void actionPerformed(ActionEvent e) {
074                CoordinateEdit f = new CoordinateEdit();
075                f.addHelpMenu("package.jmri.jmrit.display.CoordinateEdit", true);
076                f.init(Bundle.getMessage("SetXY", ""), pos, true); // use property without ellipsis in variable
077                f.initSetXY();
078                f.setVisible(true);
079                f.setLocationRelativeTo((Component) pos);
080            }
081        };
082    }
083    //////////////////////////////////////////////////////////////
084
085    public static AbstractAction getLevelEditAction(final Positionable pos) {
086        return new AbstractAction(Bundle.getMessage("SetLevel", "...")) {
087            @Override
088            public void actionPerformed(ActionEvent e) {
089                CoordinateEdit f = new CoordinateEdit();
090                f.addHelpMenu("package.jmri.jmrit.display.CoordinateEdit", true);
091                f.init(Bundle.getMessage("SetLevel", ""), pos, true); // use property without ellipsis in variable
092                f.initSetLevel();
093                f.setVisible(true);
094                f.setLocationRelativeTo((Component) pos);
095            }
096        };
097    }
098    //////////////////////////////////////////////////////////////
099
100    public static AbstractAction getToolTipEditAction(final Positionable pos) {
101        return new AbstractAction(Bundle.getMessage("SetCustomTooltip", "...")) {
102            @Override
103            public void actionPerformed(ActionEvent e) {
104                CoordinateEdit f = new CoordinateEdit();
105                f.addHelpMenu("package.jmri.jmrit.display.CoordinateEdit", true);
106                f.init(Bundle.getMessage("SetTooltip", ""), pos, true); // use property without ellipsis in variable
107                f.initSetTip();
108                f.setVisible(true);
109                f.setLocationRelativeTo((Component) pos);
110            }
111        };
112    }
113    //////////////////////////////////////////////////////////////
114
115    public static AbstractAction getBorderEditAction(final Positionable pos) {
116        return new AbstractAction(Bundle.getMessage("SetBorderSize", "...")) {
117
118            @Override
119            public void actionPerformed(ActionEvent e) {
120                CoordinateEdit f = new CoordinateEdit();
121                f.addHelpMenu("package.jmri.jmrit.display.CoordinateEdit", true);
122                f.init(Bundle.getMessage("SetBorderSize", ""), pos, true);
123                f.initBorder();
124                f.setVisible(true);
125                f.setLocationRelativeTo((Component) pos);
126            }
127        };
128    }
129    //////////////////////////////////////////////////////////////
130
131    public static AbstractAction getMarginEditAction(final Positionable pos) {
132        return new AbstractAction(Bundle.getMessage("SetMarginSize", "...")) {
133            @Override
134            public void actionPerformed(ActionEvent e) {
135                CoordinateEdit f = new CoordinateEdit();
136                f.addHelpMenu("package.jmri.jmrit.display.CoordinateEdit", true);
137                f.init(Bundle.getMessage("SetMarginSize", ""), pos, true);
138                f.initMargin();
139                f.setVisible(true);
140                f.setLocationRelativeTo((Component) pos);
141            }
142        };
143    }
144    //////////////////////////////////////////////////////////////
145
146    public static AbstractAction getFixedSizeEditAction(final Positionable pos) {
147        return new AbstractAction(Bundle.getMessage("SetFixedSize", "...")) {
148
149            @Override
150            public void actionPerformed(ActionEvent e) {
151                CoordinateEdit f = new CoordinateEdit();
152                f.addHelpMenu("package.jmri.jmrit.display.CoordinateEdit", true);
153                f.init(Bundle.getMessage("SetFixedSize", ""), pos, true);
154                f.initFixedSize();
155                f.setVisible(true);
156                f.setLocationRelativeTo((Component) pos);
157            }
158        };
159    }
160    //////////////////////////////////////////////////////////////
161
162    public static AbstractAction getRotateEditAction(final Positionable pos) {
163        return new AbstractAction(Bundle.getMessage("RotateSign", pos.getDegrees())) { // Bundle property includes degree symbol
164
165            @Override
166            public void actionPerformed(ActionEvent e) {
167                CoordinateEdit f = new CoordinateEdit();
168                f.addHelpMenu("package.jmri.jmrit.display.CoordinateEdit", true);
169                f.init(Bundle.getMessage("Rotate", ""), pos, true);
170                f.initRotate();
171                f.setVisible(true);
172                f.setLocationRelativeTo((Component) pos);
173            }
174        };
175    }
176    //////////////////////////////////////////////////////////////
177
178    public static AbstractAction getScaleEditAction(final Positionable pos) {
179        return new AbstractAction(Bundle.getMessage("Rescale", "...")) {
180
181            @Override
182            public void actionPerformed(ActionEvent e) {
183                CoordinateEdit f = new CoordinateEdit();
184                f.addHelpMenu("package.jmri.jmrit.display.CoordinateEdit", true);
185                f.init(Bundle.getMessage("Rescale", ""), pos, true);
186                f.initScale();
187                f.setVisible(true);
188                f.setLocationRelativeTo((Component) pos);
189            }
190        };
191    }
192    //////////////////////////////////////////////////////////////
193
194    public static AbstractAction getIdEditAction(
195            final Positionable pos, final String title, final Editor editor) {
196
197        return new AbstractAction(Bundle.getMessage(title) + "...") {
198
199            @Override
200            public void actionPerformed(ActionEvent e) {
201                CoordinateEdit f = new CoordinateEdit();
202                f.addHelpMenu("package.jmri.jmrit.display.CoordinateEdit", true);
203                f.init(Bundle.getMessage(title), pos, false);
204                f.initId(editor);
205                f.setVisible(true);
206                f.setLocationRelativeTo((Component) pos);
207            }
208        };
209    }
210    //////////////////////////////////////////////////////////////
211
212    public static AbstractAction getClassesEditAction(
213            final Positionable pos, final String title, final Editor editor) {
214
215        return new AbstractAction(Bundle.getMessage(title) + "...") {
216
217            @Override
218            public void actionPerformed(ActionEvent e) {
219                CoordinateEdit f = new CoordinateEdit();
220                f.addHelpMenu("package.jmri.jmrit.display.CoordinateEdit", true);
221                f.init(Bundle.getMessage(title), pos, false);
222                f.initClasses(editor);
223                f.setVisible(true);
224                f.setLocationRelativeTo((Component) pos);
225            }
226        };
227    }
228    //////////////////////////////////////////////////////////////
229
230    public static AbstractAction getTextEditAction(final Positionable pos, final String title) {
231        return new AbstractAction(Bundle.getMessage(title) + "...") {
232
233            @Override
234            public void actionPerformed(ActionEvent e) {
235                CoordinateEdit f = new CoordinateEdit();
236                f.addHelpMenu("package.jmri.jmrit.display.CoordinateEdit", true);
237                f.init(Bundle.getMessage(title), pos, false);
238                f.initText();
239                f.setVisible(true);
240                f.setLocationRelativeTo((Component) pos);
241            }
242        };
243    }
244    //////////////////////////////////////////////////////////////
245
246    public static AbstractAction getLinkEditAction(final Positionable pos, final String title) {
247        return new AbstractAction(Bundle.getMessage(title) + "...") {
248
249            @Override
250            public void actionPerformed(ActionEvent e) {
251                CoordinateEdit f = new CoordinateEdit();
252                f.addHelpMenu("package.jmri.jmrit.display.CoordinateEdit", true);
253                f.init(Bundle.getMessage(title), pos, false);
254                f.initLink();
255                f.setVisible(true);
256                f.setLocationRelativeTo((Component) pos);
257            }
258        };
259    }
260    //////////////////////////////////////////////////////////////
261
262    public static AbstractAction getZoomEditAction(final Positionable pos) {
263        return new AbstractAction(Bundle.getMessage("Zoom", "...")) {
264
265            @Override
266            public void actionPerformed(ActionEvent e) {
267                CoordinateEdit f = new CoordinateEdit();
268                f.addHelpMenu("package.jmri.jmrit.display.CoordinateEdit", true);
269                f.init(Bundle.getMessage("Zoom", ""), pos, false);
270                f.initZoom();
271                f.setVisible(true);
272                //f.setLocation(100,100);
273                f.setLocationRelativeTo(pos.getEditor().getTargetPanel());
274            }
275        };
276    }
277    //////////////////////////////////////////////////////////////
278
279    public static AbstractAction getNameEditAction(final Positionable pos) {
280        return new AbstractAction(Bundle.getMessage("renamePanelMenu", "...")) {
281
282            @Override
283            public void actionPerformed(ActionEvent e) {
284                CoordinateEdit f = new CoordinateEdit();
285                f.addHelpMenu("package.jmri.jmrit.display.CoordinateEdit", true);
286                f.init(Bundle.getMessage("renamePanelMenu", ""), pos, false);
287                f.initSetName();
288                f.setVisible(true);
289                //f.setLocation(100,100);
290                f.setLocationRelativeTo(pos.getEditor().getTargetPanel());
291            }
292        };
293    }
294    //////////////////////////////////////////////////////////////
295
296    public CoordinateEdit() {
297        super(false, false);
298    }
299
300    @Override
301    public void windowClosed(WindowEvent e) {
302        super.windowClosed(e);
303    }
304
305    public void init(String title, Positionable pos, boolean showName) {
306        pl = pos;
307        if (showName) {
308            nameText.setText(MessageFormat.format(Bundle.getMessage("namelabel"), pos.getNameString()));
309            nameText.setVisible(true);
310        }
311        okButton.setText(Bundle.getMessage("ButtonOK"));
312        okButton.setVisible(true);
313
314        cancelButton.setText(Bundle.getMessage("ButtonCancel"));
315        cancelButton.setVisible(true);
316
317        Dimension dim = (new JButton("XXXXXXXX")).getPreferredSize();
318        okButton.setMinimumSize(dim);
319        cancelButton.setMinimumSize(dim);
320        setTitle(title);
321        //setLocation(pl.getLocation());
322    }
323
324    public void initSetXY() {
325        oldX = pl.getX();
326        oldY = pl.getY();
327
328        textX = new JLabel();
329        textX.setText("X: " + pl.getX());
330        textX.setVisible(true);
331        textY = new JLabel();
332        textY.setText("Y: " + pl.getY());
333        textY.setVisible(true);
334
335        SpinnerNumberModel model = new SpinnerNumberModel(0, 0, 10000, 1);
336        ChangeListener listener = e -> {
337            int x = ((Number) spinX.getValue()).intValue();
338            int y = ((Number) spinY.getValue()).intValue();
339            pl.setLocation(x, y);
340            textX.setText("X: " + pl.getX());
341            textY.setText("Y: " + pl.getY());
342        };
343        spinX = new JSpinner(model);
344        spinX.setValue(pl.getX());
345        spinX.setToolTipText(Bundle.getMessage("EnterXcoord"));
346        spinX.setMaximumSize(new Dimension(
347                spinX.getMaximumSize().width, spinX.getPreferredSize().height));
348        spinX.addChangeListener(listener);
349        model = new SpinnerNumberModel(0, 0, 10000, 1);
350        spinY = new JSpinner(model);
351        spinY.setValue(pl.getY());
352        spinY.setToolTipText(Bundle.getMessage("EnterYcoord"));
353        spinY.setMaximumSize(new Dimension(
354                spinY.getMaximumSize().width, spinY.getPreferredSize().height));
355        spinY.addChangeListener(listener);
356
357        getContentPane().setLayout(new GridBagLayout());
358
359        addSpinItems(true);
360
361        okButton.addActionListener(e -> {
362            int x = ((Number) spinX.getValue()).intValue();
363            int y = ((Number) spinY.getValue()).intValue();
364            pl.setLocation(x, y);
365            textX.setText("X: " + pl.getX());
366            textY.setText("Y: " + pl.getY());
367            dispose();
368        });
369        okButton.getRootPane().setDefaultButton(okButton);
370
371        cancelButton.addActionListener(e -> {
372            pl.setLocation(oldX, oldY);
373            dispose();
374        });
375        // make large enough to easily move
376        setMinimumSize(new Dimension(250, 175));
377        pack();
378    }
379
380    public void initSetLevel() {
381        oldX = pl.getDisplayLevel();
382        textX = new JLabel();
383        textX.setText(Bundle.getMessage("Level") + ": " + pl.getDisplayLevel());
384        textX.setVisible(true);
385
386        SpinnerNumberModel model = new SpinnerNumberModel(0, 0, 10, 1);
387        spinX = new JSpinner(model);
388        spinX.setValue(pl.getDisplayLevel());
389        spinX.setToolTipText(Bundle.getMessage("EnterLevel"));
390        spinX.setMaximumSize(new Dimension(
391                spinX.getMaximumSize().width, spinX.getPreferredSize().height));
392
393        getContentPane().setLayout(new GridBagLayout());
394
395        addSpinItems(false);
396
397        okButton.addActionListener(e -> {
398            int l = ((Number) spinX.getValue()).intValue();
399            pl.getEditor().setSelectionsDisplayLevel(l, pl);
400            textX.setText(Bundle.getMessage("Level") + ": " + l);
401            dispose();
402        });
403        okButton.getRootPane().setDefaultButton(okButton);
404        cancelButton.addActionListener(e -> {
405            pl.getEditor().setSelectionsDisplayLevel(oldX, pl);
406            dispose();
407        });
408        setMinimumSize(new Dimension(250, 175));
409        pack();
410    }
411
412    public void initSetTip() {
413        oldStr = pl.getToolTip().getText();
414        textX = new JLabel();
415        textX.setText(Bundle.getMessage("TooltipLabel") + ": ");
416        textX.setVisible(true);
417
418        xTextField = new JTextField(15);
419        xTextField.setText(pl.getToolTip().getText());
420        xTextField.setToolTipText(Bundle.getMessage("EnterTooltip"));
421//  xTextField.setMaximumSize(new Dimension(
422//    xTextField.getMaximumSize().width+100, xTextField.getPreferredSize().height));
423
424        getContentPane().setLayout(new GridBagLayout());
425
426        addTextItems();
427
428        okButton.addActionListener(e -> {
429            pl.getToolTip().setText(xTextField.getText()); // is fetched from pane OK but not stored in icon pl
430            dispose();
431        });
432        okButton.getRootPane().setDefaultButton(okButton);
433        cancelButton.addActionListener(e -> {
434            pl.getToolTip().setText(oldStr);
435            dispose();
436        });
437        pack();
438    }
439
440    public void initBorder() {
441        PositionablePopupUtil util = pl.getPopupUtility();
442        oldX = util.getBorderSize();
443
444        textX = new JLabel();
445        textX.setText(Bundle.getMessage("Border") + ": " + util.getBorderSize());
446        textX.setVisible(true);
447
448        SpinnerNumberModel model = new SpinnerNumberModel(0, 0, 1000, 1);
449        spinX = new JSpinner(model);
450        spinX.setValue(util.getBorderSize());
451        spinX.setToolTipText("Enter border size");
452        spinX.setMaximumSize(new Dimension(
453                spinX.getMaximumSize().width, spinX.getPreferredSize().height));
454
455        getContentPane().setLayout(new GridBagLayout());
456
457        addSpinItems(false);
458
459        okButton.addActionListener(e -> {
460            int l = ((Number) spinX.getValue()).intValue();
461            PositionablePopupUtil util1 = pl.getPopupUtility();
462            util1.setBorderSize(l);
463            pl.getEditor().setAttributes(util1, pl);
464            textX.setText(Bundle.getMessage("Border") + ": " + l);
465            dispose();
466        });
467        okButton.getRootPane().setDefaultButton(okButton);
468        cancelButton.addActionListener(e -> {
469            pl.getPopupUtility().setBorderSize(oldX);
470            dispose();
471        });
472        pack();
473    }
474
475    public void initMargin() {
476        PositionablePopupUtil util = pl.getPopupUtility();
477        oldX = util.getMargin();
478
479        textX = new JLabel();
480        textX.setText(Bundle.getMessage("Margin") + ": " + util.getMargin());
481        textX.setVisible(true);
482
483        SpinnerNumberModel model = new SpinnerNumberModel(0, 0, 1000, 1);
484        spinX = new JSpinner(model);
485        spinX.setValue(util.getMargin());
486        spinX.setToolTipText("Enter margin size");
487        spinX.setMaximumSize(new Dimension(
488                spinX.getMaximumSize().width, spinX.getPreferredSize().height));
489
490        getContentPane().setLayout(new GridBagLayout());
491
492        addSpinItems(false);
493
494        okButton.addActionListener(e -> {
495            int l = ((Number) spinX.getValue()).intValue();
496            PositionablePopupUtil util1 = pl.getPopupUtility();
497            pl.getPopupUtility().setMargin(l);
498            pl.getEditor().setAttributes(util1, pl);
499            textX.setText(Bundle.getMessage("Margin") + ": " + l);
500            dispose();
501        });
502        okButton.getRootPane().setDefaultButton(okButton);
503        cancelButton.addActionListener(e -> {
504            pl.getPopupUtility().setMargin(oldX);
505            dispose();
506        });
507        pack();
508    }
509
510    public void initFixedSize() {
511        PositionablePopupUtil util = pl.getPopupUtility();
512        oldX = util.getFixedHeight();
513        oldY = util.getFixedWidth();
514
515        textX = new JLabel();
516        textX.setText("Height = " + util.getFixedHeight());
517        textX.setVisible(true);
518        textY = new JLabel();
519        textY.setText("Width = " + util.getFixedWidth());
520        textY.setVisible(true);
521
522        SpinnerNumberModel model = new SpinnerNumberModel(0, 0, 1000, 1);
523        spinX = new JSpinner(model);
524        spinX.setValue(util.getFixedHeight());
525        spinX.setToolTipText(Bundle.getMessage("FixedSizeHeight"));
526        spinX.setMaximumSize(new Dimension(
527                spinX.getMaximumSize().width, spinX.getPreferredSize().height));
528        model = new SpinnerNumberModel(0, 0, 1000, 1);
529        spinY = new JSpinner(model);
530        spinY.setValue(util.getFixedWidth());
531        spinY.setToolTipText(Bundle.getMessage("FixedSizeWidth"));
532        spinY.setMaximumSize(new Dimension(
533                spinY.getMaximumSize().width, spinY.getPreferredSize().height));
534
535        getContentPane().setLayout(new GridBagLayout());
536
537        addSpinItems(true);
538
539        okButton.addActionListener(e -> {
540            int height = ((Number) spinX.getValue()).intValue();
541            int width = ((Number) spinY.getValue()).intValue();
542            PositionablePopupUtil util1 = pl.getPopupUtility();
543            util1.setFixedSize(width, height);
544            pl.getEditor().setAttributes(util1, pl);
545            textX.setText("Height: " + util1.getFixedHeight());
546            textY.setText("Width: " + util1.getFixedWidth());
547            dispose();
548        });
549        okButton.getRootPane().setDefaultButton(okButton);
550        cancelButton.addActionListener(e -> {
551            pl.getPopupUtility().setFixedSize(oldY, oldX);
552            dispose();
553        });
554        pack();
555    }
556
557    public void initRotate() {
558        oldX = pl.getDegrees();
559
560        textX = new JLabel();
561        int deg = oldX;
562        textX.setText(MessageFormat.format(Bundle.getMessage("Angle"), deg));
563        textX.setVisible(true);
564
565        SpinnerNumberModel model = new SpinnerNumberModel(0, -360, 360, 1);
566        spinX = new JSpinner(model);
567//        spinX.setValue(Integer.valueOf(((NamedIcon)pLabel.getIcon()).getDegrees()));
568        spinX.setValue(deg);
569        spinX.setToolTipText(Bundle.getMessage("enterDegrees"));
570        spinX.setMaximumSize(new Dimension(
571                spinX.getMaximumSize().width, spinX.getPreferredSize().height));
572
573        getContentPane().setLayout(new GridBagLayout());
574
575        addSpinItems(false);
576
577        okButton.addActionListener(e -> {
578            int k = ((Number) spinX.getValue()).intValue();
579            pl.getEditor().setSelectionsRotation(k, pl);
580            textX.setText(MessageFormat.format(Bundle.getMessage("Angle"), k));
581            dispose();
582        });
583        okButton.getRootPane().setDefaultButton(okButton);
584        cancelButton.addActionListener(e -> dispose());
585        pack();
586    }
587
588    public void initScale() {
589        //int scale = (int)Math.round(pl.getScale()*100);
590        oldD = pl.getScale();
591
592        textX = new JLabel();
593        textX.setText(MessageFormat.format(Bundle.getMessage("Scale"), oldD * 100));
594        textX.setVisible(true);
595
596        SpinnerNumberModel model = new SpinnerNumberModel(100.0, 10.0, 5000.0, 1.0);
597        spinX = new JSpinner(model);
598        if (log.isDebugEnabled()) {
599            log.debug("scale%= {}", (int) Math.round(oldD * 100));
600        }
601        spinX.setValue((int) Math.round(oldD * 100));
602        spinX.setToolTipText(Bundle.getMessage("enterScale"));
603        spinX.setMaximumSize(new Dimension(
604                spinX.getMaximumSize().width, spinX.getPreferredSize().height));
605
606        getContentPane().setLayout(new GridBagLayout());
607
608        addSpinItems(false);
609
610        okButton.addActionListener(e -> {
611            double s = ((Number) spinX.getValue()).doubleValue() / 100;
612            pl.getEditor().setSelectionsScale(s, pl);
613            textX.setText(MessageFormat.format(Bundle.getMessage("Scale"), pl.getScale() * 100));
614            dispose();
615        });
616        okButton.getRootPane().setDefaultButton(okButton);
617        cancelButton.addActionListener(e -> dispose());
618        pack();
619    }
620
621    public void initId(final Editor editor) {
622        PositionableLabel pLabel = (PositionableLabel) pl;
623        oldStr = pLabel.getId();
624        textX = new JLabel();
625        textX.setText(Bundle.getMessage("EnterId") + ":");
626        textX.setVisible(true);
627
628        xTextField = new JTextField(15);
629        xTextField.setText(pLabel.getId());
630        xTextField.setToolTipText(Bundle.getMessage("TooltipEnterId"));
631
632        getContentPane().setLayout(new GridBagLayout());
633        addTextItems();
634
635        okButton.addActionListener(e -> {
636            PositionableLabel pp = (PositionableLabel) pl;
637            String t = xTextField.getText();
638            boolean hasText = (t != null && t.length() > 0);
639            if (hasText) {
640                try {
641                    pp.setId(t);
642                    pp.updateSize();
643                    dispose();
644                } catch (Positionable.DuplicateIdException ignore) {
645                    JmriJOptionPane.showMessageDialog(editor,
646                            Bundle.getMessage("ErrorIdNotUnique"),
647                            Bundle.getMessage("ErrorDialog"),
648                            JmriJOptionPane.ERROR_MESSAGE);
649                }
650            } else {
651                try {
652                    pp.setId(null);
653                    pp.updateSize();
654                    dispose();
655                } catch (Positionable.DuplicateIdException ex) {
656                    // This should never happen
657                    log.error("Positionable.setId(null) has thrown DuplicateIdException", ex);
658                }
659            }
660        });
661        okButton.getRootPane().setDefaultButton(okButton);
662        cancelButton.addActionListener(e -> {
663            PositionableLabel pp = (PositionableLabel) pl;
664//            pp.setId(oldStr);
665            pp.updateSize();
666            dispose();
667        });
668        pack();
669    }
670
671    public void initClasses(final Editor editor) {
672        PositionableLabel pLabel = (PositionableLabel) pl;
673        oldStr = String.join(",", pLabel.getClasses());
674        textX = new JLabel();
675        textX.setText(Bundle.getMessage("EnterClasses") + ":");
676        textX.setVisible(true);
677
678        xTextField = new JTextField(15);
679        xTextField.setText(oldStr);
680        xTextField.setToolTipText(Bundle.getMessage("TooltipEnterClasses"));
681
682        getContentPane().setLayout(new GridBagLayout());
683        addTextItems();
684
685        okButton.addActionListener(e -> {
686            PositionableLabel pp = (PositionableLabel) pl;
687            pp.removeAllClasses();
688            String t = xTextField.getText();
689            if (t != null && t.length() > 0) {
690                for (String className : t.split(",")) {
691                    if (!className.isBlank()) {
692                        pp.addClass(className.trim());
693                    }
694                }
695            }
696            pp.updateSize();
697            dispose();
698        });
699        okButton.getRootPane().setDefaultButton(okButton);
700        cancelButton.addActionListener(e -> {
701            PositionableLabel pp = (PositionableLabel) pl;
702            pp.updateSize();
703            dispose();
704        });
705        pack();
706    }
707
708    public void initText() {
709        PositionableLabel pLabel = (PositionableLabel) pl;
710        oldStr = pLabel.getUnRotatedText();
711        textX = new JLabel();
712        textX.setText(Bundle.getMessage("TextLabel") + ":");
713        textX.setVisible(true);
714
715        xTextField = new JTextField(15);
716        xTextField.setText(pLabel.getUnRotatedText());
717        xTextField.setToolTipText(Bundle.getMessage("TooltipEnterText"));
718
719        getContentPane().setLayout(new GridBagLayout());
720        addTextItems();
721
722        okButton.addActionListener(e -> {
723            PositionableLabel pp = (PositionableLabel) pl;
724            String t = xTextField.getText();
725            boolean hasText = (t != null && t.length() > 0);
726            if (pp.isIcon() || hasText) {
727                pp._text = hasText;
728                if (pp instanceof SensorIcon) {
729                    ((SensorIcon) pp).setOriginalText(t);
730                }
731                pp.setText(t);
732                pp.updateSize();
733                dispose();
734            } else {
735                xTextField.setText(Bundle.getMessage("warningNullText"));
736            }
737        });
738        okButton.getRootPane().setDefaultButton(okButton);
739        cancelButton.addActionListener(e -> {
740            PositionableLabel pp = (PositionableLabel) pl;
741            pp.setText(oldStr);
742            pp.updateSize();
743            dispose();
744        });
745        pack();
746    }
747
748    public void initLink() {
749        LinkingObject pLabel = (LinkingObject) pl;
750        oldStr = pLabel.getURL();
751        textX = new JLabel();
752        textX.setText(Bundle.getMessage("LinkEqual"));
753        textX.setVisible(true);
754
755        xTextField = new JTextField(15);
756        xTextField.setText(pLabel.getURL());
757        xTextField.setToolTipText(Bundle.getMessage("EnterLink"));
758
759        getContentPane().setLayout(new GridBagLayout());
760        addTextItems();
761        oldX = 0;  // counter for warning
762
763        okButton.addActionListener(e -> {
764            LinkingObject pp = (LinkingObject) pl;
765            String t = xTextField.getText();
766            boolean hasText = (t != null && t.length() > 0);
767            if (hasText || oldX > 0) {
768                pp.setULRL(t);
769                pp.updateSize();
770                dispose();
771            } else {
772                xTextField.setText("Link disappears with null text!");
773                oldX++;
774            }
775        });
776        okButton.getRootPane().setDefaultButton(okButton);
777        cancelButton.addActionListener(e -> {
778            LinkingObject pp = (LinkingObject) pl;
779            pp.setULRL(oldStr);
780            pp.updateSize();
781            dispose();
782        });
783        pack();
784    }
785
786    public void initZoom() {
787        oldD = pl.getScale();
788
789        textX = new JLabel();
790        textX.setText(MessageFormat.format(Bundle.getMessage("Scale"), oldD * 100));
791        textX.setVisible(true);
792
793        SpinnerNumberModel model = new SpinnerNumberModel(100.0, 1.0, 5000.0, 1.0);
794        spinX = new JSpinner(model);
795        if (log.isDebugEnabled()) {
796            log.debug("scale%= {}", (int) Math.round(oldD * 100));
797        }
798        spinX.setToolTipText(Bundle.getMessage("enterZoom"));
799        spinX.setMaximumSize(new Dimension(
800                spinX.getMaximumSize().width, spinX.getPreferredSize().height));
801
802        getContentPane().setLayout(new GridBagLayout());
803
804        addSpinItems(false);
805
806        okButton.addActionListener(e -> {
807            double s = ((Number) spinX.getValue()).doubleValue() / 100;
808            pl.setScale(s);
809            pl.getEditor().setPaintScale(s);
810            textX.setText(MessageFormat.format(Bundle.getMessage("Scale"), pl.getScale() * 100));
811            dispose();
812        });
813        okButton.getRootPane().setDefaultButton(okButton);
814        cancelButton.addActionListener(e -> dispose());
815        pack();
816    }
817
818    public void initSetName() {
819        oldStr = pl.getEditor().getName();
820
821        textX = new JLabel();
822        textX.setText(MessageFormat.format(Bundle.getMessage("namelabel"), oldStr));
823        textX.setVisible(true);
824
825        xTextField = new JTextField(15);
826        xTextField.setText(oldStr);
827        xTextField.setToolTipText(Bundle.getMessage("PromptNewName"));
828//  xTextField.setMaximumSize(new Dimension(1000, xTextField.getPreferredSize().height));
829//    xTextField.getMaximumSize().width+100, xTextField.getPreferredSize().height));
830
831        getContentPane().setLayout(new GridBagLayout());
832
833        addTextItems();
834
835        okButton.addActionListener(e -> {
836            String t = xTextField.getText();
837            Editor ed = pl.getEditor();
838            ed.setName(t);
839            ed.setTitle();
840            textX.setText(MessageFormat.format(Bundle.getMessage("namelabel"), t));
841            dispose();
842        });
843        okButton.getRootPane().setDefaultButton(okButton);
844        cancelButton.addActionListener(e -> {
845            pl.getEditor().setName(oldStr);
846            dispose();
847        });
848        pack();
849    }
850
851    protected void addSpinItems(boolean addY) {
852        addItem(nameText, 0, 0, 2, true);
853        addItem(textX, 0, 1, 1, true);
854        addItem(spinX, 1, 1, 1, false);
855        if (addY) {
856            addItem(textY, 0, 2, 1, true);
857            addItem(spinY, 1, 2, 1, false);
858            addItem(cancelButton, 0, 3, 1, false);
859            addItem(okButton, 1, 3, 1, false);
860        } else {
861            addItem(cancelButton, 0, 2, 1, false);
862            addItem(okButton, 1, 2, 1, false);
863        }
864        validate();
865    }
866
867    private void addTextItems() {
868        addItem(nameText, 0, 0, 2, true);
869        addItem(textX, 0, 1, 1, true);
870        addItem(xTextField, 1, 1, 1, true);
871        addItem(cancelButton, 0, 2, 1, false);
872        addItem(okButton, 1, 2, 1, false);
873        validate();
874    }
875
876    private void addItem(JComponent c, int x, int y, int w, boolean horzExpand) {
877        GridBagConstraints gc = new GridBagConstraints();
878        gc.gridx = x;
879        gc.gridy = y;
880        gc.gridwidth = w;
881        gc.weightx = 100.0;
882        gc.weighty = 100.0;
883        gc.anchor = GridBagConstraints.CENTER;
884        if (horzExpand) {
885            gc.fill = GridBagConstraints.HORIZONTAL;  // text field will expand
886        }
887        getContentPane().add(c, gc);
888    }
889
890    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CoordinateEdit.class);
891
892}