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.netbeans.modules.ruby.rubyproject.ui.wizards;
043:
044: import java.io.File;
045: import java.io.IOException;
046: import java.text.MessageFormat;
047: import javax.swing.JFileChooser;
048: import javax.swing.event.DocumentEvent;
049: import javax.swing.event.DocumentListener;
050: import javax.swing.text.Document;
051: import org.netbeans.modules.ruby.RubyUtils;
052: import org.netbeans.modules.ruby.rubyproject.ui.FoldersListSettings;
053: import org.netbeans.modules.ruby.spi.project.support.rake.PropertyUtils;
054: import org.netbeans.spi.project.ui.support.ProjectChooser;
055: import org.openide.WizardDescriptor;
056: import org.openide.WizardValidationException;
057: import org.openide.filesystems.FileUtil;
058: import org.openide.util.NbBundle;
059: import org.openide.util.Utilities;
060:
061: /**
062: *
063: * @author Petr Hrebejk
064: */
065:
066: public class PanelProjectLocationVisual extends SettingsPanel implements
067: DocumentListener {
068:
069: public static final String PROP_PROJECT_NAME = "projectName"; //NOI18N
070:
071: private PanelConfigureProject panel;
072: private int type;
073:
074: /** Creates new form PanelProjectLocationVisual */
075: public PanelProjectLocationVisual(PanelConfigureProject panel,
076: int type) {
077: initComponents();
078: this .panel = panel;
079: this .type = type;
080: // Register listener on the textFields to make the automatic updates
081: projectNameTextField.getDocument().addDocumentListener(this );
082: projectLocationTextField.getDocument()
083: .addDocumentListener(this );
084: }
085:
086: public String getProjectName() {
087: return this .projectNameTextField.getText();
088: }
089:
090: /** This method is called from within the constructor to
091: * initialize the form.
092: * WARNING: Do NOT modify this code. The content of this method is
093: * always regenerated by the Form Editor.
094: */
095: private void initComponents() {//GEN-BEGIN:initComponents
096: java.awt.GridBagConstraints gridBagConstraints;
097:
098: projectNameLabel = new javax.swing.JLabel();
099: projectNameTextField = new javax.swing.JTextField();
100: projectLocationLabel = new javax.swing.JLabel();
101: projectLocationTextField = new javax.swing.JTextField();
102: browseButton = new javax.swing.JButton();
103: createdFolderLabel = new javax.swing.JLabel();
104: createdFolderTextField = new javax.swing.JTextField();
105:
106: setLayout(new java.awt.GridBagLayout());
107:
108: getAccessibleContext().setAccessibleName(
109: org.openide.util.NbBundle.getMessage(
110: PanelProjectLocationVisual.class,
111: "ACSN_PanelProjectLocationVisual"));
112: getAccessibleContext().setAccessibleDescription(
113: org.openide.util.NbBundle.getMessage(
114: PanelProjectLocationVisual.class,
115: "ACSD_PanelProjectLocationVisual"));
116: projectNameLabel.setLabelFor(projectNameTextField);
117: org.openide.awt.Mnemonics.setLocalizedText(projectNameLabel,
118: org.openide.util.NbBundle.getMessage(
119: PanelProjectLocationVisual.class,
120: "LBL_NWP1_ProjectName_Label"));
121: gridBagConstraints = new java.awt.GridBagConstraints();
122: gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
123: gridBagConstraints.insets = new java.awt.Insets(0, 0, 12, 0);
124: add(projectNameLabel, gridBagConstraints);
125: projectNameLabel.getAccessibleContext().setAccessibleName(
126: org.openide.util.NbBundle.getBundle(
127: PanelProjectLocationVisual.class).getString(
128: "ACSN_projectNameLabel"));
129: projectNameLabel.getAccessibleContext()
130: .setAccessibleDescription(
131: org.openide.util.NbBundle.getBundle(
132: PanelProjectLocationVisual.class)
133: .getString("ACSD_projectNameLabel"));
134:
135: gridBagConstraints = new java.awt.GridBagConstraints();
136: gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
137: gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
138: gridBagConstraints.weightx = 1.0;
139: gridBagConstraints.insets = new java.awt.Insets(0, 12, 12, 0);
140: add(projectNameTextField, gridBagConstraints);
141:
142: projectLocationLabel.setLabelFor(projectLocationTextField);
143: org.openide.awt.Mnemonics.setLocalizedText(
144: projectLocationLabel, org.openide.util.NbBundle
145: .getMessage(PanelProjectLocationVisual.class,
146: "LBL_NWP1_ProjectLocation_Label"));
147: gridBagConstraints = new java.awt.GridBagConstraints();
148: gridBagConstraints.gridy = 1;
149: gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
150: gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 0);
151: add(projectLocationLabel, gridBagConstraints);
152: projectLocationLabel.getAccessibleContext().setAccessibleName(
153: org.openide.util.NbBundle.getBundle(
154: PanelProjectLocationVisual.class).getString(
155: "ACSN_projectLocationLabel"));
156: projectLocationLabel
157: .getAccessibleContext()
158: .setAccessibleDescription(
159: org.openide.util.NbBundle.getBundle(
160: PanelProjectLocationVisual.class)
161: .getString("ACSD_projectLocationLabel"));
162:
163: gridBagConstraints = new java.awt.GridBagConstraints();
164: gridBagConstraints.gridy = 1;
165: gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
166: gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
167: gridBagConstraints.weightx = 1.0;
168: gridBagConstraints.insets = new java.awt.Insets(0, 12, 5, 0);
169: add(projectLocationTextField, gridBagConstraints);
170:
171: org.openide.awt.Mnemonics.setLocalizedText(browseButton,
172: org.openide.util.NbBundle.getMessage(
173: PanelProjectLocationVisual.class,
174: "LBL_NWP1_BrowseLocation_Button"));
175: browseButton.setActionCommand("BROWSE");
176: browseButton
177: .addActionListener(new java.awt.event.ActionListener() {
178: public void actionPerformed(
179: java.awt.event.ActionEvent evt) {
180: browseLocationAction(evt);
181: }
182: });
183:
184: gridBagConstraints = new java.awt.GridBagConstraints();
185: gridBagConstraints.gridy = 1;
186: gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
187: gridBagConstraints.insets = new java.awt.Insets(0, 6, 5, 0);
188: add(browseButton, gridBagConstraints);
189: browseButton.getAccessibleContext().setAccessibleName(
190: org.openide.util.NbBundle.getBundle(
191: PanelProjectLocationVisual.class).getString(
192: "ACSN_browseButton"));
193: browseButton.getAccessibleContext().setAccessibleDescription(
194: org.openide.util.NbBundle.getBundle(
195: PanelProjectLocationVisual.class).getString(
196: "ACSD_browseButton"));
197:
198: createdFolderLabel.setLabelFor(createdFolderTextField);
199: org.openide.awt.Mnemonics.setLocalizedText(createdFolderLabel,
200: org.openide.util.NbBundle.getMessage(
201: PanelProjectLocationVisual.class,
202: "LBL_NWP1_CreatedProjectFolder_Lablel"));
203: gridBagConstraints = new java.awt.GridBagConstraints();
204: gridBagConstraints.gridheight = java.awt.GridBagConstraints.REMAINDER;
205: gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
206: add(createdFolderLabel, gridBagConstraints);
207: createdFolderLabel.getAccessibleContext().setAccessibleName(
208: org.openide.util.NbBundle.getBundle(
209: PanelProjectLocationVisual.class).getString(
210: "ACSN_createdFolderLabel"));
211: createdFolderLabel.getAccessibleContext()
212: .setAccessibleDescription(
213: org.openide.util.NbBundle.getBundle(
214: PanelProjectLocationVisual.class)
215: .getString("ACSD_createdFolderLabel"));
216:
217: createdFolderTextField.setEditable(false);
218: gridBagConstraints = new java.awt.GridBagConstraints();
219: gridBagConstraints.gridheight = java.awt.GridBagConstraints.REMAINDER;
220: gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
221: gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
222: gridBagConstraints.weightx = 1.0;
223: gridBagConstraints.weighty = 1.0;
224: gridBagConstraints.insets = new java.awt.Insets(0, 12, 0, 0);
225: add(createdFolderTextField, gridBagConstraints);
226:
227: }//GEN-END:initComponents
228:
229: private void browseLocationAction(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseLocationAction
230: String command = evt.getActionCommand();
231: if ("BROWSE".equals(command)) { // NOI18N
232: JFileChooser chooser = new JFileChooser();
233: FileUtil.preventFileChooserSymlinkTraversal(chooser, null);
234: chooser.setDialogTitle(NbBundle.getMessage(
235: PanelSourceFolders.class,
236: "LBL_NWP1_SelectProjectLocation"));
237: chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
238: String path = this .projectLocationTextField.getText();
239: if (path.length() > 0) {
240: File f = new File(path);
241: if (f.exists()) {
242: chooser.setSelectedFile(f);
243: }
244: }
245: if (JFileChooser.APPROVE_OPTION == chooser
246: .showOpenDialog(this )) { //NOI18N
247: File projectDir = chooser.getSelectedFile();
248: projectLocationTextField.setText(FileUtil
249: .normalizeFile(projectDir).getAbsolutePath());
250: }
251: panel.fireChangeEvent();
252: }
253: }//GEN-LAST:event_browseLocationAction
254:
255: public void addNotify() {
256: super .addNotify();
257: //same problem as in 31086, initial focus on Cancel button
258: projectNameTextField.requestFocus();
259: }
260:
261: boolean valid(WizardDescriptor wizardDescriptor) {
262:
263: if (projectNameTextField.getText().length() == 0
264: || projectNameTextField.getText().indexOf('/') > 0 //NOI18N
265: || projectNameTextField.getText().indexOf('\\') > 0 //NOI18N
266: || projectNameTextField.getText().indexOf(':') > 0) { //NOI18N
267: wizardDescriptor.putProperty("WizardPanel_errorMessage", // NOI18N
268: NbBundle.getMessage(
269: PanelProjectLocationVisual.class,
270: "MSG_IllegalProjectName"));
271: return false; // Display name not specified
272: }
273: File f = new File(projectLocationTextField.getText())
274: .getAbsoluteFile();
275: if (getCanonicalFile(f) == null) {
276: String message = NbBundle.getMessage(
277: PanelProjectLocationVisual.class,
278: "MSG_IllegalProjectLocation");
279: wizardDescriptor.putProperty("WizardPanel_errorMessage",
280: message); // NOI18N
281: return false;
282: }
283: // not allow to create project on unix root folder, see #82339
284: File cfl = getCanonicalFile(new File(createdFolderTextField
285: .getText()));
286: if (Utilities.isUnix() && cfl != null
287: && cfl.getParentFile().getParent() == null) {
288: String message = NbBundle.getMessage(
289: PanelProjectLocationVisual.class,
290: "MSG_ProjectInRootNotSupported");
291: wizardDescriptor.putProperty("WizardPanel_errorMessage",
292: message); // NOI18N
293: return false;
294: }
295:
296: final File destFolder = new File(createdFolderTextField
297: .getText()).getAbsoluteFile();
298: if (getCanonicalFile(destFolder) == null) {
299: String message = NbBundle.getMessage(
300: PanelProjectLocationVisual.class,
301: "MSG_IllegalProjectLocation");
302: wizardDescriptor.putProperty("WizardPanel_errorMessage",
303: message); // NOI18N
304: return false;
305: }
306:
307: File projLoc = FileUtil.normalizeFile(destFolder);
308: while (projLoc != null && !projLoc.exists()) {
309: projLoc = projLoc.getParentFile();
310: }
311: if (projLoc == null || !projLoc.canWrite()) {
312: wizardDescriptor.putProperty("WizardPanel_errorMessage", // NOI18N
313: NbBundle.getMessage(
314: PanelProjectLocationVisual.class,
315: "MSG_ProjectFolderReadOnly"));
316: return false;
317: }
318:
319: if (FileUtil.toFileObject(projLoc) == null) {
320: String message = NbBundle.getMessage(
321: PanelProjectLocationVisual.class,
322: "MSG_IllegalProjectLocation");
323: wizardDescriptor.putProperty("WizardPanel_errorMessage",
324: message); // NOI18N
325: return false;
326: }
327:
328: File[] kids = destFolder.listFiles();
329: if (destFolder.exists() && kids != null && kids.length > 0) {
330: // Folder exists and is not empty
331: wizardDescriptor.putProperty("WizardPanel_errorMessage", // NOI18N
332: NbBundle.getMessage(
333: PanelProjectLocationVisual.class,
334: "MSG_ProjectFolderExists"));
335: return false;
336: }
337:
338: String msg = RubyUtils.getIdentifierWarning(
339: projectNameTextField.getText(), 0);
340: if (msg != null) {
341: wizardDescriptor.putProperty("WizardPanel_errorMessage", // NOI18N
342: msg);
343: // warning only, don't return false
344: }
345:
346: return true;
347: }
348:
349: void store(WizardDescriptor d) {
350:
351: String name = projectNameTextField.getText().trim();
352: String location = projectLocationTextField.getText().trim();
353: String folder = createdFolderTextField.getText().trim();
354:
355: d.putProperty( /*XXX Define somewhere */"projdir", new File(
356: folder)); // NOI18N
357: d.putProperty( /*XXX Define somewhere */"name", name); // NOI18N
358: }
359:
360: void read(WizardDescriptor settings) {
361: File projectLocation = (File) settings.getProperty("projdir"); //NOI18N
362: if (projectLocation == null
363: || projectLocation.getParentFile() == null
364: || !projectLocation.getParentFile().isDirectory()) {
365: projectLocation = ProjectChooser.getProjectsFolder();
366: } else {
367: projectLocation = projectLocation.getParentFile();
368: }
369: this .projectLocationTextField.setText(projectLocation
370: .getAbsolutePath());
371:
372: String projectName = (String) settings.getProperty("name"); //NOI18N
373: if (projectName == null) {
374: if (this .type == NewRubyProjectWizardIterator.TYPE_APP) {
375: int baseCount = FoldersListSettings.getDefault()
376: .getNewApplicationCount() + 1;
377: String formater = NbBundle
378: .getMessage(PanelSourceFolders.class,
379: "TXT_JavaApplication");
380: while ((projectName = validFreeProjectName(
381: projectLocation, formater, baseCount)) == null)
382: baseCount++;
383: settings.putProperty(
384: NewRubyProjectWizardIterator.PROP_NAME_INDEX,
385: new Integer(baseCount));
386: }
387: // else {
388: // int baseCount = FoldersListSettings.getDefault().getNewLibraryCount() + 1;
389: // String formater = NbBundle.getMessage(PanelSourceFolders.class,"TXT_JavaLibrary");
390: // while ((projectName=validFreeProjectName(projectLocation, formater, baseCount))==null)
391: // baseCount++;
392: // settings.putProperty (NewRubyProjectWizardIterator.PROP_NAME_INDEX, new Integer(baseCount));
393: // }
394: }
395: this .projectNameTextField.setText(projectName);
396: this .projectNameTextField.selectAll();
397: }
398:
399: void validate(WizardDescriptor d) throws WizardValidationException {
400: // nothing to validate
401: }
402:
403: // Variables declaration - do not modify//GEN-BEGIN:variables
404: private javax.swing.JButton browseButton;
405: private javax.swing.JLabel createdFolderLabel;
406: private javax.swing.JTextField createdFolderTextField;
407: private javax.swing.JLabel projectLocationLabel;
408: private javax.swing.JTextField projectLocationTextField;
409: private javax.swing.JLabel projectNameLabel;
410: private javax.swing.JTextField projectNameTextField;
411:
412: // End of variables declaration//GEN-END:variables
413:
414: // Private methods ---------------------------------------------------------------------
415:
416: private static JFileChooser createChooser() {
417: JFileChooser chooser = new JFileChooser();
418: FileUtil.preventFileChooserSymlinkTraversal(chooser, null);
419: chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
420: chooser.setAcceptAllFileFilterUsed(false);
421: chooser.setName("Select Project Directory"); // XXX // NOI18N
422: return chooser;
423: }
424:
425: private String validFreeProjectName(final File parentFolder,
426: final String formater, final int index) {
427: String name = MessageFormat.format(formater,
428: new Object[] { new Integer(index) });
429: File file = new File(parentFolder, name);
430: return file.exists() ? null : name;
431: }
432:
433: // Implementation of DocumentListener --------------------------------------------------
434:
435: public void changedUpdate(DocumentEvent e) {
436: updateTexts(e);
437: if (this .projectNameTextField.getDocument() == e.getDocument()) {
438: firePropertyChange(PROP_PROJECT_NAME, null,
439: this .projectNameTextField.getText());
440: }
441: }
442:
443: public void insertUpdate(DocumentEvent e) {
444: updateTexts(e);
445: if (this .projectNameTextField.getDocument() == e.getDocument()) {
446: firePropertyChange(PROP_PROJECT_NAME, null,
447: this .projectNameTextField.getText());
448: }
449: }
450:
451: public void removeUpdate(DocumentEvent e) {
452: updateTexts(e);
453: if (this .projectNameTextField.getDocument() == e.getDocument()) {
454: firePropertyChange(PROP_PROJECT_NAME, null,
455: this .projectNameTextField.getText());
456: }
457: }
458:
459: /** Handles changes in the Project name and project directory
460: */
461: private void updateTexts(DocumentEvent e) {
462: Document doc = e.getDocument();
463: if (doc == projectNameTextField.getDocument()
464: || doc == projectLocationTextField.getDocument()) {
465: // Change in the project name
466: String projectName = projectNameTextField.getText();
467: String projectFolder = projectLocationTextField.getText();
468: String projFolderPath = getCanonicalPath(new File(
469: projectFolder));
470: if (projFolderPath.endsWith(File.separator)) {
471: createdFolderTextField.setText(projFolderPath
472: + projectName);
473: } else {
474: createdFolderTextField.setText(projFolderPath
475: + File.separator + projectName);
476: }
477: }
478: panel.fireChangeEvent(); // Notify that the panel changed
479: }
480:
481: static File getCanonicalFile(File file) {
482: try {
483: return file.getCanonicalFile();
484: } catch (IOException e) {
485: return null;
486: }
487: }
488:
489: static String getCanonicalPath(File f) {
490: try {
491: return f.getCanonicalPath();
492: } catch (IOException e) {
493: return "";
494: }
495: }
496:
497: }
|