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                if (actions.getSelectedIndex() >= 0) { // checks for nothing selected
070                    String name = actions.getSelectedValue();
071                    Optional<StartupActionsManager> manager = InstanceManager.getOptionalDefault(StartupActionsManager.class);
072                    if (!name.equals(model.getName())) {
073                        model.setName(name);
074                        manager.ifPresent(StartupActionsManager::setRestartRequired);
075                    }
076                    if ((userName.isEmpty() && connections.getSelectedItem() != null)
077                            || !userName.equals(connections.getSelectedItem())) {
078                        ((AbstractActionModel) model).setSystemPrefix(ConnectionNameFromSystemName.getPrefixFromName((String) connections.getSelectedItem()));
079                        manager.ifPresent(StartupActionsManager::setRestartRequired);
080                    }
081                }
082            }
083        }
084    }
085
086    @Override
087    public void initialize() {
088        // nothing to do
089    }
090
091    private JPanel getDialogMessage(JList<String> actions, JComboBox<String> connections) {
092        JLabel connectionsLabel = new JLabel(Bundle.getMessage("AbstractActionModelFactory.getDialogMessage.connectionsLabel", SwingConstants.LEADING)); // NOI18N
093        actions.getSelectionModel().addListSelectionListener((ListSelectionEvent e) -> {
094            if (!e.getValueIsAdjusting()) {
095                connections.removeAllItems();
096                connections.setEnabled(false);
097                connectionsLabel.setEnabled(false);
098                String name = actions.getSelectedValue();
099                if (name != null) {
100                    String className = StartupActionModelUtil.getDefault().getClassName(name);
101                    if (className != null && StartupActionModelUtil.getDefault().isSystemConnectionAction(className)) {
102                        try {
103                            Action action = (Action) Class.forName(className).getDeclaredConstructor().newInstance();
104                            if (action instanceof SystemConnectionAction) {
105                                ((SystemConnectionAction<?>) action).getSystemConnectionMemoClasses().forEach(clazz
106                                        -> InstanceManager.getList(SystemConnectionMemo.class).stream()
107                                                .filter(memo -> clazz.isAssignableFrom(memo.getClass()))
108                                                .forEach(memo -> {
109                                                    connections.addItem(memo.getUserName());
110                                                    connections.setEnabled(true);
111                                                    connectionsLabel.setEnabled(true);
112                                                }));
113                            }
114                        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException ex) {
115                            log.error("Unable to create Action", ex);
116                        }
117                    }
118                }
119            }
120        });
121        connections.setEnabled(false);
122        connectionsLabel.setEnabled(false);
123        JPanel panel = new JPanel();
124        panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
125        panel.add(new JLabel(this.getEditModelMessage(), SwingConstants.LEADING));
126        panel.add(new JScrollPane(actions));
127        panel.add(connectionsLabel);
128        panel.add(connections);
129        return panel;
130    }
131
132    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(AbstractActionModelFactory.class);
133
134}