001package jmri.util.startup;
002
003import java.awt.Component;
004import java.lang.reflect.InvocationTargetException;
005import java.util.Optional;
006
007import javax.swing.Action;
008import javax.swing.BoxLayout;
009import javax.swing.JComboBox;
010import javax.swing.JLabel;
011import javax.swing.JList;
012import javax.swing.JPanel;
013import javax.swing.JScrollPane;
014import javax.swing.SwingConstants;
015import javax.swing.event.ListSelectionEvent;
016
017import jmri.InstanceManager;
018import jmri.SystemConnectionMemo;
019import jmri.jmrix.swing.SystemConnectionAction;
020import jmri.util.ConnectionNameFromSystemName;
021import jmri.util.swing.JmriJOptionPane;
022
023/**
024 * Provide an abstract StartupModelFactory with common methods for factories
025 * that manipulate models that extend {@link jmri.util.startup.AbstractActionModel}.
026 *
027 * @author Randall Wood
028 */
029public abstract class AbstractActionModelFactory implements StartupModelFactory {
030
031    @Override
032    public String getDescription() {
033        return Bundle.getMessage(this.getModelClass().getCanonicalName());
034    }
035
036    @Override
037    public String getActionText() {
038        return Bundle.getMessage("EditableStartupAction", this.getDescription());
039    }
040
041    /**
042     * Get the message text for the dialog created in
043     * {@link #editModel(StartupModel, java.awt.Component)}.
044     *
045     * @return the message text
046     */
047    public abstract String getEditModelMessage();
048
049    @Override
050    public void editModel(StartupModel model, Component parent) {
051        if (model instanceof AbstractActionModel && this.getModelClass().isInstance(model)) {
052            JList<String> actions = new JList<>(StartupActionModelUtil.getDefault().getNames());
053            JComboBox<String> connections = new JComboBox<>();
054            JPanel message = this.getDialogMessage(actions, connections);
055            actions.setSelectedValue(model.getName(), true);
056            String userName = ConnectionNameFromSystemName.getConnectionName(((AbstractActionModel) model).getSystemPrefix());
057            if (userName == null) {
058                userName = ""; // make not null to simplify following conditionals
059            }
060            if (!userName.isEmpty()) {
061                connections.setSelectedItem(userName);
062            }
063            int result = JmriJOptionPane.showConfirmDialog(parent,
064                    message,
065                    this.getDescription(),
066                    JmriJOptionPane.OK_CANCEL_OPTION,
067                    JmriJOptionPane.PLAIN_MESSAGE);
068            if (result == JmriJOptionPane.OK_OPTION) {
069                String name = actions.getSelectedValue();
070                Optional<StartupActionsManager> manager = InstanceManager.getOptionalDefault(StartupActionsManager.class);
071                if (!name.equals(model.getName())) {
072                    model.setName(name);
073                    manager.ifPresent(StartupActionsManager::setRestartRequired);
074                }
075                if ((userName.isEmpty() && connections.getSelectedItem() != null)
076                        || !userName.equals(connections.getSelectedItem())) {
077                    ((AbstractActionModel) model).setSystemPrefix(ConnectionNameFromSystemName.getPrefixFromName((String) connections.getSelectedItem()));
078                    manager.ifPresent(StartupActionsManager::setRestartRequired);
079                }
080            }
081        }
082    }
083
084    @Override
085    public void initialize() {
086        // nothing to do
087    }
088
089    private JPanel getDialogMessage(JList<String> actions, JComboBox<String> connections) {
090        JLabel connectionsLabel = new JLabel(Bundle.getMessage("AbstractActionModelFactory.getDialogMessage.connectionsLabel", SwingConstants.LEADING)); // NOI18N
091        actions.getSelectionModel().addListSelectionListener((ListSelectionEvent e) -> {
092            if (!e.getValueIsAdjusting()) {
093                connections.removeAllItems();
094                connections.setEnabled(false);
095                connectionsLabel.setEnabled(false);
096                String name = actions.getSelectedValue();
097                if (name != null) {
098                    String className = StartupActionModelUtil.getDefault().getClassName(name);
099                    if (className != null && StartupActionModelUtil.getDefault().isSystemConnectionAction(className)) {
100                        try {
101                            Action action = (Action) Class.forName(className).getDeclaredConstructor().newInstance();
102                            if (action instanceof SystemConnectionAction) {
103                                ((SystemConnectionAction<?>) action).getSystemConnectionMemoClasses().forEach(clazz
104                                        -> InstanceManager.getList(SystemConnectionMemo.class).stream()
105                                                .filter(memo -> clazz.isAssignableFrom(memo.getClass()))
106                                                .forEach(memo -> {
107                                                    connections.addItem(memo.getUserName());
108                                                    connections.setEnabled(true);
109                                                    connectionsLabel.setEnabled(true);
110                                                }));
111                            }
112                        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException ex) {
113                            log.error("Unable to create Action", ex);
114                        }
115                    }
116                }
117            }
118        });
119        connections.setEnabled(false);
120        connectionsLabel.setEnabled(false);
121        JPanel panel = new JPanel();
122        panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
123        panel.add(new JLabel(this.getEditModelMessage(), SwingConstants.LEADING));
124        panel.add(new JScrollPane(actions));
125        panel.add(connectionsLabel);
126        panel.add(connections);
127        return panel;
128    }
129
130    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(AbstractActionModelFactory.class);
131
132}