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