001package jmri.jmrix.openlcb.swing;
002
003import java.awt.*;
004import java.awt.datatransfer.*;
005import java.awt.event.*;
006
007import javax.swing.*;
008
009import jmri.util.swing.*;
010import jmri.jmrix.can.CanSystemConnectionMemo;
011import jmri.jmrix.openlcb.OlcbAddress;
012import jmri.jmrix.openlcb.OlcbEventNameStore;
013
014import org.openlcb.EventID;
015import org.openlcb.swing.EventIdTextField;
016
017/**
018 * This is an entry field for Event IDs that also 
019 * accepts event names
020 *
021 * @author Bob Jacobsen  (C) 2024
022 */
023public class NamedEventIdTextField extends OvertypeTextArea {
024        
025    public NamedEventIdTextField(CanSystemConnectionMemo memo) {
026        this(23, memo);  // heuristically-found default size
027    }
028
029    public NamedEventIdTextField(int size, CanSystemConnectionMemo memo) {
030        super(size);
031        this.memo = memo;
032        
033        // set up semi-automatic tool tip
034        addMouseListener(JmriMouseListener.adapt(new JmriMouseListener() {
035            @Override
036            public void mouseEntered(JmriMouseEvent arg0) {
037                // Generate dynamic tooltip text here
038                setToolTipText(makeToolTipText(getText()));
039            }
040
041            @Override public void mouseClicked(JmriMouseEvent e) {}
042            @Override public void mouseExited(JmriMouseEvent arg0) {}
043            @Override public void mousePressed(JmriMouseEvent arg0) {}
044            @Override public void mouseReleased(JmriMouseEvent arg0) {}
045        }));
046
047        // Add a focus listener to update the tooltip dynamically
048        addFocusListener(new FocusListener() {
049            @Override
050            public void focusGained(FocusEvent e) {
051                setToolTipText(makeToolTipText(getText()));
052            }
053
054            @Override public void focusLost(FocusEvent e) {}
055        });
056
057        var popup = EventIdTextField.createPopupMenu(this);
058        // add a custom copy operator to capture the numerical value
059        JMenuItem menuItem = new JMenuItem("Copy Numerical Event ID");
060        popup.add(menuItem);
061        var self = this;
062        menuItem.addActionListener(new ActionListener() {
063            @Override
064            public void actionPerformed(ActionEvent e) {
065                String s = new OlcbAddress(self.getText(), memo).toDottedString();
066                SwingUtilities.invokeLater(new Runnable() {
067                    @Override
068                    public void run() {
069                        self.selectAll();
070                    }
071                });
072                StringSelection eventToCopy = new StringSelection(s);
073                Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
074                clipboard.setContents(eventToCopy, new ClipboardOwner() {
075                    @Override
076                    public void lostOwnership(Clipboard clipboard, Transferable transferable) {
077                    }
078                });
079            }
080        });
081        // add a custom operator to set an event name
082        menuItem = new JMenuItem("Name This Event");
083        popup.add(menuItem);
084        menuItem.addActionListener(new ActionListener() {
085            @Override
086            public void actionPerformed(ActionEvent e) {
087                String name = JmriJOptionPane.showInputDialog(
088                    self,
089                    "Enter a Name for the Event ID",
090                    "" )        ;
091                   
092                if (name == null || name.isEmpty() ) return; // no new name entered
093                        
094                memo.get(OlcbEventNameStore.class).addMatch(getEventID(), name);
095                // and update the NEITF object to get name displayed
096                self.setText(name);
097                self.repaint();
098            }
099        });
100       
101        // and set the updated popup menu
102        this.setComponentPopupMenu(popup);
103    }
104
105    // Provide a placeholder display if the content is empty
106    @Override
107    protected void paintComponent(Graphics g) {
108        super.paintComponent(g);
109
110        // Draw the placeholder if the field is empty and not focused
111        if (getText().isEmpty() && !hasFocus()) {
112            Graphics2D g2d = (Graphics2D) g;
113            
114            // Enable anti-aliasing for smooth text rendering
115            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
116            
117            // Set the dim text color and match the current font
118            g2d.setColor(Color.LIGHT_GRAY); 
119            g2d.setFont(getFont());
120            
121            // Align placeholder horizontally with standard text padding
122            int padding = getInsets().left; 
123            
124            // Center the placeholder vertically within the text field
125            int textHeight = g2d.getFontMetrics().getAscent();
126            int height = getHeight();
127            int y = (height - textHeight) / 2 + textHeight;
128
129            g2d.drawString(placeholder, padding, y);
130        }
131    }
132
133    String placeholder = "Enter numeric event ID or event name";
134
135    public String getPlaceholder() {
136        return placeholder;
137    }
138    
139    
140    final CanSystemConnectionMemo memo;
141    
142    protected String makeToolTipText(String fieldText) {
143        var address = new OlcbAddress(fieldText, memo);
144        if (address.isFromName()) {
145            return fieldText+" is "+address.toDottedString();
146        }
147        return "Enter an event ID or event name";
148    }    
149    
150    public EventID getEventID() {
151        return new EventID(new OlcbAddress(getText(), memo).toDottedString());
152    }
153    
154    public String getEventIDAsDottedString() {
155        return new OlcbAddress(getText(), memo).toDottedString();
156    }
157    
158    // private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(NamedEventIdTextField.class);
159}