001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.openide.loaders;
043:
044: import java.awt.event.KeyEvent;
045: import java.beans.PropertyDescriptor;
046: import java.io.IOException;
047: import java.lang.ref.*;
048: import java.lang.reflect.Method;
049: import javax.swing.*;
050: import javax.swing.event.*;
051: import org.openide.explorer.propertysheet.*;
052: import org.openide.filesystems.*;
053: import org.openide.util.*;
054:
055: /** Dialog that can be used in create from template.
056: *
057: * @author Jaroslav Tulach, Jiri Rechtacek
058: */
059: final class TemplateWizard2 extends javax.swing.JPanel implements
060: DocumentListener {
061:
062: /** listener to changes in the wizard */
063: private ChangeListener listener;
064:
065: private static final String PROP_LOCATION_FOLDER = "locationFolder"; // NOI18N
066: private DataFolder locationFolder;
067: private Reference<FileSystem> fileSystemRef = new WeakReference<FileSystem>(
068: null);
069: private DefaultPropertyModel locationFolderModel;
070:
071: /** File extension of the template and of the created file -
072: * it is used to test whether file already exists.
073: */
074: private String extension;
075:
076: /** Creates new form TemplateWizard2 */
077: public TemplateWizard2() {
078: initLocationFolder();
079: initComponents();
080: setName(DataObject.getString("LAB_TargetLocationPanelName")); // NOI18N
081: // registers itself to listen to changes in the content of document
082: java.util.ResourceBundle bundle = org.openide.util.NbBundle
083: .getBundle(TemplateWizard2.class);
084: newObjectName.getDocument().addDocumentListener(this );
085: newObjectName.unregisterKeyboardAction(KeyStroke.getKeyStroke(
086: KeyEvent.VK_ENTER, 0));
087: newObjectName.getAccessibleContext().setAccessibleDescription(
088: bundle.getString("ACSD_NewObjectName")); // NOI18N
089: }
090:
091: /** This method is called from within the constructor to
092: * initialize the location folder and make it accessible.
093: * The getter/setter methods must be accessible for purposes introspection.
094: * Because this class is not public then these methods are made accessible explicitly.
095: */
096: private void initLocationFolder() {
097: PropertyDescriptor pd = null;
098: try {
099: Method getterMethod = this .getClass().getDeclaredMethod(
100: "getLocationFolder", new Class[] {}); // NOI18N
101: getterMethod.setAccessible(true);
102: Method setterMethod = this .getClass().getDeclaredMethod(
103: "setLocationFolder",
104: new Class[] { DataFolder.class }); // NOI18N
105: setterMethod.setAccessible(true);
106: pd = new PropertyDescriptor(PROP_LOCATION_FOLDER,
107: getterMethod, setterMethod);
108: } catch (java.beans.IntrospectionException ie) {
109: Exceptions.printStackTrace(ie);
110: } catch (NoSuchMethodException nsme) {
111: Exceptions.printStackTrace(nsme);
112: }
113: locationFolderModel = new DefaultPropertyModel(this , pd);
114: }
115:
116: /** Getter for default name of a new object.
117: * @return the default name.
118: */
119: private static String defaultNewObjectName() {
120: return DataObject.getString("FMT_DefaultNewObjectName"); // NOI18N
121: }
122:
123: /** This method is called from within the constructor to
124: * initialize the form.
125: * WARNING: Do NOT modify this code. The content of this method is
126: * always regenerated by the Form Editor.
127: */
128: // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
129: private void initComponents() {
130:
131: namePanel = new javax.swing.JPanel();
132: jLabel1 = new javax.swing.JLabel();
133: newObjectName = new javax.swing.JTextField();
134: dataFolderPanel = dataFolderPanel = new PropertyPanel(
135: locationFolderModel, PropertyPanel.PREF_CUSTOM_EDITOR);
136:
137: FormListener formListener = new FormListener();
138:
139: setLayout(new java.awt.BorderLayout());
140:
141: namePanel.setLayout(new java.awt.BorderLayout(12, 0));
142:
143: jLabel1.setLabelFor(newObjectName);
144: java.util.ResourceBundle bundle = java.util.ResourceBundle
145: .getBundle("org/openide/loaders/Bundle"); // NOI18N
146: org.openide.awt.Mnemonics.setLocalizedText(jLabel1, bundle
147: .getString("CTL_NewObjectName")); // NOI18N
148: namePanel.add(jLabel1, java.awt.BorderLayout.WEST);
149:
150: newObjectName.addFocusListener(formListener);
151: namePanel.add(newObjectName, java.awt.BorderLayout.CENTER);
152:
153: add(namePanel, java.awt.BorderLayout.NORTH);
154: add(dataFolderPanel, java.awt.BorderLayout.CENTER);
155: }
156:
157: // Code for dispatching events from components to event handlers.
158:
159: private class FormListener implements java.awt.event.FocusListener {
160: FormListener() {
161: }
162:
163: public void focusGained(java.awt.event.FocusEvent evt) {
164: if (evt.getSource() == newObjectName) {
165: TemplateWizard2.this .newObjectNameFocusGained(evt);
166: }
167: }
168:
169: public void focusLost(java.awt.event.FocusEvent evt) {
170: }
171: }// </editor-fold>//GEN-END:initComponents
172:
173: private void newObjectNameFocusGained(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_newObjectNameFocusGained
174: newObjectName.selectAll();
175: }//GEN-LAST:event_newObjectNameFocusGained
176:
177: /** Add a listener to changes of the panel's validity.
178: * @param l the listener to add
179: * @see #isValid
180: *
181: */
182: void addChangeListener(ChangeListener l) {
183: if (listener != null)
184: throw new IllegalStateException();
185:
186: listener = l;
187: }
188:
189: public void addNotify() {
190: super .addNotify();
191: //Fix for issue 31086, initial focus on Back button
192: newObjectName.requestFocus();
193: getAccessibleContext().setAccessibleDescription(
194: NbBundle.getBundle(TemplateWizard2.class).getString(
195: "ACSD_TemplateWizard2") // NOI18N
196: );
197: }
198:
199: /** Helper implementation of WizardDescription.Panel for TemplateWizard.Panel2.
200: * Provides the wizard panel with the current data--either
201: * the default data or already-modified settings, if the user used the previous and/or next buttons.
202: * This method can be called multiple times on one instance of <code>WizardDescriptor.Panel</code>.
203: * <p>The settings object is originally supplied to {@link WizardDescriptor#WizardDescriptor(WizardDescriptor.Iterator,Object)}.
204: * In the case of a <code>TemplateWizard.Iterator</code> panel, the object is
205: * in fact the <code>TemplateWizard</code>.
206: * @param settings the object representing wizard panel state
207: * @exception IllegalStateException if the the data provided
208: * by the wizard are not valid.
209: *
210: */
211: void implReadSettings(Object settings) {
212: TemplateWizard wizard = (TemplateWizard) settings;
213:
214: DataObject template = wizard.getTemplate();
215: if (template != null) {
216: extension = template.getPrimaryFile().getExt();
217: }
218:
219: setNewObjectName(wizard.getTargetName());
220:
221: try {
222: setLocationFolder(wizard.getTargetFolder());
223: } catch (IOException ioe) {
224: setLocationFolder(null);
225: }
226: }
227:
228: /** Remove a listener to changes of the panel's validity.
229: * @param l the listener to remove
230: *
231: */
232: public void removeChangeListener(ChangeListener l) {
233: listener = null;
234: }
235:
236: /** Helper implementation of WizardDescription.Panel for TemplateWizard.Panel2.
237: * Provides the wizard panel with the opportunity to update the
238: * settings with its current customized state.
239: * Rather than updating its settings with every change in the GUI, it should collect them,
240: * and then only save them when requested to by this method.
241: * Also, the original settings passed to {@link #readSettings} should not be modified (mutated);
242: * rather, the object passed in here should be mutated according to the collected changes,
243: * in case it is a copy.
244: * This method can be called multiple times on one instance of <code>WizardDescriptor.Panel</code>.
245: * <p>The settings object is originally supplied to {@link WizardDescriptor#WizardDescriptor(WizardDescriptor.Iterator,Object)}.
246: * In the case of a <code>TemplateWizard.Iterator</code> panel, the object is
247: * in fact the <code>TemplateWizard</code>.
248: * @param settings the object representing wizard panel state
249: *
250: */
251: void implStoreSettings(Object settings) {
252: TemplateWizard wizard = (TemplateWizard) settings;
253:
254: wizard.setTargetFolder(locationFolder);
255:
256: String name = newObjectName.getText();
257: if (name.equals(defaultNewObjectName())) {
258: name = null;
259: }
260: wizard.setTargetName(name);
261: }
262:
263: /** Helper implementation of WizardDescription.Panel for TemplateWizard.Panel2.
264: * Test whether the panel is finished and it is safe to proceed to the next one.
265: * If the panel is valid, the "Next" (or "Finish") button will be enabled.
266: * @return <code>null</code> if the user has entered satisfactory information
267: * or localized string describing the error.
268: */
269: String implIsValid() {
270: // test whether the selected folder on selected filesystem already exists
271: FileSystem fs = fileSystemRef.get();
272: if (locationFolder == null || fs == null)
273: return NbBundle.getMessage(TemplateWizard2.class,
274: "MSG_fs_or_folder_does_not_exist"); // NOI18N
275:
276: // target filesystem should be writable
277: if (fileSystemRef.get().isReadOnly())
278: return NbBundle.getMessage(TemplateWizard2.class,
279: "MSG_fs_is_readonly"); // NOI18N
280:
281: if (locationFolder == null)
282: locationFolder = DataFolder.findFolder(fs.getRoot());
283:
284: // test whether the selected name already exists
285: StringBuffer sb = new StringBuffer();
286: sb.append(locationFolder.getPrimaryFile().getPath());
287: sb.append("/");
288: sb.append(newObjectName.getText());
289: if ("" != extension) { // NOI18N
290: sb.append('.');
291: sb.append(extension);
292: }
293:
294: FileObject f = fs.findResource(sb.toString());
295: if (f != null) {
296: return NbBundle.getMessage(TemplateWizard2.class,
297: "MSG_file_already_exist", sb.toString()); // NOI18N
298: }
299:
300: if ((Utilities.isWindows() || (Utilities.getOperatingSystem() == Utilities.OS_OS2))) {
301: if (TemplateWizard.checkCaseInsensitiveName(locationFolder
302: .getPrimaryFile(), newObjectName.getText(),
303: extension)) {
304: return NbBundle.getMessage(TemplateWizard2.class,
305: "MSG_file_already_exist", newObjectName
306: .getText()); // NOI18N
307: }
308: }
309:
310: // all ok
311: return null;
312: }
313:
314: /** Gives notification that an attribute or set of attributes changed.
315: *
316: * @param e the document event
317: *
318: */
319: public void changedUpdate(DocumentEvent e) {
320: if (e.getDocument() == newObjectName.getDocument()) {
321: SwingUtilities.invokeLater(new Updater());
322: }
323: }
324:
325: /** Gives notification that there was an insert into the document. The
326: * range given by the DocumentEvent bounds the freshly inserted region.
327: *
328: * @param e the document event
329: *
330: */
331: public void insertUpdate(DocumentEvent e) {
332: changedUpdate(e);
333: }
334:
335: /** Gives notification that a portion of the document has been
336: * removed. The range is given in terms of what the view last
337: * saw (that is, before updating sticky positions).
338: *
339: * @param e the document event
340: *
341: */
342: public void removeUpdate(DocumentEvent e) {
343: // so just check the name
344: if (e.getDocument() == newObjectName.getDocument()) {
345: SwingUtilities.invokeLater(new Updater());
346: }
347: }
348:
349: /** Does the update called from changedUpdate, insertUpdate and
350: * removeUpdate methods.
351: */
352: private class Updater implements Runnable {
353: Updater() {
354: }
355:
356: public void run() {
357: if (newObjectName.getText().equals("")) { // NOI18N
358: setNewObjectName(""); // NOI18N
359: }
360:
361: fireStateChanged();
362: }
363: }
364:
365: /** Request focus.
366: */
367: public void requestFocus() {
368: newObjectName.requestFocus();
369: newObjectName.selectAll();
370: }
371:
372: /** Sets the class name to some reasonable value.
373: * @param name the name to set the name to
374: */
375: private void setNewObjectName(String name) {
376: String n = name;
377: if (name == null || name.length() == 0) {
378: n = defaultNewObjectName();
379: }
380:
381: newObjectName.getDocument().removeDocumentListener(this );
382: newObjectName.setText(n);
383: newObjectName.getDocument().addDocumentListener(this );
384:
385: if (name == null || name.length() == 0) {
386: newObjectName.selectAll();
387: }
388: }
389:
390: /** Fires info to listener.
391: */
392: private void fireStateChanged() {
393: if (listener != null) {
394: listener.stateChanged(new ChangeEvent(this ));
395: }
396: }
397:
398: // Variables declaration - do not modify//GEN-BEGIN:variables
399: private org.openide.explorer.propertysheet.PropertyPanel dataFolderPanel;
400: private javax.swing.JLabel jLabel1;
401: private javax.swing.JPanel namePanel;
402: private javax.swing.JTextField newObjectName;
403:
404: // End of variables declaration//GEN-END:variables
405:
406: public void setLocationFolder(DataFolder fd) {
407: if (locationFolder == fd)
408: return;
409: if (locationFolder != null && locationFolder.equals(fd))
410: return;
411: DataFolder oldLocation = locationFolder;
412: locationFolder = fd;
413: firePropertyChange(PROP_LOCATION_FOLDER, oldLocation,
414: locationFolder);
415: if (fd != null) {
416: try {
417: fileSystemRef = new WeakReference<FileSystem>(fd
418: .getPrimaryFile().getFileSystem());
419: } catch (org.openide.filesystems.FileStateInvalidException fsie) {
420: fileSystemRef = new WeakReference<FileSystem>(null);
421: }
422: }
423: fireStateChanged();
424: }
425:
426: public DataFolder getLocationFolder() {
427: return locationFolder;
428: }
429:
430: }
|