001/*============================================================================*
002 * WARNING      This class contains automatically modified code.      WARNING *
003 *                                                                            *
004 * The method initComponents() and the variable declarations between the      *
005 * "// Variables declaration - do not modify" and                             *
006 * "// End of variables declaration" comments will be overwritten if modified *
007 * by hand. Using the NetBeans IDE to edit this file is strongly recommended. *
008 *                                                                            *
009 * See http://jmri.org/help/en/html/doc/Technical/NetBeansGUIEditor.shtml for *
010 * more information.                                                          *
011 *============================================================================*/
012package jmri.profile;
013
014import java.awt.Cursor;
015import java.awt.Dialog;
016import java.awt.Dimension;
017import java.awt.Font;
018import java.awt.event.ActionEvent;
019import java.awt.event.ActionListener;
020import java.awt.event.FocusAdapter;
021import java.awt.event.FocusEvent;
022import java.awt.event.KeyAdapter;
023import java.awt.event.KeyEvent;
024import java.io.File;
025import java.io.IOException;
026import java.util.ResourceBundle;
027
028import javax.swing.GroupLayout;
029import javax.swing.JButton;
030import javax.swing.JFileChooser;
031import javax.swing.JLabel;
032import javax.swing.JSeparator;
033import javax.swing.JTextField;
034import javax.swing.LayoutStyle;
035import javax.swing.WindowConstants;
036import javax.swing.event.DocumentEvent;
037import javax.swing.event.DocumentListener;
038
039import jmri.util.FileUtil;
040import jmri.util.swing.JmriJOptionPane;
041
042/**
043 * Add a new {@link Profile} to JMRI.
044 *
045 * @author Randall Wood
046 */
047public class AddProfileDialog extends javax.swing.JDialog {
048
049    private String profileId;
050    private boolean setNextProfile = false;
051    private Profile source = null;
052
053    public AddProfileDialog(java.awt.Frame parent, boolean modal, boolean setNextProfile) {
054        super(parent, modal);
055        this.setNextProfile = setNextProfile;
056        initComponents();
057    }
058
059    AddProfileDialog(Dialog parent, boolean modal, boolean setNextProfile) {
060        super(parent, modal);
061        this.setNextProfile = setNextProfile;
062        initComponents();
063    }
064
065    /**
066     * This method is called from within the constructor to initialize the form.
067     * WARNING: Do NOT modify this code. The content of this method is always
068     * regenerated by the Form Editor.
069     */
070    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
071    private void initComponents() {
072
073        lblProfileNameAndLocation = new JLabel();
074        jSeparator2 = new JSeparator();
075        profileName = new JTextField();
076        lblProfileName = new JLabel();
077        lblProfileLocation = new JLabel();
078        profileLocation = new JTextField();
079        profileFolder = new JTextField();
080        btnBrowse = new JButton();
081        lblProfileFolder = new JLabel();
082        jSeparator1 = new JSeparator();
083        btnCancel = new JButton();
084        btnOk = new JButton();
085
086        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
087        ResourceBundle bundle = ResourceBundle.getBundle("jmri/profile/Bundle"); // NOI18N
088        setTitle(bundle.getString("AddProfileDialog.title")); // NOI18N
089        setMinimumSize(new Dimension(413, 239));
090
091        lblProfileNameAndLocation.setFont(lblProfileNameAndLocation.getFont().deriveFont(lblProfileNameAndLocation.getFont().getStyle() | Font.BOLD));
092        lblProfileNameAndLocation.setText(bundle.getString("AddProfileDialog.lblProfileNameAndLocation.text")); // NOI18N
093
094        profileName.setText("");
095        profileName.getDocument().addDocumentListener(new DocumentListener() {
096            @Override
097            public void changedUpdate(DocumentEvent e) {
098                profileNameActionPerformed(null);
099            }
100            @Override
101            public void insertUpdate(DocumentEvent e) {
102                profileNameActionPerformed(null);
103            }
104            @Override
105            public void removeUpdate(DocumentEvent e) {
106                profileNameActionPerformed(null);
107            }
108        });
109        profileName.addFocusListener(new FocusAdapter() {
110            @Override
111            public void focusLost(FocusEvent evt) {
112                profileNameFocusLost(evt);
113            }
114        });
115        profileName.addActionListener(new ActionListener() {
116            @Override
117            public void actionPerformed(ActionEvent evt) {
118                profileNameActionPerformed(evt);
119            }
120        });
121        profileName.addKeyListener(new KeyAdapter() {
122            @Override
123            public void keyTyped(KeyEvent evt) {
124                profileNameKeyTyped(evt);
125            }
126        });
127
128        lblProfileName.setText(bundle.getString("AddProfileDialog.lblProfileName.text")); // NOI18N
129
130        lblProfileLocation.setText(bundle.getString("AddProfileDialog.lblProfileLocation.text")); // NOI18N
131
132        profileLocation.setText(ProfileManager.getDefault().getDefaultSearchPath().getPath());
133        profileLocation.setMinimumSize(new Dimension(14, 128));
134        profileLocation.addFocusListener(new FocusAdapter() {
135            @Override
136            public void focusLost(FocusEvent evt) {
137                profileLocationFocusLost(evt);
138            }
139        });
140        profileLocation.addActionListener(new ActionListener() {
141            @Override
142            public void actionPerformed(ActionEvent evt) {
143                profileLocationActionPerformed(evt);
144            }
145        });
146        profileLocation.addKeyListener(new KeyAdapter() {
147            @Override
148            public void keyTyped(KeyEvent evt) {
149                profileLocationKeyTyped(evt);
150            }
151        });
152
153        profileFolder.setEditable(false);
154        profileFolder.setText(ProfileManager.getDefault().getDefaultSearchPath().getPath());
155        profileFolder.setEnabled(false);
156        profileFolder.addActionListener(new ActionListener() {
157            @Override
158            public void actionPerformed(ActionEvent evt) {
159                profileFolderActionPerformed(evt);
160            }
161        });
162
163        btnBrowse.setText(bundle.getString("AddProfileDialog.btnBrowse.text")); // NOI18N
164        btnBrowse.addActionListener(new ActionListener() {
165            @Override
166            public void actionPerformed(ActionEvent evt) {
167                btnBrowseActionPerformed(evt);
168            }
169        });
170
171        lblProfileFolder.setText(bundle.getString("AddProfileDialog.lblProfileFolder.text")); // NOI18N
172
173        btnCancel.setText(bundle.getString("AddProfileDialog.btnCancel.text")); // NOI18N
174        btnCancel.addActionListener(new ActionListener() {
175            @Override
176            public void actionPerformed(ActionEvent evt) {
177                btnCancelActionPerformed(evt);
178            }
179        });
180
181        btnOk.setText(bundle.getString("AddProfileDialog.btnOk.text")); // NOI18N
182        btnOk.addActionListener(new ActionListener() {
183            @Override
184            public void actionPerformed(ActionEvent evt) {
185                btnOkActionPerformed(evt);
186            }
187        });
188
189        GroupLayout layout = new GroupLayout(getContentPane());
190        getContentPane().setLayout(layout);
191        layout.setHorizontalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
192            .addGroup(layout.createSequentialGroup()
193                .addContainerGap()
194                .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
195                    .addComponent(jSeparator2)
196                    .addGroup(layout.createSequentialGroup()
197                        .addGap(6, 6, 6)
198                        .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
199                            .addGroup(layout.createSequentialGroup()
200                                .addComponent(lblProfileName)
201                                .addGap(24, 24, 24)
202                                .addComponent(profileName, GroupLayout.DEFAULT_SIZE, 185, Short.MAX_VALUE))
203                            .addGroup(layout.createSequentialGroup()
204                                .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
205                                    .addComponent(lblProfileLocation)
206                                    .addComponent(lblProfileFolder))
207                                .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
208                                .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
209                                    .addComponent(profileFolder)
210                                    .addComponent(profileLocation, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
211                        .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
212                        .addComponent(btnBrowse))
213                    .addGroup(layout.createSequentialGroup()
214                        .addComponent(lblProfileNameAndLocation)
215                        .addGap(0, 0, Short.MAX_VALUE))
216                    .addComponent(jSeparator1)
217                    .addGroup(GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
218                        .addGap(0, 0, Short.MAX_VALUE)
219                        .addComponent(btnOk)
220                        .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
221                        .addComponent(btnCancel)))
222                .addContainerGap())
223        );
224        layout.setVerticalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
225            .addGroup(layout.createSequentialGroup()
226                .addContainerGap()
227                .addComponent(lblProfileNameAndLocation)
228                .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
229                .addComponent(jSeparator2, GroupLayout.PREFERRED_SIZE, 10, GroupLayout.PREFERRED_SIZE)
230                .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
231                .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
232                    .addComponent(profileName, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
233                    .addComponent(lblProfileName))
234                .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
235                .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
236                    .addComponent(profileLocation, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
237                    .addComponent(btnBrowse)
238                    .addComponent(lblProfileLocation))
239                .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
240                .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
241                    .addComponent(profileFolder, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
242                    .addComponent(lblProfileFolder))
243                .addGap(18, 18, 18)
244                .addComponent(jSeparator1, GroupLayout.PREFERRED_SIZE, 10, GroupLayout.PREFERRED_SIZE)
245                .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
246                .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
247                    .addComponent(btnCancel)
248                    .addComponent(btnOk))
249                .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
250        );
251
252        pack();
253    }// </editor-fold>//GEN-END:initComponents
254
255    private void profileNameActionPerformed(ActionEvent evt) {//GEN-FIRST:event_profileNameActionPerformed
256        String location = this.profileLocation.getText();
257        this.profileId = FileUtil.sanitizeFilename(this.profileName.getText());
258        if (this.profileId.isEmpty()) {
259            this.profileFolder.setText(location);
260        } else {
261            if (!location.endsWith(File.separator)) {
262                location = location + File.separator;
263            }
264            this.profileFolder.setText(location + this.profileId + Profile.EXTENSION);
265        }
266    }//GEN-LAST:event_profileNameActionPerformed
267
268    private void btnBrowseActionPerformed(ActionEvent evt) {//GEN-FIRST:event_btnBrowseActionPerformed
269        JFileChooser chooser = new jmri.util.swing.JmriJFileChooser(this.profileLocation.getText());
270        chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
271        // TODO: Use NetBeans OpenDialog if its availble
272        if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
273            try {
274                this.profileLocation.setText(chooser.getSelectedFile().getCanonicalPath());
275                this.profileNameActionPerformed(evt);
276            } catch (IOException ex) {
277                log.error("Error selecting profile location", ex);
278            }
279        }
280    }//GEN-LAST:event_btnBrowseActionPerformed
281
282    private void profileFolderActionPerformed(ActionEvent evt) {//GEN-FIRST:event_profileFolderActionPerformed
283        this.profileNameActionPerformed(evt);
284    }//GEN-LAST:event_profileFolderActionPerformed
285
286    private void profileLocationActionPerformed(ActionEvent evt) {//GEN-FIRST:event_profileLocationActionPerformed
287        this.profileNameActionPerformed(evt);
288    }//GEN-LAST:event_profileLocationActionPerformed
289
290    private void btnCancelActionPerformed(ActionEvent evt) {//GEN-FIRST:event_btnCancelActionPerformed
291        this.dispose();
292    }//GEN-LAST:event_btnCancelActionPerformed
293
294    private void btnOkActionPerformed(ActionEvent evt) {//GEN-FIRST:event_btnOkActionPerformed
295        try {
296            this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
297            Profile p = new Profile(this.profileName.getText(), this.profileId, new File(this.profileFolder.getText()));
298            ProfileManager.getDefault().addProfile(p);
299            if (this.source != null) {
300                //if (this.source.equals(ProfileManager.getDefault().getActiveProfile())) {
301                //    // TODO: if source is active profile, prompt user to save source
302                //    InstanceManager.getDefault(ConfigureManager.class).storePrefs();
303                //}
304                ProfileUtils.copy(source, p);
305            }
306            if (this.setNextProfile) {
307                ProfileManager.getDefault().setNextActiveProfile(p);
308            } else {
309                ProfileManager.getDefault().setActiveProfile(p);
310            }
311            ProfileManager.getDefault().saveActiveProfile(p, ProfileManager.getDefault().isAutoStartActiveProfile());
312            if (this.source != null) {
313                log.info("Created profile \"{}\" by copying profile \"{}\"", p.getName(), this.source.getName());
314            } else {
315                log.info("Created new profile \"{}\"", p.getName());
316            }
317            this.setCursor(Cursor.getDefaultCursor());
318            this.dispose();
319        } catch (IOException | IllegalArgumentException ex) {
320            this.setCursor(Cursor.getDefaultCursor());
321            JmriJOptionPane.showMessageDialog(this, ex.getLocalizedMessage(), "Error Creating Profile", JmriJOptionPane.ERROR_MESSAGE);
322            log.error("Error saving profile", ex);
323        }
324    }//GEN-LAST:event_btnOkActionPerformed
325
326    private void profileNameKeyTyped(KeyEvent evt) {//GEN-FIRST:event_profileNameKeyTyped
327        this.profileNameActionPerformed(null);
328    }//GEN-LAST:event_profileNameKeyTyped
329
330    private void profileNameFocusLost(FocusEvent evt) {//GEN-FIRST:event_profileNameFocusLost
331        this.profileNameActionPerformed(null);
332    }//GEN-LAST:event_profileNameFocusLost
333
334    private void profileLocationKeyTyped(KeyEvent evt) {//GEN-FIRST:event_profileLocationKeyTyped
335        this.profileNameActionPerformed(null);
336    }//GEN-LAST:event_profileLocationKeyTyped
337
338    private void profileLocationFocusLost(FocusEvent evt) {//GEN-FIRST:event_profileLocationFocusLost
339        this.profileNameActionPerformed(null);
340    }//GEN-LAST:event_profileLocationFocusLost
341
342    // Variables declaration - do not modify//GEN-BEGIN:variables
343    private JButton btnBrowse;
344    private JButton btnCancel;
345    private JButton btnOk;
346    private JSeparator jSeparator1;
347    private JSeparator jSeparator2;
348    private JLabel lblProfileFolder;
349    private JLabel lblProfileLocation;
350    private JLabel lblProfileName;
351    private JLabel lblProfileNameAndLocation;
352    private JTextField profileFolder;
353    private JTextField profileLocation;
354    private JTextField profileName;
355    // End of variables declaration//GEN-END:variables
356    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(AddProfileDialog.class);
357
358    void setSourceProfile(Profile profile) {
359        this.source = profile;
360        this.setTitle(Bundle.getMessage("AddProfileDialog.copyTitle"));
361    }
362}