001package jmri.jmrit.logixng.swing;
002
003import java.util.*;
004
005import javax.annotation.CheckForNull;
006import javax.annotation.Nonnull;
007import javax.swing.*;
008
009import jmri.NamedBean;
010import jmri.NamedBean.BadSystemNameException;
011import jmri.NamedBean.BadUserNameException;
012import jmri.jmrit.logixng.*;
013
014/**
015 * The parent interface for configuring classes with Swing.
016 *
017 * @author Daniel Bergqvist Copyright 2018
018 */
019public interface SwingConfiguratorInterface extends Comparable<SwingConfiguratorInterface> {
020
021    /**
022     * Set the dialog of this SWI.
023     *
024     * @param dialog the dialog
025     */
026    public void setJDialog(JDialog dialog);
027
028    /**
029     * Set the dialog of this SWI.
030     *
031     * @return the dialog
032     */
033    public JDialog getJDialog();
034
035    /**
036     * Get the menu text for execute/evaluate.
037     * @return the menu text
038     */
039    public String getExecuteEvaluateMenuText();
040
041    /**
042     * Execute or evaluate an item that this object configures.
043     * @param object the object to execute or evaluate
044     */
045    public void executeEvaluate(@Nonnull Base object);
046
047    /**
048     * Get the manager that handles the beans for the new object.
049     * This is used for validation of the system name for the bean that this
050     * class creates.
051     *
052     * @return the manager
053     */
054    public BaseManager<? extends NamedBean> getManager();
055
056    /**
057     * Get a configuration panel when a new object is to be created and we don't
058     * have it yet.
059     * This method initializes the panel with an empty configuration.
060     *
061     * @param buttonPanel panel with the buttons
062     * @return a panel that configures this object
063     * @throws IllegalArgumentException if this class does not support the class
064     * with the name given in parameter 'className'
065     */
066    public JPanel getConfigPanel(@Nonnull JPanel buttonPanel) throws IllegalArgumentException;
067
068    /**
069     * Get a configuration panel for an object.
070     * This method initializes the panel with the configuration of the object.
071     *
072     * @param object the object for which to return a configuration panel
073     * @param buttonPanel panel with the buttons
074     * @return a panel that configures this object
075     * @throws IllegalArgumentException when needed
076     */
077    public JPanel getConfigPanel(@Nonnull Base object, @Nonnull JPanel buttonPanel) throws IllegalArgumentException;
078
079    /**
080     * Validate the form.
081     * <P>
082     * The parameter errorMessage is used to give the error message in case of
083     * an error. If there are errors, the error messages is added to the list
084     * errorMessage.
085     *
086     * @param errorMessages the error messages in case of an error
087     * @return true if data in the form is valid, false otherwise
088     */
089    public boolean validate(@Nonnull List<String> errorMessages);
090
091    /**
092     * Get an example of a system name
093     * @return the system name
094     */
095    public String getExampleSystemName();
096
097    /**
098     * Create a new system name.
099     * @return a new system name
100     */
101    public String getAutoSystemName();
102
103    /**
104     * Create a new object with the data entered.This method must also register the object in its manager.
105     *
106     * @param systemName system name
107     * @param userName user name
108     * @return a male socket for the new object
109     * @throws BadUserNameException when needed
110     * @throws BadSystemNameException when needed
111     */
112    @Nonnull
113    public MaleSocket createNewObject(@Nonnull String systemName, @CheckForNull String userName)
114            throws BadUserNameException, BadSystemNameException;
115
116    /**
117     * Updates the object with the data in the form.
118     *
119     * @param object the object to update
120     */
121    public void updateObject(@Nonnull Base object);
122
123    /**
124     * Returns the name of the class that this class configures.
125     *
126     * @return the name of the class this class configures.
127     */
128    @Override
129    public String toString();
130
131    /**
132     * Set default values for this dialog.
133     * This method is used by tests to be able to run validation without
134     * knowing which data that needs to be entered for the validation to pass.
135     */
136    public default void setDefaultValues() {
137        // Do nothing
138    }
139
140    /**
141     * Is the SWI ready to be closed?
142     * @return true if the SWI is ready to be closed, false otherwise.
143     */
144    public default boolean canClose() {
145        return true;
146    }
147
148    /**
149     * Dispose the panel and remove all the listeners that this class may have
150     * registered.
151     */
152    public void dispose();
153
154
155    /**
156     * Parses the message and creates a list of components there the given
157     * components are separated by JLabel components from the message.
158     * @param message the message to be parsed
159     * @param components the components
160     * @return the components separated with JLabel components
161     */
162    public static List<JComponent> parseMessage(String message, JComponent[] components) {
163        List<JComponent> componentsToReturn = new ArrayList<>();
164        StringBuilder sb = new StringBuilder();
165        boolean parseNumber = false;
166
167        for (int index=0; index < message.length(); index++) {
168            int character = message.codePointAt(index);
169
170            if (parseNumber) {
171                if (character == '}') {
172                    int number = Integer.parseInt(sb.toString());
173                    componentsToReturn.add(components[number]);
174                    sb = new StringBuilder();
175                    parseNumber = false;
176                } else if ((character >= '0') && (character <= '9')) {
177                    sb.appendCodePoint(character);
178                } else {
179                    throw new IllegalArgumentException(
180                            "left curly bracket must be followed by a digit but is followed by "
181                                    + Arrays.toString(Character.toChars(character)));
182                }
183            } else {
184                if (character == '{') {
185                    parseNumber = true;
186                    componentsToReturn.add(new JLabel(sb.toString()));
187                    sb = new StringBuilder();
188                } else {
189                    sb.appendCodePoint(character);
190                }
191            }
192        }
193
194        if (sb.length() > 0) componentsToReturn.add(new JLabel(sb.toString()));
195
196        return componentsToReturn;
197    }
198
199    /** {@inheritDoc} */
200    @Override
201    public default int compareTo(SwingConfiguratorInterface swi) {
202        return toString().compareTo(swi.toString());
203    }
204
205}