001package jmri.jmrix.dccpp.swing.messages;
002
003import java.awt.Frame;
004
005import javax.annotation.CheckForNull;
006import javax.swing.JMenuItem;
007import javax.swing.JPopupMenu;
008
009import jmri.InstanceManager;
010import jmri.InvokeOnGuiThread;
011import jmri.UserPreferencesManager;
012import jmri.configurexml.JmriConfigureXmlException;
013import jmri.jmrix.dccpp.DCCppSystemConnectionMemo;
014import jmri.jmrix.dccpp.swing.messages.configurexml.MessagesConfigurationXml;
015import jmri.util.JmriJFrame;
016import jmri.util.swing.*;
017
018import org.jdom2.Element;
019
020/** Window showing EXRAIL MESSAGE() broadcasts, one per DCC-EX connection. */
021public class MessagesFrame extends JmriJFrame {
022
023    private final DCCppSystemConnectionMemo _memo;
024    private final MessagesPanel _messagesPanel;
025    private JPopupMenu popup;
026
027    private static String getElementName(DCCppSystemConnectionMemo memo) {
028        return "dccex_messages_config" + "___" + memo.getSystemPrefix();
029    }
030
031    public MessagesFrame(DCCppSystemConnectionMemo memo) {
032        // save window position but not size, include prefix in title for multiple connections
033        super(false, true, Bundle.getMessage("MessagesFrameTitle") + " (" + memo.getSystemPrefix() + ")");
034        _memo = memo;
035        _messagesPanel = new MessagesPanel(this, false);
036        _messagesPanel.setMemo(memo);
037    }
038
039    public DCCppSystemConnectionMemo getMemo() {
040        return _memo;
041    }
042
043    public MessagesPanel getMessagesPanel() {
044        return _messagesPanel;
045    }
046
047    /** Find the open Messages window for this connection, or null. */
048    @CheckForNull
049    public static MessagesFrame findFrame(DCCppSystemConnectionMemo memo) {
050        for (MessagesFrame f : JmriJFrame.getFrameList(MessagesFrame.class)) {
051            if (f.getMemo() == memo) {
052                return f;
053            }
054        }
055        return null;
056    }
057
058    /** Open (or bring forward) the Messages window; initialMessage is only added to a newly created window. */
059    @InvokeOnGuiThread
060    public static MessagesFrame showFrame(DCCppSystemConnectionMemo memo, @CheckForNull String initialMessage) {
061        MessagesFrame frame = findFrame(memo);
062        if (frame == null) {
063            frame = new MessagesFrame(memo);
064            frame.initComponents();
065            if (initialMessage != null) {
066                frame.getMessagesPanel().addMessage(initialMessage);
067            }
068            frame.setVisible(true);
069        }
070        frame.setExtendedState(Frame.NORMAL);
071        frame.toFront();
072        return frame;
073    }
074
075    /** Whether the window should open itself when a message arrives; true unless the user turned it off. */
076    public static boolean isAutoOpen(DCCppSystemConnectionMemo memo) {
077        MessagesFrame frame = findFrame(memo);
078        if (frame != null) {
079            return frame.getMessagesPanel().isAutoOpen();
080        }
081        UserPreferencesManager p = InstanceManager.getNullableDefault(UserPreferencesManager.class);
082        if (p == null) {
083            return true;
084        }
085        Element e = p.loadElement(getElementName(memo));
086        if (e == null) {
087            return true;
088        }
089        Element config = e.getChild("dccex_messages_config");
090        String value = config != null ? config.getChildTextTrim("autoOpen") : null;
091        return value == null || "true".equals(value);
092    }
093
094    @Override
095    public void dispose() {
096        storeSettings();
097        _messagesPanel.dispose();
098        super.dispose();
099    }
100
101    private void storeSettings() {
102        InstanceManager.getOptionalDefault(UserPreferencesManager.class).ifPresent(p -> {
103            Element parent = new Element(getElementName(_memo), UserPreferencesManager.GENERIC_NAMESPACE);
104            parent.addContent(MessagesConfigurationXml.store(_messagesPanel));
105            p.storeElement(parent);
106        });
107    }
108
109    void editSettings() {
110        ConfigureMessages.editConfigureMessages(null, _messagesPanel, this::storeSettings);
111    }
112
113    /** {@inheritDoc} */
114    @Override
115    public void initComponents() {
116        super.initComponents();
117        _messagesPanel.initComponents();
118        add(_messagesPanel);
119
120        popup = new JPopupMenu();
121        JMenuItem editItem = new JMenuItem(Bundle.getMessage("EditMessages"));
122        editItem.addActionListener(evt -> editSettings());
123        popup.add(editItem);
124        JMenuItem clearItem = new JMenuItem(Bundle.getMessage("ClearMessages"));
125        clearItem.addActionListener(evt -> _messagesPanel.clearMessages());
126        popup.add(clearItem);
127
128        JmriMouseListener popupListener = new JmriMouseAdapter() {
129            @Override
130            public void mousePressed(JmriMouseEvent e) {
131                maybeShowPopup(e);
132            }
133
134            @Override
135            public void mouseReleased(JmriMouseEvent e) {
136                maybeShowPopup(e);
137            }
138
139            private void maybeShowPopup(JmriMouseEvent e) {
140                if (e.isPopupTrigger()) {
141                    popup.show(e.getComponent(), e.getX(), e.getY());
142                }
143            }
144        };
145        _messagesPanel.addMouseListener(JmriMouseListener.adapt(popupListener));
146
147        pack();
148
149        InstanceManager.getOptionalDefault(UserPreferencesManager.class).ifPresent(p -> {
150            Element e = p.loadElement(getElementName(_memo));
151            if (e != null) {
152                try {
153                    MessagesConfigurationXml.load(_messagesPanel, e, true);
154                } catch (JmriConfigureXmlException ex) {
155                    log.error("Unexpected exception during loading of settings", ex);
156                }
157            }
158        });
159    }
160
161    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(MessagesFrame.class);
162
163}