001package jmri.jmrit.display;
002
003import java.awt.Color;
004import java.awt.Font;
005import java.awt.GraphicsEnvironment;
006import java.awt.event.ActionEvent;
007import java.util.ArrayList;
008import javax.swing.AbstractAction;
009import javax.swing.BorderFactory;
010import javax.swing.ButtonGroup;
011import javax.swing.JCheckBoxMenuItem;
012import javax.swing.JComponent;
013import javax.swing.JLabel;
014import javax.swing.JMenu;
015import javax.swing.JMenuItem;
016import javax.swing.JPopupMenu;
017import javax.swing.JRadioButtonMenuItem;
018import javax.swing.JTextField;
019import javax.swing.border.Border;
020import javax.swing.border.CompoundBorder;
021import javax.swing.border.LineBorder;
022import jmri.util.MenuScroller;
023import jmri.util.swing.JmriColorChooser;
024import org.slf4j.Logger;
025import org.slf4j.LoggerFactory;
026
027/**
028 * This class handles text attributes for Positionables. Font, size, style and
029 * color. Margin size and color, Border size and color, Fixed sizes.
030 * Justification.
031 * <p>
032 * moved from PositionableLabel
033 *
034 * @author Pete Cressman copyright (C) 2010
035 */
036public class PositionablePopupUtil {
037
038    protected JComponent _textComponent;    // closest ancestor for JLabel and JTextField
039    protected int _textType;                // JComponent does not have text, used for casting
040    protected Positionable _parent;
041    protected PositionablePopupUtil _self;
042    protected PositionablePropertiesUtil _propertiesUtil;
043
044    private final Color defaultBorderColor;
045    private boolean _suppressRecentColor = false;
046
047    protected final int LABEL = 1;
048    protected final int TEXTFIELD = 2;
049    protected final int JCOMPONENT = 3;
050
051    public PositionablePopupUtil(Positionable parent, JComponent textComp) {
052        _parent = parent;
053        if (textComp instanceof JLabel) {
054            _textType = LABEL;
055        } else if (textComp instanceof JTextField) {
056            _textType = TEXTFIELD;
057        } else {
058            _textType = JCOMPONENT;
059        }
060        _textComponent = textComp;
061        _self = this;
062
063        defaultBorderColor = _parent.getBackground();
064        _propertiesUtil = new PositionablePropertiesUtil(_parent);
065    }
066
067    public PositionablePopupUtil clone(Positionable parent, JComponent textComp) {
068        PositionablePopupUtil util = new PositionablePopupUtil(parent, textComp);
069        util.setJustification(getJustification());
070        util.setHorizontalAlignment(getJustification());
071        util.setFixedWidth(getFixedWidth());
072        util.setFixedHeight(getFixedHeight());
073        util.setMargin(getMargin());
074        util.setBorderSize(getBorderSize());
075        util.setBorderColor(getBorderColor());
076        util.setFont(getFont().deriveFont(getFontStyle()));
077        util.setFontSize(getFontSize());
078        util.setFontStyle(getFontStyle());
079        util.setOrientation(getOrientation());
080        util.setBackgroundColor(getBackground());
081        util.setForeground(getForeground());
082        util.setHasBackground(hasBackground());     // must do this AFTER setBackgroundColor
083        return util;
084    }
085
086    @Override
087    public String toString() {
088        return _parent.getNameString() + ": fixedWidth= " + fixedWidth + ", fixedHeight= " + fixedHeight
089                + ", margin= " + margin + ", borderSize= " + borderSize;
090    }
091
092    /**
093     * *************************************************************************************
094     */
095    static final public int FONT_COLOR = 0x00;
096    static final public int BACKGROUND_COLOR = 0x01;
097    static final public int BORDER_COLOR = 0x02;
098    static final public int MIN_SIZE = 5;
099
100    private int fixedWidth = 0;
101    private int fixedHeight = 0;
102    private int margin = 0;
103    private int borderSize = 0;
104    private Color borderColor = null;
105    private Border borderMargin = BorderFactory.createEmptyBorder(0, 0, 0, 0);
106    private Border outlineBorder = BorderFactory.createEmptyBorder(0, 0, 0, 0);
107    private boolean _hasBackground;      // Should background be painted or clear
108
109    JMenuItem italic = null;
110    JMenuItem bold = null;
111
112    public void propertyUtil(JPopupMenu popup) {
113        JMenuItem edit = new JMenuItem(Bundle.getMessage("MenuItemProperties") + "...");
114        edit.addActionListener((ActionEvent e) -> _propertiesUtil.display());
115        popup.add(edit);
116    }
117
118    public void setFixedTextMenu(JPopupMenu popup) {
119        JMenu edit = new JMenu(Bundle.getMessage("EditFixed"));
120        JMenuItem jmi;
121        if (getFixedWidth() == 0) {
122            jmi = edit.add("Width = Auto");
123        } else {
124            jmi = edit.add("Width = " + _parent.maxWidth());
125        }
126        jmi.setEnabled(false);
127
128        if (getFixedHeight() == 0) {
129            jmi = edit.add("Height = Auto");
130        } else {
131            jmi = edit.add("Height = " + _parent.maxHeight());
132        }
133        jmi.setEnabled(false);
134
135        edit.add(CoordinateEdit.getFixedSizeEditAction(_parent));
136
137        popup.add(edit);
138    }
139
140    public void setTextMarginMenu(JPopupMenu popup) {
141        JMenu edit = new JMenu(Bundle.getMessage("EditMargin"));
142        if ((fixedHeight == 0) || (fixedWidth == 0)) {
143            JMenuItem jmi = edit.add("Margin = " + getMargin());
144            jmi.setEnabled(false);
145            edit.add(CoordinateEdit.getMarginEditAction(_parent));
146        }
147        popup.add(edit);
148    }
149
150    public void setBackgroundMenu(JPopupMenu popup) {
151        JMenuItem edit = new JMenuItem(Bundle.getMessage("FontBackgroundColor"));
152        edit.addActionListener((ActionEvent event) -> {
153            Color desiredColor = JmriColorChooser.showDialog(_textComponent,
154                                 Bundle.getMessage("FontBackgroundColor"),
155                                 getBackground());
156            if (desiredColor!=null ) {
157               setBackgroundColor(desiredColor);
158           }
159        });
160
161        popup.add(edit);
162
163    }
164
165    public void setTextBorderMenu(JPopupMenu popup) {
166        JMenu edit = new JMenu(Bundle.getMessage("EditBorder"));
167        JMenuItem jmi = edit.add("Border Size = " + borderSize);
168        jmi.setEnabled(false);
169        edit.add(CoordinateEdit.getBorderEditAction(_parent));
170        JMenuItem colorMenu = new JMenuItem(Bundle.getMessage("BorderColorMenu"));
171        colorMenu.addActionListener((ActionEvent event) -> {
172            Color desiredColor = JmriColorChooser.showDialog(_textComponent,
173                                 Bundle.getMessage("BorderColorMenu"),
174                                 defaultBorderColor);
175            if (desiredColor!=null ) {
176               setBorderColor(desiredColor);
177           }
178        });
179        edit.add(colorMenu);
180        popup.add(edit);
181    }
182
183    public void setTextFontMenu(JPopupMenu popup) {
184        JMenu edit = new JMenu(Bundle.getMessage("EditFont"));
185        edit.add(makeFontMenu());
186        edit.add(makeFontSizeMenu());
187        edit.add(makeFontStyleMenu());
188        JMenuItem colorMenu = new JMenuItem(Bundle.getMessage("FontColor"));
189        colorMenu.addActionListener((ActionEvent event) -> {
190            Color desiredColor = JmriColorChooser.showDialog(_textComponent,
191                                 Bundle.getMessage("FontColor"),
192                                 _textComponent.getForeground());
193            if (desiredColor!=null ) {
194               _textComponent.setForeground(desiredColor);
195           }
196        });
197        edit.add(colorMenu);
198        popup.add(edit);
199    }
200
201    public int getMargin() {
202        return margin;
203    }
204
205    public void setMargin(int m) {
206        margin = m;
207        if (_parent.isOpaque()) {
208            borderMargin = new LineBorder(getBackground(), m);
209        } else {
210            borderMargin = BorderFactory.createEmptyBorder(m, m, m, m);
211        }
212        if (_showBorder) {
213            _parent.setBorder(new CompoundBorder(outlineBorder, borderMargin));
214        }
215        _parent.updateSize();
216    }
217
218    public int getFixedWidth() {
219        return fixedWidth;
220    }
221
222    public void setFixedWidth(int w) {
223        fixedWidth = w;
224        if (log.isDebugEnabled()) {
225            log.debug("setFixedWidth()={}", getFixedWidth());
226        }
227        _parent.updateSize();
228    }
229
230    public int getFixedHeight() {
231        return fixedHeight;
232    }
233
234    public void setFixedHeight(int h) {
235        fixedHeight = h;
236        log.debug("setFixedHeight()={}", getFixedHeight());
237        _parent.updateSize();
238    }
239
240    public void setFixedSize(int w, int h) {
241        fixedWidth = w;
242        fixedHeight = h;
243        log.debug("setFixedSize()=({},{})", getFixedWidth(), getFixedHeight());
244        _parent.updateSize();
245    }
246
247    public void setBorderSize(int border) {
248        borderSize = border;
249
250        if (borderColor != null) {
251            outlineBorder = new LineBorder(borderColor, borderSize);
252            _parent.setBorder(new CompoundBorder(outlineBorder, borderMargin));
253            //setHorizontalAlignment(CENTRE);
254        }
255        _parent.updateSize();
256    }
257
258    private boolean _showBorder = true;
259
260    public void setBorder(boolean set) {
261        _showBorder = set;
262        if (set) {
263            if (borderColor != null ) {
264                outlineBorder = new LineBorder(borderColor, borderSize);
265                _parent.setBorder(new CompoundBorder(outlineBorder, borderMargin));
266            }
267        } else {
268            _parent.setBorder(null);
269        }
270    }
271
272    public int getBorderSize() {
273        return borderSize;
274    }
275
276    public void setBorderColor(Color border) {
277        borderColor = border;
278        if (borderColor != null && _showBorder) {
279            outlineBorder = new LineBorder(borderColor, borderSize);
280            _parent.setBorder(new CompoundBorder(outlineBorder, borderMargin));
281        }
282        if (!_suppressRecentColor) {
283            JmriColorChooser.addRecentColor(border);
284        }
285    }
286
287    public Color getBorderColor() {
288        if (borderColor == null) {
289            borderColor = _parent.getBackground();
290        }
291        return borderColor;
292    }
293
294    public void setForeground(Color c) {
295        _textComponent.setForeground(c);
296        _parent.updateSize();
297        if (!_suppressRecentColor) {
298            JmriColorChooser.addRecentColor(c);
299        }
300    }
301
302    public Color getForeground() {
303        return _textComponent.getForeground();
304    }
305
306    public void setBackgroundColor(Color color) {
307        if (color == null || color.getAlpha() == 0) {
308            setHasBackground(false);
309            _textComponent.setBackground(color); // retain the passed color
310                                                 // which may not be null
311        } else {
312            setHasBackground(true);
313            _textComponent.setBackground(color);
314            _parent.setBackground(color);
315            _parent.setOpaque(true);
316            if (!_suppressRecentColor) {
317                JmriColorChooser.addRecentColor(color);
318            }
319        }
320        if (hasBackground()) {
321            setMargin(margin);  //This rebuilds margin and sets it colour.
322        }
323        _parent.updateSize();
324    }
325
326    public void setSuppressRecentColor(boolean b) {
327        _suppressRecentColor = b;
328    }
329
330    public void setHasBackground(boolean set) {
331        _hasBackground = set;
332        if (_textComponent instanceof PositionableJPanel) {
333            _textComponent.setOpaque(_hasBackground);
334        }
335        if (!_hasBackground) {
336            _parent.setOpaque(false);
337            _textComponent.setOpaque(false);
338        }
339    }
340
341    public boolean hasBackground() {
342        return _hasBackground;
343    }
344
345    public Color getBackground() {
346        Color c = _textComponent.getBackground();
347        if (c==null) {
348            c = Color.WHITE;
349        }
350        if (!_hasBackground) {
351            // make sure the alpha value is set to 0
352            c = jmri.util.ColorUtil.setAlpha(c,0);
353        }
354        return c;
355    }
356
357    protected JMenu makeFontMenu() {
358        JMenu fontMenu = new JMenu("Font"); // create font menu
359        //fontMenu.setMnemonic('n'); // set mnemonic to n
360
361        // get the current font family name
362        String defaultFontFamilyName = _textComponent.getFont().getFamily();
363
364        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
365        String[] fontFamilyNames = ge.getAvailableFontFamilyNames();
366
367        // create radiobutton menu items for font names
368        ButtonGroup fontButtonGroup = new ButtonGroup(); // manages font names
369
370        // create Font radio button menu items
371        for (String fontFamilyName : fontFamilyNames) {
372            // create its menu item
373            JCheckBoxMenuItem fontMenuItem = new JCheckBoxMenuItem(fontFamilyName);
374            Font menuFont = fontMenuItem.getFont();
375            menuFont = new Font(fontFamilyName, menuFont.getStyle(), menuFont.getSize());
376            fontMenuItem.setFont(menuFont);
377
378            // set its action listener
379            fontMenuItem.addActionListener((ActionEvent e) -> {
380                Font oldFont = _textComponent.getFont();
381                Font newFont = new Font(fontFamilyName, oldFont.getStyle(), oldFont.getSize());
382                if (!oldFont.equals(newFont)) {
383                    setFont(newFont);
384                }
385            });
386
387            // add to button group
388            fontButtonGroup.add(fontMenuItem);
389            // set (de)selected
390            fontMenuItem.setSelected(defaultFontFamilyName.equals(fontFamilyName));
391            // add to font menu
392            fontMenu.add(fontMenuItem);
393        }
394
395        MenuScroller.setScrollerFor(fontMenu, 36);
396
397        return fontMenu;
398    }
399
400    protected JMenu makeFontSizeMenu() {
401        JMenu sizeMenu = new JMenu("Font Size");
402        ButtonGroup buttonGrp = new ButtonGroup();
403        addFontSizeMenuEntry(sizeMenu, buttonGrp, 6);
404        addFontSizeMenuEntry(sizeMenu, buttonGrp, 8);
405        addFontSizeMenuEntry(sizeMenu, buttonGrp, 10);
406        addFontSizeMenuEntry(sizeMenu, buttonGrp, 11);
407        addFontSizeMenuEntry(sizeMenu, buttonGrp, 12);
408        addFontSizeMenuEntry(sizeMenu, buttonGrp, 14);
409        addFontSizeMenuEntry(sizeMenu, buttonGrp, 16);
410        addFontSizeMenuEntry(sizeMenu, buttonGrp, 18);
411        addFontSizeMenuEntry(sizeMenu, buttonGrp, 20);
412        addFontSizeMenuEntry(sizeMenu, buttonGrp, 24);
413        addFontSizeMenuEntry(sizeMenu, buttonGrp, 28);
414        addFontSizeMenuEntry(sizeMenu, buttonGrp, 32);
415        addFontSizeMenuEntry(sizeMenu, buttonGrp, 36);
416        return sizeMenu;
417    }
418
419    void addFontSizeMenuEntry(JMenu menu, ButtonGroup fontButtonGroup, final int size) {
420        JRadioButtonMenuItem r = new JRadioButtonMenuItem("" + size);
421        r.addActionListener((ActionEvent e) -> setFontSize(size));
422        fontButtonGroup.add(r);
423        r.setSelected(_textComponent.getFont().getSize() == size);
424        menu.add(r);
425    }
426
427    public void setFont(Font font) {
428        Font oldFont = _textComponent.getFont();
429        Font newFont = new Font(font.getFamily(), oldFont.getStyle(), oldFont.getSize());
430        if (!oldFont.equals(newFont)) {
431            _textComponent.setFont(newFont);
432            _parent.updateSize();
433            _parent.getEditor().setAttributes(_self, _parent);
434        }
435    }
436
437    public Font getFont() {
438        return _textComponent.getFont();
439    }
440
441    public void setFontSize(float newSize) {
442        _textComponent.setFont(_textComponent.getFont().deriveFont(newSize));
443        _parent.updateSize();
444        ///_parent.getEditor().setAttributes(_self, _parent);
445    }
446
447    public int getFontSize() {
448        return _textComponent.getFont().getSize();
449    }
450
451    void setItalic() {
452        log.debug("When style item selected italic state is {}", italic.isSelected());
453        if (italic.isSelected()) {
454            setFontStyle(Font.ITALIC, 0);
455        } else {
456            setFontStyle(0, Font.ITALIC);
457        }
458    }
459
460    void setBold() {
461        log.debug("When style item selected bold state is {}", bold.isSelected());
462        if (bold.isSelected()) {
463            setFontStyle(Font.BOLD, 0);
464        } else {
465            setFontStyle(0, Font.BOLD);
466        }
467    }
468
469    protected JMenu makeFontStyleMenu() {
470        JMenu styleMenu = new JMenu(Bundle.getMessage("FontStyle"));
471        styleMenu.add(italic = newStyleMenuItem(new AbstractAction(Bundle.getMessage("Italic")) {
472            @Override
473            public void actionPerformed(ActionEvent e) {
474                if (log.isDebugEnabled()) { // Avoid action lookup unless needed
475                    log.debug("When style item selected {} italic state is {}", getValue(NAME), italic.isSelected());
476                }
477                if (italic.isSelected()) {
478                    setFontStyle(Font.ITALIC, 0);
479                } else {
480                    setFontStyle(0, Font.ITALIC);
481                }
482            }
483        }, Font.ITALIC));
484
485        styleMenu.add(bold = newStyleMenuItem(new AbstractAction(Bundle.getMessage("Bold")) {
486            @Override
487            public void actionPerformed(ActionEvent e) {
488                if (log.isDebugEnabled()) { // Avoid action lookup unless needed
489                    log.debug("When style item selected {} bold state is {}",
490                            getValue(NAME), bold.isSelected());
491                }
492                if (bold.isSelected()) {
493                    setFontStyle(Font.BOLD, 0);
494                } else {
495                    setFontStyle(0, Font.BOLD);
496                }
497            }
498        }, Font.BOLD));
499        return styleMenu;
500    }
501
502    public void setFontStyle(int style) {
503        _textComponent.setFont(_textComponent.getFont().deriveFont(style));
504        _parent.updateSize();
505    }
506
507    public void setFontStyle(int addStyle, int dropStyle) {
508        int styleValue = (getFontStyle() & ~dropStyle) | addStyle;
509        log.debug("setFontStyle: addStyle={}, dropStyle={}, net styleValue is {}", addStyle, dropStyle, styleValue);
510        if (bold != null) {
511            bold.setSelected((styleValue & Font.BOLD) != 0);
512        }
513        if (italic != null) {
514            italic.setSelected((styleValue & Font.ITALIC) != 0);
515        }
516        _textComponent.setFont(_textComponent.getFont().deriveFont(styleValue));
517
518        //setSize(getPreferredSize().width, getPreferredSize().height);
519        _parent.updateSize();
520    }
521
522    public int getFontStyle() {
523        return _textComponent.getFont().getStyle();
524    }
525
526    protected JMenuItem newStyleMenuItem(AbstractAction a, int mask) {
527        // next two lines needed because JCheckBoxMenuItem(AbstractAction) not in 1.1.8
528        JCheckBoxMenuItem c = new JCheckBoxMenuItem((String) a.getValue(AbstractAction.NAME));
529        c.addActionListener(a);
530        if (log.isDebugEnabled()) { // Avoid action lookup unless needed
531            log.debug("When creating style item {} mask was {} state was {}",
532                     a.getValue(AbstractAction.NAME), mask, getFontStyle());
533        }
534        if ((mask & getFontStyle()) == mask) {
535            c.setSelected(true);
536        }
537        return c;
538    }
539
540    public void copyItem(JPopupMenu popup) {
541        JMenuItem edit = new JMenuItem("Copy");
542        edit.addActionListener((ActionEvent e) -> _parent.getEditor().copyItem(_parent));
543        popup.add(edit);
544    }
545
546    /*
547     * ************* Justification ***********************
548     */
549    public void setTextJustificationMenu(JPopupMenu popup) {
550        JMenu justMenu = new JMenu(Bundle.getMessage("Justification"));
551        addJustificationMenuEntry(justMenu, LEFT);
552        addJustificationMenuEntry(justMenu, RIGHT);
553        addJustificationMenuEntry(justMenu, CENTRE);
554        popup.add(justMenu);
555    }
556
557    static public final int LEFT = 0x00;
558    static public final int RIGHT = 0x02;
559    static public final int CENTRE = 0x04;
560
561    private int justification = CENTRE; //Default is always Centre
562
563    public void setJustification(int just) {
564        log.debug("setJustification: justification={}", just);
565        justification = just;
566        setHorizontalAlignment(justification);
567        _parent.updateSize();
568    }
569
570    public void setJustification(String just) {
571        log.debug("setJustification: justification ={}", just);
572        switch (just) {
573            case "right":
574                justification = RIGHT;
575                break;
576            case "center":
577            case "centre":
578                // allow US or UK spellings
579                justification = CENTRE;
580                break;
581            default:
582                justification = LEFT;
583                break;
584        }
585        setHorizontalAlignment(justification);
586        _parent.updateSize();
587    }
588
589    public int getJustification() {
590        log.debug("getJustification: justification ={}", justification);
591        return justification;
592    }
593
594    void addJustificationMenuEntry(JMenu menu, final int just) {
595        ButtonGroup justButtonGroup = new ButtonGroup();
596        JRadioButtonMenuItem r;
597        switch (just) {
598            case RIGHT:
599                r = new JRadioButtonMenuItem(Bundle.getMessage("right"));
600                break;
601            case CENTRE:
602                r = new JRadioButtonMenuItem(Bundle.getMessage("center"));
603                break;
604            case LEFT:
605            default:
606                r = new JRadioButtonMenuItem(Bundle.getMessage("left"));
607        }
608        r.addActionListener((ActionEvent e) -> setJustification(just) //final int justification = just;
609        );
610        justButtonGroup.add(r);
611        if (justification == just) {
612            r.setSelected(true);
613        } else {
614            r.setSelected(false);
615        }
616        menu.add(r);
617    }
618
619    public void setHorizontalAlignment(int alignment) {
620        if (_textType == LABEL) {
621            switch (alignment) {
622                case LEFT:
623                    ((JLabel) _textComponent).setHorizontalAlignment(JLabel.LEFT);
624                    break;
625                case RIGHT:
626                    ((JLabel) _textComponent).setHorizontalAlignment(JLabel.RIGHT);
627                    break;
628                case CENTRE:
629                default:
630                    ((JLabel) _textComponent).setHorizontalAlignment(JLabel.CENTER);
631            }
632        } else if (_textType == TEXTFIELD) {
633            switch (alignment) {
634                case LEFT:
635                    ((JTextField) _textComponent).setHorizontalAlignment(JTextField.LEFT);
636                    break;
637                case RIGHT:
638                    ((JTextField) _textComponent).setHorizontalAlignment(JTextField.RIGHT);
639                    break;
640                case CENTRE:
641                default:
642                    ((JTextField) _textComponent).setHorizontalAlignment(JTextField.CENTER);
643            }
644        }
645    }
646
647    public String getText() {
648        if (_textType == LABEL) {
649            return ((JLabel) _textComponent).getText();
650        } else if (_textType == TEXTFIELD) {
651            return ((JTextField) _textComponent).getText();
652        }
653        return null;
654    }
655
656    public final static int HORIZONTAL = 0x00;
657    public final static int VERTICAL_UP = 0x01;
658    public final static int VERTICAL_DOWN = 0x02;
659
660    private int orientation = HORIZONTAL;
661
662    public int getOrientation() {
663        return orientation;
664    }
665
666    public void setOrientation(int ori) {
667        orientation = ori;
668        _parent.updateSize();
669    }
670
671    public void setOrientation(String ori) {
672        switch (ori) {
673            case "vertical_up":
674                setOrientation(VERTICAL_UP);
675                break;
676            case "vertical_down":
677                setOrientation(VERTICAL_DOWN);
678                break;
679            default:
680                setOrientation(HORIZONTAL);
681                break;
682        }
683    }
684
685    public void setTextOrientationMenu(JPopupMenu popup) {
686        JMenu oriMenu = new JMenu(Bundle.getMessage("Orientation"));
687        addOrientationMenuEntry(oriMenu, HORIZONTAL);
688        addOrientationMenuEntry(oriMenu, VERTICAL_UP);
689        addOrientationMenuEntry(oriMenu, VERTICAL_DOWN);
690        popup.add(oriMenu);
691    }
692
693    void addOrientationMenuEntry(JMenu menu, final int ori) {
694        ButtonGroup justButtonGroup = new ButtonGroup();
695        JRadioButtonMenuItem r;
696        switch (ori) {
697            default:
698            case HORIZONTAL:
699                r = new JRadioButtonMenuItem("Horizontal");
700                break;
701            case VERTICAL_UP:
702                r = new JRadioButtonMenuItem("Vertical Up");
703                break;
704            case VERTICAL_DOWN:
705                r = new JRadioButtonMenuItem("Vertical Down");
706                break;
707        }
708        r.addActionListener((ActionEvent e) -> setOrientation(ori));
709        justButtonGroup.add(r);
710        if (orientation == ori) {
711            r.setSelected(true);
712        } else {
713            r.setSelected(false);
714        }
715        menu.add(r);
716    }
717
718    ArrayList<JMenuItem> editAdditionalMenu = new ArrayList<>(0);
719    ArrayList<JMenuItem> viewAdditionalMenu = new ArrayList<>(0);
720
721    /**
722     * Add a menu item to be displayed when the popup menu is called for when in
723     * edit mode.
724     *
725     * @param menu the item to add
726     */
727    public void addEditPopUpMenu(JMenuItem menu) {
728        if (!editAdditionalMenu.contains(menu)) {
729            editAdditionalMenu.add(menu);
730        }
731    }
732
733    /**
734     * Add a menu item to be displayed when the popup menu is called for when in
735     * view mode.
736     *
737     * @param menu menu item or submenu to add
738     */
739    public void addViewPopUpMenu(JMenuItem menu) {
740        if (!viewAdditionalMenu.contains(menu)) {
741            viewAdditionalMenu.add(menu);
742        }
743    }
744
745    /**
746     * Add the menu items to the edit popup menu
747     *
748     * @param popup the menu to add items to
749     */
750    public void setAdditionalEditPopUpMenu(JPopupMenu popup) {
751        if (editAdditionalMenu.isEmpty()) {
752            return;
753        }
754        popup.addSeparator();
755        editAdditionalMenu.forEach(popup::add);
756    }
757
758    /**
759     * Add the menu items to the view popup menu.
760     *
761     * @param popup the menu to add items to
762     */
763    public void setAdditionalViewPopUpMenu(JPopupMenu popup) {
764        if (viewAdditionalMenu.isEmpty()) {
765            return;
766        }
767        viewAdditionalMenu.forEach(popup::add);
768    }
769
770    private final static Logger log = LoggerFactory.getLogger(PositionablePopupUtil.class);
771}