001: /*BEGIN_COPYRIGHT_BLOCK
002: *
003: * Copyright (c) 2001-2007, JavaPLT group at Rice University (javaplt@rice.edu)
004: * All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions are met:
008: * * Redistributions of source code must retain the above copyright
009: * notice, this list of conditions and the following disclaimer.
010: * * Redistributions in binary form must reproduce the above copyright
011: * notice, this list of conditions and the following disclaimer in the
012: * documentation and/or other materials provided with the distribution.
013: * * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
014: * names of its contributors may be used to endorse or promote products
015: * derived from this software without specific prior written permission.
016: *
017: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
018: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
019: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
020: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
021: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
022: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
023: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
024: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
025: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
026: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
027: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028: *
029: * This software is Open Source Initiative approved Open Source Software.
030: * Open Source Initative Approved is a trademark of the Open Source Initiative.
031: *
032: * This file is part of DrJava. Download the current version of this project
033: * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
034: *
035: * END_COPYRIGHT_BLOCK*/
036:
037: package edu.rice.cs.drjava.ui;
038:
039: import javax.swing.*;
040: import javax.swing.event.*;
041: import javax.swing.border.EmptyBorder;
042:
043: import java.awt.event.*;
044: import java.awt.*;
045: import java.io.IOException;
046: import java.io.File;
047: import java.util.Vector;
048:
049: import edu.rice.cs.drjava.DrJava;
050: import edu.rice.cs.drjava.model.SingleDisplayModel;
051: import edu.rice.cs.drjava.config.*;
052: import edu.rice.cs.drjava.ui.config.*;
053:
054: import edu.rice.cs.plt.io.IOUtil;
055: import edu.rice.cs.plt.iter.IterUtil;
056: import edu.rice.cs.util.swing.FileSelectorComponent;
057: import edu.rice.cs.util.swing.DirectorySelectorComponent;
058: import edu.rice.cs.util.swing.DirectoryChooser;
059: import edu.rice.cs.util.swing.FileChooser;
060: import edu.rice.cs.util.swing.Utilities;
061:
062: import javax.swing.filechooser.FileFilter;
063:
064: /** A frame for setting Project Preferences */
065: public class ProjectPropertiesFrame extends JFrame {
066:
067: private static final int FRAME_WIDTH = 503;
068: private static final int FRAME_HEIGHT = 318;
069:
070: private MainFrame _mainFrame;
071: private SingleDisplayModel _model;
072: private File _projFile;
073:
074: private final JButton _okButton;
075: private final JButton _applyButton;
076: private final JButton _cancelButton;
077: // private JButton _saveSettingsButton;
078: private JPanel _mainPanel;
079:
080: private DirectorySelectorComponent _projRootSelector;
081: private DirectorySelectorComponent _buildDirSelector;
082: private DirectorySelectorComponent _workDirSelector;
083: private FileSelectorComponent _mainDocumentSelector;
084:
085: private FileSelectorComponent _jarFileSelector;
086: private FileSelectorComponent _manifestFileSelector;
087:
088: private VectorFileOptionComponent _extraClassPathList;
089:
090: /** Constructs project properties frame for a new project and displays it. Assumes that a project is active. */
091: public ProjectPropertiesFrame(MainFrame mf) {
092: super ("Project Properties");
093:
094: // Utilities.show("ProjectPropertiesFrame(" + mf + ", " + projFile + ")");
095:
096: _mainFrame = mf;
097: _model = _mainFrame.getModel();
098: _projFile = _model.getProjectFile();
099: _mainPanel = new JPanel();
100:
101: Action okAction = new AbstractAction("OK") {
102: public void actionPerformed(ActionEvent e) {
103: // Always apply and save settings
104: boolean successful = true;
105: successful = saveSettings();
106: if (successful)
107: ProjectPropertiesFrame.this .setVisible(false);
108: reset();
109: }
110: };
111: _okButton = new JButton(okAction);
112:
113: Action applyAction = new AbstractAction("Apply") {
114: public void actionPerformed(ActionEvent e) {
115: // Always save settings
116: saveSettings();
117: reset();
118: }
119: };
120: _applyButton = new JButton(applyAction);
121:
122: Action cancelAction = new AbstractAction("Cancel") {
123: public void actionPerformed(ActionEvent e) {
124: cancel();
125: }
126: };
127: _cancelButton = new JButton(cancelAction);
128:
129: init();
130: }
131:
132: /** Initializes the components in this frame. */
133: private void init() {
134: _setupPanel(_mainPanel);
135: JScrollPane scrollPane = new JScrollPane(_mainPanel);
136: Container cp = getContentPane();
137:
138: GridBagLayout cpLayout = new GridBagLayout();
139: GridBagConstraints c = new GridBagConstraints();
140: cp.setLayout(cpLayout);
141:
142: c.fill = GridBagConstraints.BOTH;
143: c.anchor = GridBagConstraints.NORTH;
144: c.gridwidth = GridBagConstraints.REMAINDER;
145: c.gridheight = GridBagConstraints.RELATIVE;
146: c.weightx = 1.0;
147: c.weighty = 1.0;
148: cpLayout.setConstraints(scrollPane, c);
149: cp.add(scrollPane);
150:
151: // Add buttons
152: JPanel bottom = new JPanel();
153: bottom.setBorder(new EmptyBorder(5, 5, 5, 5));
154: bottom.setLayout(new BoxLayout(bottom, BoxLayout.X_AXIS));
155: bottom.add(Box.createHorizontalGlue());
156: bottom.add(_applyButton);
157: bottom.add(_okButton);
158: bottom.add(_cancelButton);
159: bottom.add(Box.createHorizontalGlue());
160:
161: c.fill = GridBagConstraints.NONE;
162: c.anchor = GridBagConstraints.SOUTH;
163: c.gridheight = GridBagConstraints.REMAINDER;
164: c.weighty = 0.0;
165: cpLayout.setConstraints(bottom, c);
166: cp.add(bottom);
167:
168: // Set all dimensions ----
169: setSize(FRAME_WIDTH, FRAME_HEIGHT);
170: MainFrame.setPopupLoc(this , _mainFrame);
171:
172: addWindowListener(new WindowAdapter() {
173: public void windowClosing(java.awt.event.WindowEvent e) {
174: cancel();
175: }
176: });
177:
178: reset();
179: }
180:
181: /** Resets the frame and hides it. */
182: public void cancel() {
183: reset();
184: _applyButton.setEnabled(false);
185: ProjectPropertiesFrame.this .setVisible(false);
186: }
187:
188: public void reset() {
189: reset(_model.getProjectRoot());
190: }
191:
192: private void reset(File projRoot) {
193: // Utilities.show("reset(" + projRoot + ")");
194: _projRootSelector.setFileField(projRoot);
195:
196: final File bd = _model.getBuildDirectory();
197: final JTextField bdTextField = _buildDirSelector.getFileField();
198: if (bd == null)
199: bdTextField.setText("");
200: else
201: _buildDirSelector.setFileField(bd);
202:
203: final File wd = _model.getWorkingDirectory();
204: final JTextField wdTextField = _workDirSelector.getFileField();
205: if (wd == null)
206: wdTextField.setText("");
207: else
208: _workDirSelector.setFileField(wd);
209:
210: final File mc = _model.getMainClass();
211: final JTextField mcTextField = _mainDocumentSelector
212: .getFileField();
213: if (mc == null)
214: mcTextField.setText("");
215: else
216: _mainDocumentSelector.setFileField(mc);
217:
218: Vector<File> cp = new Vector<File>(IterUtil.asList(_model
219: .getExtraClassPath()));
220: _extraClassPathList.setValue(cp);
221: _applyButton.setEnabled(false);
222: }
223:
224: /** Caches the settings in the global model */
225: public boolean saveSettings() {//throws IOException {
226: boolean projRootChanged = false;
227:
228: File pr = _projRootSelector.getFileFromField();
229: if (_projRootSelector.getFileField().getText().equals("")) {
230: pr = null;
231: } else {
232: if (!pr.equals(_model.getProjectRoot())) {
233: _model.setProjectRoot(pr);
234: projRootChanged = true;
235: }
236: }
237:
238: File bd = _buildDirSelector.getFileFromField();
239: if (_buildDirSelector.getFileField().getText().equals(""))
240: bd = null;
241: _model.setBuildDirectory(bd);
242:
243: File wd = _workDirSelector.getFileFromField();
244: if (_workDirSelector.getFileField().getText().equals(""))
245: wd = null;
246: _model.setWorkingDirectory(wd);
247:
248: File mc = _mainDocumentSelector.getFileFromField();
249: if (_mainDocumentSelector.getFileField().getText().equals(""))
250: mc = null;
251: _model.setMainClass(mc);
252:
253: Vector<File> extras = _extraClassPathList.getValue();
254: _model.setExtraClassPath(IterUtil.snapshot(extras));
255:
256: // _mainFrame.saveProject();
257: if (projRootChanged) {
258: try {
259: _model.reloadProject(_mainFrame.getCurrentProject(),
260: _mainFrame.gatherProjectDocInfo());
261: } catch (IOException e) {
262: throw new edu.rice.cs.util.UnexpectedException(e,
263: "I/O error while reloading project");
264: }
265: }
266: return true;
267: }
268:
269: /** Returns the current project root in the project profile. */
270: private File _getProjRoot() {
271: File projRoot = _mainFrame.getModel().getProjectRoot();
272: if (projRoot != null)
273: return projRoot;
274: return FileOption.NULL_FILE;
275: }
276:
277: /** Returns the current build directory in the project profile. */
278: private File _getBuildDir() {
279: File buildDir = _mainFrame.getModel().getBuildDirectory();
280: if (buildDir != null)
281: return buildDir;
282: return FileOption.NULL_FILE;
283: }
284:
285: /** Returns the current working directory in the project profile (FileOption.NULL_FILE if none is set) */
286: private File _getWorkDir() {
287: File workDir = _mainFrame.getModel().getWorkingDirectory();
288: if (workDir != null)
289: return workDir;
290: return FileOption.NULL_FILE;
291: }
292:
293: /** Returns the current working directory in the project profile (FileOption.NULL_FILE if none is set) */
294: private File _getMainFile() {
295: File mainFile = _mainFrame.getModel().getMainClass();
296: if (mainFile != null)
297: return mainFile;
298: return FileOption.NULL_FILE;
299: }
300:
301: private void _setupPanel(JPanel panel) {
302: GridBagLayout gridbag = new GridBagLayout();
303: GridBagConstraints c = new GridBagConstraints();
304: panel.setLayout(gridbag);
305: c.fill = GridBagConstraints.HORIZONTAL;
306: Insets labelInsets = new Insets(5, 10, 0, 0);
307: Insets compInsets = new Insets(5, 5, 0, 10);
308:
309: // Project Root
310:
311: c.weightx = 0.0;
312: c.gridwidth = 1;
313: c.insets = labelInsets;
314:
315: JLabel prLabel = new JLabel("Project Root");
316: prLabel
317: .setToolTipText("<html>The root directory for the project source files .<br>"
318: + "If not specified, the parent directory of the project file.</html>");
319: gridbag.setConstraints(prLabel, c);
320:
321: panel.add(prLabel);
322: c.weightx = 1.0;
323: c.gridwidth = GridBagConstraints.REMAINDER;
324: c.insets = compInsets;
325:
326: JPanel prPanel = _projRootPanel();
327: gridbag.setConstraints(prPanel, c);
328: panel.add(prPanel);
329:
330: // Build Directory
331:
332: c.weightx = 0.0;
333: c.gridwidth = 1;
334: c.insets = labelInsets;
335:
336: JLabel bdLabel = new JLabel("Build Directory");
337: bdLabel
338: .setToolTipText("<html>The directory the class files will be compiled into.<br>"
339: + "If not specified, the class files will be compiled into<br>"
340: + "the same directory as their corresponding source files</html>");
341: gridbag.setConstraints(bdLabel, c);
342:
343: panel.add(bdLabel);
344: c.weightx = 1.0;
345: c.gridwidth = GridBagConstraints.REMAINDER;
346: c.insets = compInsets;
347:
348: JPanel bdPanel = _buildDirectoryPanel();
349: gridbag.setConstraints(bdPanel, c);
350: panel.add(bdPanel);
351:
352: // Working Directory
353:
354: c.weightx = 0.0;
355: c.gridwidth = 1;
356: c.insets = labelInsets;
357:
358: JLabel wdLabel = new JLabel("Working Directory");
359: wdLabel
360: .setToolTipText("<html>The root directory for relative path names.</html>");
361: gridbag.setConstraints(wdLabel, c);
362:
363: panel.add(wdLabel);
364: c.weightx = 1.0;
365: c.gridwidth = GridBagConstraints.REMAINDER;
366: c.insets = compInsets;
367:
368: JPanel wdPanel = _workDirectoryPanel();
369: gridbag.setConstraints(wdPanel, c);
370: panel.add(wdPanel);
371:
372: // Main Document file
373:
374: c.weightx = 0.0;
375: c.gridwidth = 1;
376: c.insets = labelInsets;
377:
378: JLabel classLabel = new JLabel("Main Document");
379: classLabel
380: .setToolTipText("<html>The project document containing the<br>"
381: + "<code>main</code>method for the entire project</html>");
382: gridbag.setConstraints(classLabel, c);
383: panel.add(classLabel);
384:
385: c.weightx = 1.0;
386: c.gridwidth = GridBagConstraints.REMAINDER;
387: c.insets = compInsets;
388:
389: JPanel mainClassPanel = _mainDocumentSelector();
390: gridbag.setConstraints(mainClassPanel, c);
391: panel.add(mainClassPanel);
392:
393: c.weightx = 0.0;
394: c.gridwidth = 1;
395: c.insets = labelInsets;
396:
397: // ExtraProjectClasspaths
398: JLabel extrasLabel = new JLabel("Extra Classpath");
399: extrasLabel
400: .setToolTipText("<html>The list of extra classpaths to load with the project.<br>"
401: + "This may include either JAR files or directories. Any<br>"
402: + "classes defined in these classpath locations will be <br>"
403: + "visible in the interactions pane and also accessible <br>"
404: + "by the compiler when compiling the project.</html>");
405: gridbag.setConstraints(extrasLabel, c);
406: panel.add(extrasLabel);
407:
408: c.weightx = 1.0;
409: c.gridwidth = GridBagConstraints.REMAINDER;
410: c.insets = compInsets;
411:
412: Component extrasComponent = _extraClassPathComponent();
413: gridbag.setConstraints(extrasComponent, c);
414: panel.add(extrasComponent);
415: }
416:
417: private DocumentListener _applyListener = new DocumentListener() {
418: public void insertUpdate(DocumentEvent e) {
419: setEnabled();
420: }
421:
422: public void removeUpdate(DocumentEvent e) {
423: setEnabled();
424: }
425:
426: public void changedUpdate(DocumentEvent e) {
427: setEnabled();
428: }
429:
430: private void setEnabled() {
431: Utilities.invokeLater(new Runnable() {
432: public void run() {
433: _applyButton.setEnabled(true);
434: }
435: });
436: }
437: };
438:
439: public JPanel _projRootPanel() {
440: DirectoryChooser dirChooser = new DirectoryChooser(this );
441: dirChooser.setSelectedFile(_getProjRoot());
442: dirChooser.setDialogTitle("Select Project Root Folder");
443: dirChooser.setApproveButtonText("Select");
444: // dirChooser.setEditable(true);
445: _projRootSelector = new DirectorySelectorComponent(this ,
446: dirChooser, 20, 12f);
447: //toReturn.add(_buildDirSelector, BorderLayout.EAST);
448:
449: _projRootSelector.getFileField().getDocument()
450: .addDocumentListener(_applyListener);
451:
452: return _projRootSelector;
453: }
454:
455: public JPanel _buildDirectoryPanel() {
456: DirectoryChooser dirChooser = new DirectoryChooser(this );
457: File bd = _getBuildDir();
458: if (bd == null || bd == FileOption.NULL_FILE)
459: bd = _getProjRoot();
460: dirChooser.setSelectedFile(bd);
461: dirChooser.setDialogTitle("Select Build Directory");
462: dirChooser.setApproveButtonText("Select");
463: // dirChooser.setEditable(true);
464: // (..., false); since build directory does not have to exist
465: _buildDirSelector = new DirectorySelectorComponent(this ,
466: dirChooser, 20, 12f, false);
467: _buildDirSelector.setFileField(bd); // the file field is used as the initial file selection
468: //toReturn.add(_buildDirSelector, BorderLayout.EAST);
469:
470: _buildDirSelector.getFileField().getDocument()
471: .addDocumentListener(_applyListener);
472:
473: return _buildDirSelector;
474: }
475:
476: public JPanel _workDirectoryPanel() {
477: DirectoryChooser dirChooser = new DirectoryChooser(this );
478: dirChooser.setSelectedFile(_getWorkDir());
479: dirChooser.setDialogTitle("Select Working Directory");
480: dirChooser.setApproveButtonText("Select");
481: // dirChooser.setEditable(true);
482: _workDirSelector = new DirectorySelectorComponent(this ,
483: dirChooser, 20, 12f);
484: //toReturn.add(_buildDirSelector, BorderLayout.EAST);
485:
486: _workDirSelector.getFileField().getDocument()
487: .addDocumentListener(_applyListener);
488: return _workDirSelector;
489: }
490:
491: public Component _extraClassPathComponent() {
492: _extraClassPathList = new VectorFileOptionComponent(null,
493: "Extra Project Classpaths", this );
494: _extraClassPathList
495: .addChangeListener(new OptionComponent.ChangeListener() {
496: public Object apply(Object oc) {
497: _applyButton.setEnabled(true);
498: return null;
499: }
500: });
501: return _extraClassPathList.getComponent();
502: }
503:
504: public JPanel _mainDocumentSelector() {
505: final File projRoot = _getProjRoot();
506:
507: FileChooser chooser = new FileChooser(projRoot);
508: chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
509: chooser.setDialogType(JFileChooser.CUSTOM_DIALOG);
510:
511: chooser.setDialogTitle("Select Main Document");
512: // Utilities.show("Main Document Root is: " + root);
513: chooser.setCurrentDirectory(projRoot);
514: File mainFile = _getMainFile();
515: if (mainFile != FileOption.NULL_FILE)
516: chooser.setSelectedFile(mainFile);
517:
518: chooser.setApproveButtonText("Select");
519:
520: FileFilter filter = new FileFilter() {
521: public boolean accept(File f) {
522: String name = f.getName();
523: return IOUtil.isMember(f, projRoot)
524: && (f.isDirectory() || (name.endsWith(".java")
525: || name.endsWith(".dj0")
526: || name.endsWith(".dj1") || name
527: .endsWith(".dj2")));
528: }
529:
530: public String getDescription() {
531: return "Java & DrJava Files (*.java, *.dj0, *.dj1, *.dj2) in project";
532: }
533: };
534:
535: chooser.addChoosableFileFilter(filter);
536: _mainDocumentSelector = new FileSelectorComponent(this ,
537: chooser, 20, 12f);
538:
539: _mainDocumentSelector.getFileField().getDocument()
540: .addDocumentListener(_applyListener);
541: return _mainDocumentSelector;
542: }
543:
544: public JPanel _manifestFileSelector() {
545: JFileChooser fileChooser = new JFileChooser(_getProjRoot()
546: .getParentFile());
547: fileChooser.setDialogTitle("Select Output jar File");
548: fileChooser.setApproveButtonText("Select");
549: fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
550: fileChooser.setMultiSelectionEnabled(false);
551: _manifestFileSelector = new FileSelectorComponent(this ,
552: fileChooser, 20, 12f);
553:
554: _manifestFileSelector.setFileFilter(new FileFilter() {
555: public boolean accept(File f) {
556: return f.getName().endsWith(".jar") || f.isDirectory();
557: }
558:
559: public String getDescription() {
560: return "Java Archive Files (*.jar)";
561: }
562: });
563: //toReturn.add(_buildDirSelector, BorderLayout.EAST);
564: return _manifestFileSelector;
565: }
566:
567: public JPanel _jarFileSelector() {
568: JFileChooser fileChooser = new JFileChooser(_getProjRoot());
569: fileChooser.setDialogTitle("Select Manifest File");
570: fileChooser.setApproveButtonText("Select");
571: fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
572: fileChooser.setMultiSelectionEnabled(false);
573: _jarFileSelector = new FileSelectorComponent(this , fileChooser,
574: 20, 12f);
575: _jarFileSelector.setFileFilter(new FileFilter() {
576: public boolean accept(File f) {
577: return f.getName().endsWith(".jar") || f.isDirectory();
578: }
579:
580: public String getDescription() {
581: return "Java Archive Files (*.jar)";
582: }
583: });
584: //toReturn.add(_buildDirSelector, BorderLayout.EAST);
585: return _jarFileSelector;
586: }
587:
588: //public void setVisible(boolean vis) {
589: //super.setVisible(vis);
590: //reset();
591: //}
592: }
|