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.project.ant;
043:
044: import java.awt.event.ActionEvent;
045: import java.awt.event.ActionListener;
046: import java.beans.PropertyChangeEvent;
047: import java.beans.PropertyChangeListener;
048: import java.io.File;
049: import java.io.IOException;
050: import java.text.MessageFormat;
051: import java.util.ArrayList;
052: import java.util.Arrays;
053: import java.util.Collections;
054: import java.util.List;
055: import javax.swing.JFileChooser;
056: import org.netbeans.api.queries.CollocationQuery;
057: import org.netbeans.spi.project.support.ant.PropertyUtils;
058: import org.openide.DialogDisplayer;
059: import org.openide.NotifyDescriptor;
060: import org.openide.filesystems.FileObject;
061: import org.openide.filesystems.FileUtil;
062: import org.openide.util.NbBundle;
063:
064: /**
065: * Accessory allowing to choose how file is referenced from a project - relative
066: * or absolute.
067: *
068: * <p>The panel is used from two different places - FileChooser and
069: * RelativizeFilePathCustomizer.
070: *
071: * @author David Konecny
072: */
073: public class FileChooserAccessory extends javax.swing.JPanel implements
074: ActionListener, PropertyChangeListener {
075:
076: private File baseFolder;
077: private final File sharedLibrariesFolder;
078: private boolean copyAllowed;
079: private JFileChooser chooser;
080: private List<String> copiedRelativeFiles = null;
081: /** In RelativizeFilePathCustomizer scenario this property holds preselected file */
082: private File usetThisFileInsteadOfOneFromChooser = null;
083:
084: /**
085: * Constructor for usage from RelativizeFilePathCustomizer.
086: */
087: public FileChooserAccessory(File baseFolder,
088: File sharedLibrariesFolder, boolean copyAllowed,
089: File selectedFile) {
090: this (null, baseFolder, sharedLibrariesFolder, copyAllowed);
091: usetThisFileInsteadOfOneFromChooser = selectedFile;
092: enableAccessory(true);
093: update(Collections
094: .singletonList(usetThisFileInsteadOfOneFromChooser));
095:
096: //when deciding on predefined file, we can assume certain options to be preferable.
097: if (CollocationQuery.areCollocated(baseFolder, selectedFile)) {
098: rbRelative.setSelected(true);
099: } else {
100: if (copyAllowed) {
101: rbCopy.setSelected(true);
102: } else {
103: rbAbsolute.setSelected(true);
104: }
105: }
106: }
107:
108: /**
109: * Constructor for usage from FileChooser.
110: */
111: public FileChooserAccessory(JFileChooser chooser, File baseFolder,
112: File sharedLibrariesFolder, boolean copyAllowed) {
113: assert baseFolder != null;
114: assert !baseFolder.isFile();
115: if (sharedLibrariesFolder != null) {
116: assert !sharedLibrariesFolder.isFile() : true;
117: if (!sharedLibrariesFolder.equals(FileUtil
118: .normalizeFile(sharedLibrariesFolder))) {
119: throw new IllegalArgumentException(
120: "Parameter file was not "
121: + // NOI18N
122: "normalized. Was "
123: + sharedLibrariesFolder
124: + " instead of "
125: + FileUtil
126: .normalizeFile(sharedLibrariesFolder)); // NOI18N
127: }
128: }
129: this .baseFolder = baseFolder;
130: this .sharedLibrariesFolder = sharedLibrariesFolder;
131: this .copyAllowed = copyAllowed && sharedLibrariesFolder != null;
132: this .chooser = chooser;
133: initComponents();
134: //copyPanel.setVisible(copyAllowed);
135: rbCopy.addActionListener(this );
136: rbRelative.addActionListener(this );
137: rbAbsolute.addActionListener(this );
138: if (chooser != null) {
139: chooser.addPropertyChangeListener(this );
140: }
141: if (sharedLibrariesFolder != null) {
142: copyTo.setText(sharedLibrariesFolder.getAbsolutePath());
143: }
144: enableAccessory(false);
145: if (!copyAllowed) {
146: rbCopy.setVisible(false);
147: copyTo.setVisible(false);
148: }
149: }
150:
151: public String[] getFiles() {
152: assert isRelative();
153: if (isCopy()) {
154: return copiedRelativeFiles
155: .toArray(new String[copiedRelativeFiles.size()]);
156: } else {
157: List<File> files = Arrays.asList(getSelectedFiles());
158: List<String> l = getRelativeFiles(files);
159: return l.toArray(new String[l.size()]);
160: }
161: }
162:
163: public boolean canApprove() {
164: if (!isCopy()) {
165: return true;
166: }
167: File f = FileUtil.normalizeFile(new File(copyTo.getText()));
168: if (!f.getPath().equals(sharedLibrariesFolder.getPath())
169: && !(f.getPath()).startsWith(sharedLibrariesFolder
170: .getPath()
171: + File.separatorChar)) {
172: DialogDisplayer.getDefault().notify(
173: new NotifyDescriptor.Message(MessageFormat.format(
174: NbBundle.getMessage(
175: FileChooserAccessory.class,
176: "FileChooserAccessory.warning1"), // NOI18N
177: new Object[] { sharedLibrariesFolder
178: .getPath() })));
179:
180: return false;
181: }
182: final File[] files = getSelectedFiles();
183: if (f.exists()) {
184: for (File file : files) {
185: File testFile = new File(f, file.getName());
186: if (testFile.exists()) {
187: if (NotifyDescriptor.YES_OPTION != DialogDisplayer
188: .getDefault()
189: .notify(
190: new NotifyDescriptor.Confirmation(
191: NbBundle
192: .getMessage(
193: FileChooserAccessory.class,
194: "FileChooserAccessory.warning3")))) {
195: return false;
196: }
197: break;
198: }
199: }
200: } else {
201: if (NotifyDescriptor.YES_OPTION != DialogDisplayer
202: .getDefault()
203: .notify(
204: new NotifyDescriptor.Confirmation(
205: MessageFormat
206: .format(
207: NbBundle
208: .getMessage(
209: FileChooserAccessory.class,
210: "FileChooserAccessory.warning2"), // NOI18N
211: new Object[] { f
212: .getPath() })))) {
213: return false;
214: }
215: }
216: for (File file : files) {
217: if (file.isDirectory()) {
218: if (NotifyDescriptor.YES_OPTION != DialogDisplayer
219: .getDefault()
220: .notify(
221: new NotifyDescriptor.Confirmation(
222: NbBundle
223: .getMessage(
224: FileChooserAccessory.class,
225: "FileChooserAccessory.warning4")))) { // NOI18N
226: return false;
227: }
228: break;
229: }
230: }
231:
232: return true;
233: }
234:
235: public void copyFilesIfNecessary() throws IOException {
236: if (!isCopy()) {
237: return;
238: }
239: File f = FileUtil.normalizeFile(new File(copyTo.getText()));
240: FileUtil.createFolder(f);
241: FileObject fo = FileUtil
242: .toFileObject(FileUtil.normalizeFile(f));
243: List<File> selectedFiles = Arrays.asList(getSelectedFiles());
244: copyFiles(selectedFiles, fo);
245: }
246:
247: private void enableAccessory(boolean enable) {
248: rbRelative.setEnabled(enable);
249: rbCopy.setEnabled(enable && copyAllowed);
250: rbAbsolute.setEnabled(enable);
251: copyTo.setEnabled(enable);
252: copyTo.setEditable(enable && rbCopy.isSelected());
253: }
254:
255: private File[] getSelectedFiles() {
256: if (usetThisFileInsteadOfOneFromChooser != null) {
257: return new File[] { usetThisFileInsteadOfOneFromChooser };
258: }
259: if (chooser.isMultiSelectionEnabled()) {
260: return chooser.getSelectedFiles();
261: } else {
262: if (chooser.getSelectedFile() != null) {
263: return new File[] { chooser.getSelectedFile() };
264: } else {
265: return new File[0];
266: }
267: }
268: }
269:
270: public boolean isRelative() {
271: return (rbRelative.isEnabled() && rbRelative.isSelected())
272: || isCopy();
273: }
274:
275: private boolean isCopy() {
276: return rbCopy.isEnabled() && rbCopy.isSelected();
277: }
278:
279: public void actionPerformed(ActionEvent e) {
280: copyTo.setEditable(e.getSource() == rbCopy);
281: }
282:
283: public void propertyChange(PropertyChangeEvent e) {
284: if (!(JFileChooser.SELECTED_FILE_CHANGED_PROPERTY.equals(e
285: .getPropertyName()) || JFileChooser.SELECTED_FILES_CHANGED_PROPERTY
286: .equals(e.getPropertyName()))) {
287: return;
288: }
289: File[] files = getSelectedFiles();
290: enableAccessory(files.length != 0);
291: update(Arrays.asList(files));
292: }
293:
294: private void update(List<File> files) {
295: StringBuffer absolute = new StringBuffer();
296: StringBuffer relative = new StringBuffer();
297: StringBuffer copy = new StringBuffer();
298: boolean isRelative = true;
299: for (File file : files) {
300: if (absolute.length() != 0) {
301: absolute.append(", ");
302: relative.append(", ");
303: if (file.getParentFile() != null
304: && file.getParentFile().getParentFile() != null
305: && file.getParentFile().getName().length() > 0) {
306: copy.setLength(0);
307: copy.append("/" + file.getParentFile().getName());
308: }
309: } else {
310: // first file:
311: if (file.getParentFile() != null
312: && file.getParentFile().getParentFile() != null
313: && file.getParentFile().getName().length() > 0) {
314: copy.append("/" + file.getParentFile().getName()
315: + "/" + file.getName());
316: } else {
317: copy.append("/");
318: }
319: }
320: absolute.append(file.getAbsolutePath());
321: String s = PropertyUtils.relativizeFile(baseFolder, file);
322: if (s == null) {
323: isRelative = false;
324: }
325: relative.append(s);
326: }
327: rbRelative.setEnabled(isRelative && rbRelative.isEnabled());
328: relativePath.setText(relative.toString());
329: relativePath.setCaretPosition(0);
330: relativePath.setToolTipText(relative.toString());
331: if (!isRelative) {
332: relativePath.setText("");
333: relativePath.setToolTipText("");
334: }
335: absolutePath.setText(absolute.toString());
336: absolutePath.setCaretPosition(0);
337: absolutePath.setToolTipText(absolute.toString());
338: }
339:
340: private List<String> getRelativeFiles(List<File> files) {
341: List<String> fs = new ArrayList<String>();
342: for (File file : files) {
343: String s = PropertyUtils.relativizeFile(baseFolder, file);
344: if (s != null) {
345: fs.add(s);
346: }
347: }
348: return fs;
349: }
350:
351: private void copyFiles(List<File> files, FileObject newRoot)
352: throws IOException {
353: List<File> fs = new ArrayList<File>();
354: for (File file : files) {
355: FileObject fo = FileUtil.toFileObject(file);
356: FileObject newFO;
357: if (fo.isFolder()) {
358: newFO = copyFolderRecursively(fo, newRoot);
359: } else {
360: FileObject foExists = newRoot.getFileObject(fo
361: .getName(), fo.getExt());
362: if (foExists != null) {
363: foExists.delete();
364: }
365: newFO = FileUtil.copyFile(fo, newRoot, fo.getName(), fo
366: .getExt());
367: }
368: fs.add(FileUtil.toFile(newFO));
369: }
370: copiedRelativeFiles = getRelativeFiles(fs);
371: }
372:
373: public static FileObject copyFolderRecursively(
374: FileObject sourceFolder, FileObject destination)
375: throws IOException {
376: assert sourceFolder.isFolder() : sourceFolder;
377: assert destination.isFolder() : destination;
378: FileObject destinationSubFolder = destination
379: .getFileObject(sourceFolder.getName());
380: if (destinationSubFolder == null) {
381: destinationSubFolder = destination
382: .createFolder(sourceFolder.getName());
383: }
384: for (FileObject fo : sourceFolder.getChildren()) {
385: if (fo.isFolder()) {
386: copyFolderRecursively(fo, destinationSubFolder);
387: } else {
388: FileObject foExists = destinationSubFolder
389: .getFileObject(fo.getName(), fo.getExt());
390: if (foExists != null) {
391: foExists.delete();
392: }
393: FileObject newFO = FileUtil
394: .copyFile(fo, destinationSubFolder, fo
395: .getName(), fo.getExt());
396: }
397: }
398: return destinationSubFolder;
399: }
400:
401: /** This method is called from within the constructor to
402: * initialize the form.
403: * WARNING: Do NOT modify this code. The content of this method is
404: * always regenerated by the Form Editor.
405: */
406: // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
407: private void initComponents() {
408:
409: buttonGroup1 = new javax.swing.ButtonGroup();
410: rbRelative = new javax.swing.JRadioButton();
411: relativePath = new javax.swing.JTextField();
412: rbCopy = new javax.swing.JRadioButton();
413: copyTo = new javax.swing.JTextField();
414: rbAbsolute = new javax.swing.JRadioButton();
415: absolutePath = new javax.swing.JTextField();
416:
417: setMinimumSize(new java.awt.Dimension(250, 139));
418: setPreferredSize(new java.awt.Dimension(250, 139));
419:
420: buttonGroup1.add(rbRelative);
421: rbRelative.setSelected(true);
422: rbRelative.setText(org.openide.util.NbBundle.getMessage(
423: FileChooserAccessory.class,
424: "FileChooserAccessory.rbRelative.text")); // NOI18N
425:
426: relativePath.setEditable(false);
427: relativePath.setText(null);
428:
429: buttonGroup1.add(rbCopy);
430: rbCopy.setText(org.openide.util.NbBundle.getMessage(
431: FileChooserAccessory.class,
432: "FileChooserAccessory.rbCopy.text")); // NOI18N
433:
434: copyTo.setEditable(false);
435: copyTo.setText(null);
436:
437: buttonGroup1.add(rbAbsolute);
438: rbAbsolute.setText(org.openide.util.NbBundle.getMessage(
439: FileChooserAccessory.class,
440: "FileChooserAccessory.rbAbsolute.text")); // NOI18N
441:
442: absolutePath.setEditable(false);
443: absolutePath.setText(null);
444:
445: org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(
446: this );
447: this .setLayout(layout);
448: layout
449: .setHorizontalGroup(layout
450: .createParallelGroup(
451: org.jdesktop.layout.GroupLayout.LEADING)
452: .add(
453: layout
454: .createSequentialGroup()
455: .add(
456: layout
457: .createParallelGroup(
458: org.jdesktop.layout.GroupLayout.LEADING)
459: .add(rbRelative)
460: .add(
461: layout
462: .createSequentialGroup()
463: .add(
464: 21,
465: 21,
466: 21)
467: .add(
468: relativePath,
469: org.jdesktop.layout.GroupLayout.DEFAULT_SIZE,
470: 219,
471: Short.MAX_VALUE))
472: .add(
473: rbCopy,
474: org.jdesktop.layout.GroupLayout.DEFAULT_SIZE,
475: 240,
476: Short.MAX_VALUE)
477: .add(
478: layout
479: .createSequentialGroup()
480: .add(
481: 21,
482: 21,
483: 21)
484: .add(
485: copyTo,
486: org.jdesktop.layout.GroupLayout.DEFAULT_SIZE,
487: 219,
488: Short.MAX_VALUE))
489: .add(rbAbsolute)
490: .add(
491: layout
492: .createSequentialGroup()
493: .add(
494: 21,
495: 21,
496: 21)
497: .add(
498: absolutePath,
499: org.jdesktop.layout.GroupLayout.DEFAULT_SIZE,
500: 219,
501: Short.MAX_VALUE)))
502: .addContainerGap()));
503: layout
504: .setVerticalGroup(layout
505: .createParallelGroup(
506: org.jdesktop.layout.GroupLayout.LEADING)
507: .add(
508: layout
509: .createSequentialGroup()
510: .add(rbRelative)
511: .addPreferredGap(
512: org.jdesktop.layout.LayoutStyle.RELATED)
513: .add(
514: relativePath,
515: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE,
516: org.jdesktop.layout.GroupLayout.DEFAULT_SIZE,
517: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
518: .addPreferredGap(
519: org.jdesktop.layout.LayoutStyle.RELATED)
520: .add(rbCopy)
521: .addPreferredGap(
522: org.jdesktop.layout.LayoutStyle.RELATED)
523: .add(
524: copyTo,
525: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE,
526: org.jdesktop.layout.GroupLayout.DEFAULT_SIZE,
527: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
528: .addPreferredGap(
529: org.jdesktop.layout.LayoutStyle.RELATED)
530: .add(rbAbsolute)
531: .addPreferredGap(
532: org.jdesktop.layout.LayoutStyle.RELATED)
533: .add(
534: absolutePath,
535: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE,
536: org.jdesktop.layout.GroupLayout.DEFAULT_SIZE,
537: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)));
538: }// </editor-fold>//GEN-END:initComponents
539:
540: // Variables declaration - do not modify//GEN-BEGIN:variables
541: private javax.swing.JTextField absolutePath;
542: private javax.swing.ButtonGroup buttonGroup1;
543: private javax.swing.JTextField copyTo;
544: private javax.swing.JRadioButton rbAbsolute;
545: private javax.swing.JRadioButton rbCopy;
546: private javax.swing.JRadioButton rbRelative;
547: private javax.swing.JTextField relativePath;
548: // End of variables declaration//GEN-END:variables
549:
550: }
|