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            pl.getEditor().resizePanelBounds(true);
366            textX.setText("X: " + pl.getX());
367            textY.setText("Y: " + pl.getY());
368            dispose();
369        });
370        okButton.getRootPane().setDefaultButton(okButton);
371
372        cancelButton.addActionListener(e -> {
373            pl.setLocation(oldX, oldY);
374            dispose();
375        });
376        // make large enough to easily move
377        setMinimumSize(new Dimension(250, 175));
378        pack();
379    }
380
381    public void initSetLevel() {
382        oldX = pl.getDisplayLevel();
383        textX = new JLabel();
384        textX.setText(Bundle.getMessage("Level") + ": " + pl.getDisplayLevel());
385        textX.setVisible(true);
386
387        SpinnerNumberModel model = new SpinnerNumberModel(0, 0, 10, 1);
388        spinX = new JSpinner(model);
389        spinX.setValue(pl.getDisplayLevel());
390        spinX.setToolTipText(Bundle.getMessage("EnterLevel"));
391        spinX.setMaximumSize(new Dimension(
392                spinX.getMaximumSize().width, spinX.getPreferredSize().height));
393
394        getContentPane().setLayout(new GridBagLayout());
395
396        addSpinItems(false);
397
398        okButton.addActionListener(e -> {
399            int l = ((Number) spinX.getValue()).intValue();
400            pl.getEditor().setSelectionsDisplayLevel(l, pl);
401            textX.setText(Bundle.getMessage("Level") + ": " + l);
402            dispose();
403        });
404        okButton.getRootPane().setDefaultButton(okButton);
405        cancelButton.addActionListener(e -> {
406            pl.getEditor().setSelectionsDisplayLevel(oldX, pl);
407            dispose();
408        });
409        setMinimumSize(new Dimension(250, 175));
410        pack();
411    }
412
413    public void initSetTip() {
414        oldStr = pl.getToolTip().getText();
415        textX = new JLabel();
416        textX.setText(Bundle.getMessage("TooltipLabel") + ": ");
417        textX.setVisible(true);
418
419        xTextField = new JTextField(15);
420        xTextField.setText(pl.getToolTip().getText());
421        xTextField.setToolTipText(Bundle.getMessage("EnterTooltip"));
422//  xTextField.setMaximumSize(new Dimension(
423//    xTextField.getMaximumSize().width+100, xTextField.getPreferredSize().height));
424
425        getContentPane().setLayout(new GridBagLayout());
426
427        addTextItems();
428
429        okButton.addActionListener(e -> {
430            pl.getToolTip().setText(xTextField.getText()); // is fetched from pane OK but not stored in icon pl
431            dispose();
432        });
433        okButton.getRootPane().setDefaultButton(okButton);
434        cancelButton.addActionListener(e -> {
435            pl.getToolTip().setText(oldStr);
436            dispose();
437        });
438        pack();
439    }
440
441    public void initBorder() {
442        PositionablePopupUtil util = pl.getPopupUtility();
443        oldX = util.getBorderSize();
444
445        textX = new JLabel();
446        textX.setText(Bundle.getMessage("Border") + ": " + util.getBorderSize());
447        textX.setVisible(true);
448
449        SpinnerNumberModel model = new SpinnerNumberModel(0, 0, 1000, 1);
450        spinX = new JSpinner(model);
451        spinX.setValue(util.getBorderSize());
452        spinX.setToolTipText("Enter border size");
453        spinX.setMaximumSize(new Dimension(
454                spinX.getMaximumSize().width, spinX.getPreferredSize().height));
455
456        getContentPane().setLayout(new GridBagLayout());
457
458        addSpinItems(false);
459
460        okButton.addActionListener(e -> {
461            int l = ((Number) spinX.getValue()).intValue();
462            PositionablePopupUtil util1 = pl.getPopupUtility();
463            util1.setBorderSize(l);
464            pl.getEditor().setAttributes(util1, pl);
465            textX.setText(Bundle.getMessage("Border") + ": " + l);
466            dispose();
467        });
468        okButton.getRootPane().setDefaultButton(okButton);
469        cancelButton.addActionListener(e -> {
470            pl.getPopupUtility().setBorderSize(oldX);
471            dispose();
472        });
473        pack();
474    }
475
476    public void initMargin() {
477        PositionablePopupUtil util = pl.getPopupUtility();
478        oldX = util.getMargin();
479
480        textX = new JLabel();
481        textX.setText(Bundle.getMessage("Margin") + ": " + util.getMargin());
482        textX.setVisible(true);
483
484        SpinnerNumberModel model = new SpinnerNumberModel(0, 0, 1000, 1);
485        spinX = new JSpinner(model);
486        spinX.setValue(util.getMargin());
487        spinX.setToolTipText("Enter margin size");
488        spinX.setMaximumSize(new Dimension(
489                spinX.getMaximumSize().width, spinX.getPreferredSize().height));
490
491        getContentPane().setLayout(new GridBagLayout());
492
493        addSpinItems(false);
494
495        okButton.addActionListener(e -> {
496            int l = ((Number) spinX.getValue()).intValue();
497            PositionablePopupUtil util1 = pl.getPopupUtility();
498            pl.getPopupUtility().setMargin(l);
499            pl.getEditor().setAttributes(util1, pl);
500            textX.setText(Bundle.getMessage("Margin") + ": " + l);
501            dispose();
502        });
503        okButton.getRootPane().setDefaultButton(okButton);
504        cancelButton.addActionListener(e -> {
505            pl.getPopupUtility().setMargin(oldX);
506            dispose();
507        });
508        pack();
509    }
510
511    public void initFixedSize() {
512        PositionablePopupUtil util = pl.getPopupUtility();
513        oldX = util.getFixedHeight();
514        oldY = util.getFixedWidth();
515
516        textX = new JLabel();
517        textX.setText("Height = " + util.getFixedHeight());
518        textX.setVisible(true);
519        textY = new JLabel();
520        textY.setText("Width = " + util.getFixedWidth());
521        textY.setVisible(true);
522
523        SpinnerNumberModel model = new SpinnerNumberModel(0, 0, 1000, 1);
524        spinX = new JSpinner(model);
525        spinX.setValue(util.getFixedHeight());
526        spinX.setToolTipText(Bundle.getMessage("FixedSizeHeight"));
527        spinX.setMaximumSize(new Dimension(
528                spinX.getMaximumSize().width, spinX.getPreferredSize().height));
529        model = new SpinnerNumberModel(0, 0, 1000, 1);
530        spinY = new JSpinner(model);
531        spinY.setValue(util.getFixedWidth());
532        spinY.setToolTipText(Bundle.getMessage("FixedSizeWidth"));
533        spinY.setMaximumSize(new Dimension(
534                spinY.getMaximumSize().width, spinY.getPreferredSize().height));
535
536        getContentPane().setLayout(new GridBagLayout());
537
538        addSpinItems(true);
539
540        okButton.addActionListener(e -> {
541            int height = ((Number) spinX.getValue()).intValue();
542            int width = ((Number) spinY.getValue()).intValue();
543            PositionablePopupUtil util1 = pl.getPopupUtility();
544            util1.setFixedSize(width, height);
545            pl.getEditor().setAttributes(util1, pl);
546            textX.setText("Height: " + util1.getFixedHeight());
547            textY.setText("Width: " + util1.getFixedWidth());
548            dispose();
549        });
550        okButton.getRootPane().setDefaultButton(okButton);
551        cancelButton.addActionListener(e -> {
552            pl.getPopupUtility().setFixedSize(oldY, oldX);
553            dispose();
554        });
555        pack();
556    }
557
558    public void initRotate() {
559        oldX = pl.getDegrees();
560
561        textX = new JLabel();
562        int deg = oldX;
563        textX.setText(MessageFormat.format(Bundle.getMessage("Angle"), deg));
564        textX.setVisible(true);
565
566        SpinnerNumberModel model = new SpinnerNumberModel(0, -360, 360, 1);
567        spinX = new JSpinner(model);
568//        spinX.setValue(Integer.valueOf(((NamedIcon)pLabel.getIcon()).getDegrees()));
569        spinX.setValue(deg);
570        spinX.setToolTipText(Bundle.getMessage("enterDegrees"));
571        spinX.setMaximumSize(new Dimension(
572                spinX.getMaximumSize().width, spinX.getPreferredSize().height));
573
574        getContentPane().setLayout(new GridBagLayout());
575
576        addSpinItems(false);
577
578        okButton.addActionListener(e -> {
579            int k = ((Number) spinX.getValue()).intValue();
580            pl.getEditor().setSelectionsRotation(k, pl);
581            textX.setText(MessageFormat.format(Bundle.getMessage("Angle"), k));
582            dispose();
583        });
584        okButton.getRootPane().setDefaultButton(okButton);
585        cancelButton.addActionListener(e -> dispose());
586        pack();
587    }
588
589    public void initScale() {
590        //int scale = (int)Math.round(pl.getScale()*100);
591        oldD = pl.getScale();
592        log.debug("initScale oldD = {}", oldD);
593        log.trace("  pl = {}", pl);
594        textX = new JLabel();
595        textX.setText(MessageFormat.format(Bundle.getMessage("Scale"), oldD * 100));
596        textX.setVisible(true);
597
598        SpinnerNumberModel model = new SpinnerNumberModel(100.0d, 10.0d, 5000.0d, 1.0d);
599        spinX = new JSpinner(model);
600        log.debug("scale%= {}", (int) Math.round(oldD * 100));
601        spinX.setValue((double) 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        oldStr = pl.getId();
623        textX = new JLabel();
624        textX.setText(Bundle.getMessage("EnterId") + ":");
625        textX.setVisible(true);
626
627        xTextField = new JTextField(15);
628        xTextField.setText(pl.getId());
629        xTextField.setToolTipText(Bundle.getMessage("TooltipEnterId"));
630
631        getContentPane().setLayout(new GridBagLayout());
632        addTextItems();
633
634        okButton.addActionListener(e -> {
635            String t = xTextField.getText();
636            boolean hasText = (t != null && t.length() > 0);
637            if (hasText) {
638                try {
639                    pl.setId(t);
640                    pl.updateSize();
641                    dispose();
642                } catch (Positionable.DuplicateIdException ignore) {
643                    JmriJOptionPane.showMessageDialog(editor,
644                            Bundle.getMessage("ErrorIdNotUnique"),
645                            Bundle.getMessage("ErrorDialog"),
646                            JmriJOptionPane.ERROR_MESSAGE);
647                }
648            } else {
649                try {
650                    pl.setId(null);
651                    pl.updateSize();
652                    dispose();
653                } catch (Positionable.DuplicateIdException ex) {
654                    // This should never happen
655                    log.error("Positionable.setId(null) has thrown DuplicateIdException", ex);
656                }
657            }
658        });
659        okButton.getRootPane().setDefaultButton(okButton);
660        cancelButton.addActionListener(e -> {
661            PositionableLabel pp = (PositionableLabel) pl;
662//            pp.setId(oldStr);
663            pp.updateSize();
664            dispose();
665        });
666        pack();
667    }
668
669    public void initClasses(final Editor editor) {
670        PositionableLabel pLabel = (PositionableLabel) pl;
671        oldStr = String.join(",", pLabel.getClasses());
672        textX = new JLabel();
673        textX.setText(Bundle.getMessage("EnterClasses") + ":");
674        textX.setVisible(true);
675
676        xTextField = new JTextField(15);
677        xTextField.setText(oldStr);
678        xTextField.setToolTipText(Bundle.getMessage("TooltipEnterClasses"));
679
680        getContentPane().setLayout(new GridBagLayout());
681        addTextItems();
682
683        okButton.addActionListener(e -> {
684            PositionableLabel pp = (PositionableLabel) pl;
685            pp.removeAllClasses();
686            String t = xTextField.getText();
687            if (t != null && t.length() > 0) {
688                for (String className : t.split(",")) {
689                    if (!className.isBlank()) {
690                        pp.addClass(className.trim());
691                    }
692                }
693            }
694            pp.updateSize();
695            dispose();
696        });
697        okButton.getRootPane().setDefaultButton(okButton);
698        cancelButton.addActionListener(e -> {
699            PositionableLabel pp = (PositionableLabel) pl;
700            pp.updateSize();
701            dispose();
702        });
703        pack();
704    }
705
706    public void initText() {
707        PositionableLabel pLabel = (PositionableLabel) pl;
708        oldStr = pLabel.getUnRotatedText();
709        textX = new JLabel();
710        textX.setText(Bundle.getMessage("TextLabel") + ":");
711        textX.setVisible(true);
712
713        xTextField = new JTextField(15);
714        xTextField.setText(pLabel.getUnRotatedText());
715        xTextField.setToolTipText(Bundle.getMessage("TooltipEnterText"));
716
717        getContentPane().setLayout(new GridBagLayout());
718        addTextItems();
719
720        okButton.addActionListener(e -> {
721            PositionableLabel pp = (PositionableLabel) pl;
722            String t = xTextField.getText();
723            boolean hasText = (t != null && t.length() > 0);
724            if (pp.isIcon() || hasText) {
725                pp._text = hasText;
726                if (pp instanceof SensorIcon) {
727                    ((SensorIcon) pp).setOriginalText(t);
728                }
729                pp.setText(t);
730                pp.updateSize();
731                dispose();
732            } else {
733                xTextField.setText(Bundle.getMessage("warningNullText"));
734            }
735        });
736        okButton.getRootPane().setDefaultButton(okButton);
737        cancelButton.addActionListener(e -> {
738            PositionableLabel pp = (PositionableLabel) pl;
739            pp.setText(oldStr);
740            pp.updateSize();
741            dispose();
742        });
743        pack();
744    }
745
746    public void initLink() {
747        LinkingObject pLabel = (LinkingObject) pl;
748        oldStr = pLabel.getURL();
749        textX = new JLabel();
750        textX.setText(Bundle.getMessage("LinkEqual"));
751        textX.setVisible(true);
752
753        xTextField = new JTextField(15);
754        xTextField.setText(pLabel.getURL());
755        xTextField.setToolTipText(Bundle.getMessage("EnterLink"));
756
757        getContentPane().setLayout(new GridBagLayout());
758        addTextItems();
759        oldX = 0;  // counter for warning
760
761        okButton.addActionListener(e -> {
762            LinkingObject pp = (LinkingObject) pl;
763            String t = xTextField.getText();
764            boolean hasText = (t != null && t.length() > 0);
765            if (hasText || oldX > 0) {
766                pp.setULRL(t);
767                pp.updateSize();
768                dispose();
769            } else {
770                xTextField.setText("Link disappears with null text!");
771                oldX++;
772            }
773        });
774        okButton.getRootPane().setDefaultButton(okButton);
775        cancelButton.addActionListener(e -> {
776            LinkingObject pp = (LinkingObject) pl;
777            pp.setULRL(oldStr);
778            pp.updateSize();
779            dispose();
780        });
781        pack();
782    }
783
784    public void initZoom() {
785        oldD = pl.getScale();
786        log.debug("initZoom oldD = {}", oldD);
787        log.trace("  pl = {}", pl);
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}