001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2008 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-2008 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.beans.PropertyChangeListener;
045: import java.beans.PropertyChangeEvent;
046: import java.io.File;
047: import java.text.MessageFormat;
048: import java.util.ArrayList;
049: import java.util.Iterator;
050: import java.util.List;
051: import javax.swing.JButton;
052: import javax.swing.JPanel;
053: import javax.swing.event.ChangeEvent;
054: import javax.swing.event.ChangeListener;
055: import org.netbeans.spi.project.ui.templates.support.Templates;
056: import org.openide.DialogDisplayer;
057: import org.openide.NotifyDescriptor;
058: import org.openide.WizardDescriptor;
059: import org.openide.WizardValidationException;
060: import org.openide.filesystems.FileObject;
061: import org.openide.filesystems.FileUtil;
062: import org.openide.util.HelpCtx;
063: import org.openide.util.NbBundle;
064:
065: //XXX There should be a way how to add nonexistent test dir
066:
067: /**
068: * Sets up name and location for new Java project from existing sources.
069: * @author Tomas Zezula et al.
070: */
071: public class PanelSourceFolders extends SettingsPanel implements
072: PropertyChangeListener {
073:
074: private final Panel firer;
075: private WizardDescriptor wizardDescriptor;
076:
077: // key to action value that influence folder list current directory
078: public static final String INITIAL_SOURCE_ROOT = "EXISTING_SOURCES_CURRENT_DIRECTORY"; // NOI18N
079:
080: /** Creates new form PanelSourceFolders */
081: PanelSourceFolders(Panel panel) {
082: this .firer = panel;
083: initComponents();
084: this .setName(NbBundle.getMessage(PanelSourceFolders.class,
085: "LAB_ConfigureSourceRoots"));
086: this .putClientProperty("NewProjectWizard_Title", NbBundle
087: .getMessage(PanelSourceFolders.class,
088: "TXT_JavaExtSourcesProjectLocation")); // NOI18N
089: this .getAccessibleContext().setAccessibleName(
090: NbBundle.getMessage(PanelSourceFolders.class,
091: "AN_PanelSourceFolders"));
092: this .getAccessibleContext().setAccessibleDescription(
093: NbBundle.getMessage(PanelSourceFolders.class,
094: "AD_PanelSourceFolders"));
095: this .sourcePanel.addPropertyChangeListener(this );
096: this .testsPanel.addPropertyChangeListener(this );
097: ((FolderList) this .sourcePanel)
098: .setRelatedFolderList((FolderList) this .testsPanel);
099: ((FolderList) this .testsPanel)
100: .setRelatedFolderList((FolderList) this .sourcePanel);
101: }
102:
103: public void propertyChange(PropertyChangeEvent evt) {
104: if (FolderList.PROP_FILES.equals(evt.getPropertyName())) {
105: this .dataChanged();
106: } else if (FolderList.PROP_LAST_USED_DIR.equals(evt
107: .getPropertyName())) {
108: if (evt.getSource() == this .sourcePanel) {
109: ((FolderList) this .testsPanel)
110: .setLastUsedDir((File) evt.getNewValue());
111: } else if (evt.getSource() == this .testsPanel) {
112: ((FolderList) this .sourcePanel)
113: .setLastUsedDir((File) evt.getNewValue());
114: }
115: }
116: }
117:
118: private void dataChanged() {
119: this .firer.fireChangeEvent();
120: }
121:
122: void read(WizardDescriptor settings) {
123: this .wizardDescriptor = settings;
124: File projectLocation = (File) settings.getProperty("projdir"); //NOI18N
125: ((FolderList) this .sourcePanel)
126: .setProjectFolder(projectLocation);
127: ((FolderList) this .testsPanel)
128: .setProjectFolder(projectLocation);
129: File[] srcRoot = (File[]) settings.getProperty("sourceRoot"); //NOI18N
130: assert srcRoot != null : "sourceRoot property must be initialized!"; //NOI18N
131: ((FolderList) this .sourcePanel).setFiles(srcRoot);
132: File[] testRoot = (File[]) settings.getProperty("testRoot"); //NOI18N
133: assert testRoot != null : "testRoot property must be initialized!"; //NOI18N
134: ((FolderList) this .testsPanel).setFiles(testRoot);
135:
136: // #58489 honor existing source folder
137: File currentDirectory = null;
138: FileObject folder = Templates
139: .getExistingSourcesFolder(wizardDescriptor);
140: if (folder != null) {
141: currentDirectory = FileUtil.toFile(folder);
142: }
143: if (currentDirectory != null && currentDirectory.isDirectory()) {
144: ((FolderList) sourcePanel).setLastUsedDir(currentDirectory);
145: ((FolderList) testsPanel).setLastUsedDir(currentDirectory);
146: }
147: }
148:
149: void store(WizardDescriptor settings) {
150: File[] sourceRoots = ((FolderList) this .sourcePanel).getFiles();
151: File[] testRoots = ((FolderList) this .testsPanel).getFiles();
152: settings.putProperty("sourceRoot", sourceRoots); //NOI18N
153: settings.putProperty("testRoot", testRoots); //NOI18N
154: }
155:
156: boolean valid(WizardDescriptor settings) {
157: File projectLocation = (File) settings.getProperty("projdir"); //NOI18N
158: File[] sourceRoots = ((FolderList) this .sourcePanel).getFiles();
159: File[] testRoots = ((FolderList) this .testsPanel).getFiles();
160: String result = checkValidity(projectLocation, sourceRoots,
161: testRoots);
162: if (result == null) {
163: wizardDescriptor
164: .putProperty("WizardPanel_errorMessage", ""); //NOI18N
165: return true;
166: } else {
167: wizardDescriptor.putProperty("WizardPanel_errorMessage",
168: result); //NOI18N
169: return false;
170: }
171: }
172:
173: static String checkValidity(final File projectLocation,
174: final File[] sources, final File[] tests) {
175: String ploc = projectLocation.getAbsolutePath();
176: for (int i = 0; i < sources.length; i++) {
177: if (!sources[i].isDirectory() || !sources[i].canRead()) {
178: return MessageFormat.format(
179: NbBundle.getMessage(PanelSourceFolders.class,
180: "MSG_IllegalSources"),
181: new Object[] { sources[i].getAbsolutePath() });
182: }
183: String sloc = sources[i].getAbsolutePath();
184: if (ploc.equals(sloc)
185: || ploc.startsWith(sloc + File.separatorChar)) {
186: return NbBundle.getMessage(PanelSourceFolders.class,
187: "MSG_IllegalProjectFolder");
188: }
189: }
190: for (int i = 0; i < tests.length; i++) {
191: if (!tests[i].isDirectory() || !tests[i].canRead()) {
192: return MessageFormat.format(NbBundle.getMessage(
193: PanelSourceFolders.class, "MSG_IllegalTests"),
194: new Object[] { sources[i].getAbsolutePath() });
195: }
196: String tloc = tests[i].getAbsolutePath();
197: if (ploc.equals(tloc)
198: || ploc.startsWith(tloc + File.separatorChar)) {
199: return NbBundle.getMessage(PanelSourceFolders.class,
200: "MSG_IllegalProjectFolder");
201: }
202: }
203: return null;
204: }
205:
206: void validate(WizardDescriptor d) throws WizardValidationException {
207: // sources root
208: searchClassFiles(((FolderList) this .sourcePanel).getFiles());
209: // test root, not asked in issue 48198
210: //searchClassFiles (FileUtil.toFileObject (FileUtil.normalizeFile(new File (tests.getText ()))));
211: }
212:
213: private static void findClassFiles(File folder, List<File> files) {
214: File[] kids = folder.listFiles();
215: if (kids == null) {
216: return;
217: }
218: for (File kid : kids) {
219: if (kid.isFile() && kid.getName().endsWith(".class")) {
220: files.add(kid);
221: } else if (kid.isDirectory()) {
222: findClassFiles(kid, files);
223: }
224: }
225: }
226:
227: private void searchClassFiles(File[] folders)
228: throws WizardValidationException {
229: List<File> classFiles = new ArrayList<File>();
230: for (File folder : folders) {
231: findClassFiles(folder, classFiles);
232: }
233: if (!classFiles.isEmpty()) {
234: JButton DELETE_OPTION = new JButton(NbBundle.getMessage(
235: PanelSourceFolders.class, "TXT_DeleteOption")); // NOI18N
236: JButton KEEP_OPTION = new JButton(NbBundle.getMessage(
237: PanelSourceFolders.class, "TXT_KeepOption")); // NOI18N
238: JButton CANCEL_OPTION = new JButton(NbBundle.getMessage(
239: PanelSourceFolders.class, "TXT_CancelOption")); // NOI18N
240: DELETE_OPTION.getAccessibleContext()
241: .setAccessibleDescription(
242: NbBundle.getMessage(
243: PanelSourceFolders.class,
244: "AD_DeleteOption"));
245: KEEP_OPTION.getAccessibleContext()
246: .setAccessibleDescription(
247: NbBundle.getMessage(
248: PanelSourceFolders.class,
249: "AD_KeepOption"));
250: CANCEL_OPTION.getAccessibleContext()
251: .setAccessibleDescription(
252: NbBundle.getMessage(
253: PanelSourceFolders.class,
254: "AD_CancelOption"));
255: NotifyDescriptor desc = new NotifyDescriptor(
256: NbBundle.getMessage(PanelSourceFolders.class,
257: "MSG_FoundClassFiles"), // NOI18N
258: NbBundle.getMessage(PanelSourceFolders.class,
259: "MSG_FoundClassFiles_Title"), // NOI18N
260: NotifyDescriptor.YES_NO_CANCEL_OPTION,
261: NotifyDescriptor.QUESTION_MESSAGE,
262: new Object[] { DELETE_OPTION, KEEP_OPTION,
263: CANCEL_OPTION }, DELETE_OPTION);
264: Object result = DialogDisplayer.getDefault().notify(desc);
265: if (DELETE_OPTION.equals(result)) {
266: for (File f : classFiles) {
267: f.delete(); // ignore if fails
268: }
269: } else if (!KEEP_OPTION.equals(result)) {
270: // cancel, back to wizard
271: throw new WizardValidationException(this .sourcePanel,
272: "", ""); // NOI18N
273: }
274: }
275: }
276:
277: /** This method is called from within the constructor to
278: * initialize the form.
279: * WARNING: Do NOT modify this code. The content of this method is
280: * always regenerated by the Form Editor.
281: */
282: // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
283: private void initComponents() {
284: java.awt.GridBagConstraints gridBagConstraints;
285:
286: description = new javax.swing.JLabel();
287: sourcePanel = createSourcePanel();
288: testsPanel = createTestPanel();
289:
290: setLayout(new java.awt.GridBagLayout());
291:
292: org.openide.awt.Mnemonics.setLocalizedText(description,
293: org.openide.util.NbBundle.getMessage(
294: PanelSourceFolders.class,
295: "LBL_SourceDirectoriesLabel")); // NOI18N
296: gridBagConstraints = new java.awt.GridBagConstraints();
297: gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
298: gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
299: gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
300: add(description, gridBagConstraints);
301: description.getAccessibleContext().setAccessibleName(
302: org.openide.util.NbBundle.getBundle(
303: PanelSourceFolders.class).getString(
304: "ACSN_jLabel3")); // NOI18N
305: description.getAccessibleContext().setAccessibleDescription(
306: org.openide.util.NbBundle.getBundle(
307: PanelSourceFolders.class).getString(
308: "ACSD_jLabel3")); // NOI18N
309:
310: gridBagConstraints = new java.awt.GridBagConstraints();
311: gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
312: gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
313: gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
314: gridBagConstraints.weightx = 1.0;
315: gridBagConstraints.weighty = 0.45;
316: gridBagConstraints.insets = new java.awt.Insets(12, 0, 0, 0);
317: add(sourcePanel, gridBagConstraints);
318: gridBagConstraints = new java.awt.GridBagConstraints();
319: gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
320: gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
321: gridBagConstraints.weightx = 1.0;
322: gridBagConstraints.weighty = 0.45;
323: gridBagConstraints.insets = new java.awt.Insets(12, 0, 0, 0);
324: add(testsPanel, gridBagConstraints);
325:
326: getAccessibleContext().setAccessibleName(
327: org.openide.util.NbBundle.getMessage(
328: PanelSourceFolders.class,
329: "ACSN_PanelSourceFolders")); // NOI18N
330: getAccessibleContext().setAccessibleDescription(
331: org.openide.util.NbBundle.getMessage(
332: PanelSourceFolders.class,
333: "ACSD_PanelSourceFolders")); // NOI18N
334: }// </editor-fold>//GEN-END:initComponents
335:
336: // Variables declaration - do not modify//GEN-BEGIN:variables
337: private javax.swing.JLabel description;
338: private javax.swing.JPanel sourcePanel;
339: private javax.swing.JPanel testsPanel;
340:
341: // End of variables declaration//GEN-END:variables
342:
343: static class Panel implements WizardDescriptor.ValidatingPanel {
344:
345: private ArrayList<ChangeListener> listeners;
346: private PanelSourceFolders component;
347: private WizardDescriptor settings;
348:
349: public synchronized void removeChangeListener(ChangeListener l) {
350: if (this .listeners == null) {
351: return;
352: }
353: this .listeners.remove(l);
354: }
355:
356: public void addChangeListener(ChangeListener l) {
357: if (this .listeners == null) {
358: this .listeners = new ArrayList<ChangeListener>();
359: }
360: this .listeners.add(l);
361: }
362:
363: public void readSettings(Object settings) {
364: this .settings = (WizardDescriptor) settings;
365: this .component.read(this .settings);
366: // XXX hack, TemplateWizard in final setTemplateImpl() forces new wizard's title
367: // this name is used in NewProjectWizard to modify the title
368: Object substitute = component
369: .getClientProperty("NewProjectWizard_Title"); // NOI18N
370: if (substitute != null) {
371: this .settings.putProperty("NewProjectWizard_Title",
372: substitute); // NOI18N
373: }
374: }
375:
376: public void storeSettings(Object settings) {
377: this .component.store(this .settings);
378: }
379:
380: public void validate() throws WizardValidationException {
381: this .component.validate(this .settings);
382: }
383:
384: public boolean isValid() {
385: return this .component.valid(this .settings);
386: }
387:
388: public synchronized java.awt.Component getComponent() {
389: if (this .component == null) {
390: this .component = new PanelSourceFolders(this );
391: }
392: return this .component;
393: }
394:
395: public HelpCtx getHelp() {
396: return new HelpCtx(PanelSourceFolders.class);
397: }
398:
399: private void fireChangeEvent() {
400: Iterator it = null;
401: synchronized (this ) {
402: if (this .listeners == null) {
403: return;
404: }
405: it = ((ArrayList) this .listeners.clone()).iterator();
406: }
407: ChangeEvent event = new ChangeEvent(this );
408: while (it.hasNext()) {
409: ((ChangeListener) it.next()).stateChanged(event);
410: }
411: }
412:
413: }
414:
415: private JPanel createSourcePanel() {
416: return new FolderList(NbBundle.getMessage(
417: PanelSourceFolders.class, "CTL_SourceRoots"),
418: NbBundle.getMessage(PanelSourceFolders.class,
419: "AD_SourceRoots"), NbBundle.getMessage(
420: PanelSourceFolders.class, "CTL_AddSourceRoot"),
421: NbBundle.getMessage(PanelSourceFolders.class,
422: "AD_AddSourceFolder"), NbBundle
423: .getMessage(PanelSourceFolders.class,
424: "CTL_AddSourceFolder"), NbBundle
425: .getMessage(PanelSourceFolders.class,
426: "AD_RemoveSourceFolder"), NbBundle
427: .getMessage(PanelSourceFolders.class,
428: "CTL_RemoveSourceFolder"));
429: }
430:
431: private JPanel createTestPanel() {
432: return new FolderList(NbBundle.getMessage(
433: PanelSourceFolders.class, "CTL_TestRoots"), NbBundle
434: .getMessage(PanelSourceFolders.class, "AD_TestRoots"),
435: NbBundle.getMessage(PanelSourceFolders.class,
436: "CTL_AddTestRoot"), NbBundle.getMessage(
437: PanelSourceFolders.class, "AD_AddTestFolder"),
438: NbBundle.getMessage(PanelSourceFolders.class,
439: "CTL_AddTestFolder"), NbBundle
440: .getMessage(PanelSourceFolders.class,
441: "AD_RemoveTestFolder"), NbBundle
442: .getMessage(PanelSourceFolders.class,
443: "CTL_RemoveTestFolder"));
444: }
445: }
|