001: /*
002: * FindBugs - Find Bugs in Java programs
003: * Copyright (C) 2006, University of Maryland
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307, USA
018: */
019:
020: package edu.umd.cs.findbugs.gui2;
021:
022: import java.awt.BorderLayout;
023: import java.awt.Dimension;
024: import java.awt.GridBagConstraints;
025: import java.awt.GridBagLayout;
026: import java.awt.GridLayout;
027: import java.awt.Insets;
028: import java.awt.event.ActionEvent;
029: import java.awt.event.ActionListener;
030: import java.io.File;
031: import java.util.List;
032:
033: import javax.swing.Box;
034: import javax.swing.BoxLayout;
035: import javax.swing.DefaultListModel;
036: import javax.swing.JButton;
037: import javax.swing.JComponent;
038: import javax.swing.JFileChooser;
039: import javax.swing.JLabel;
040: import javax.swing.JList;
041: import javax.swing.JOptionPane;
042: import javax.swing.JPanel;
043: import javax.swing.JScrollPane;
044: import javax.swing.JSeparator;
045: import javax.swing.JTextField;
046: import javax.swing.SwingUtilities;
047: import javax.swing.border.EmptyBorder;
048: import javax.swing.filechooser.FileFilter;
049:
050: import edu.umd.cs.findbugs.Project;
051: import edu.umd.cs.findbugs.ba.SourceFinder;
052:
053: /**
054: * The User Interface for creating a Project and editing it after the fact.
055: * @author Reuven
056: *
057: */
058: @SuppressWarnings("serial")
059: public class NewProjectWizard extends FBDialog {
060: private EmptyBorder border = new EmptyBorder(5, 5, 5, 5);
061:
062: private Project project;
063: private boolean projectChanged = false;
064: private FBFileChooser chooser = new FBFileChooser();
065: private FileFilter directoryOrArchive = new FileFilter() {
066:
067: @Override
068: public boolean accept(File f) {
069: String fileName = f.getName().toLowerCase();
070: return f.isDirectory() || fileName.endsWith(".jar")
071: || fileName.endsWith(".ear")
072: || fileName.endsWith(".war")
073: || fileName.endsWith(".zip")
074: || fileName.endsWith(".sar")
075: || fileName.endsWith(".class");
076: }
077:
078: @Override
079: public String getDescription() {
080: return edu.umd.cs.findbugs.L10N.getLocalString(
081: "file.accepted_extensions",
082: "Class archive files (*.class, *.[jwes]ar, *.zip)");
083: }
084: };
085:
086: private JList analyzeList = new JList();
087: private DefaultListModel analyzeModel = new DefaultListModel();
088:
089: private JTextField projectName = new JTextField();
090: private JList auxList = new JList();
091: private DefaultListModel auxModel = new DefaultListModel();
092:
093: private JList sourceList = new JList();
094: private DefaultListModel sourceModel = new DefaultListModel();
095:
096: private JButton finishButton = new JButton(edu.umd.cs.findbugs.L10N
097: .getLocalString("dlg.finish_btn", "Finish"));
098: private JButton cancelButton = new JButton(edu.umd.cs.findbugs.L10N
099: .getLocalString("dlg.cancel_btn", "Cancel"));
100:
101: private JComponent[] wizardComponents = new JComponent[3];
102: private int currentPanel;
103:
104: public NewProjectWizard() {
105: this (null);
106: finishButton.setEnabled(false);
107: }
108:
109: /**
110: * @param curProject the project to populate from, or null to start a new one
111: */
112: public NewProjectWizard(Project curProject) {
113: project = curProject;
114: boolean temp = false;
115:
116: if (curProject == null)
117: setTitle(edu.umd.cs.findbugs.L10N.getLocalString(
118: "dlg.new_item", "New Project"));
119: else {
120: setTitle(edu.umd.cs.findbugs.L10N.getLocalString(
121: "dlg.reconfig", "Reconfigure"));
122: temp = true;
123: }
124:
125: final boolean reconfig = temp;
126:
127: JPanel mainPanel = new JPanel();
128: mainPanel.setLayout(new GridLayout(3, 1));
129:
130: wizardComponents[0] = createFilePanel(edu.umd.cs.findbugs.L10N
131: .getLocalString("dlg.class_jars_dirs_lbl",
132: "Class archives and directories to analyze:"),
133: analyzeList, analyzeModel,
134: JFileChooser.FILES_AND_DIRECTORIES, directoryOrArchive);
135:
136: wizardComponents[1] = createFilePanel(edu.umd.cs.findbugs.L10N
137: .getLocalString("dlg.aux_class_lbl",
138: "Auxiliary class locations:"), auxList,
139: auxModel, JFileChooser.FILES_AND_DIRECTORIES,
140: directoryOrArchive);
141:
142: wizardComponents[2] = createFilePanel(edu.umd.cs.findbugs.L10N
143: .getLocalString("dlg.source_dirs_lbl",
144: "Source directories:"), sourceList,
145: sourceModel, JFileChooser.FILES_AND_DIRECTORIES, null);
146:
147: JPanel buttons = new JPanel();
148: buttons.setLayout(new BoxLayout(buttons, BoxLayout.X_AXIS));
149: if (MainFrame.isMacLookAndFeel()) {
150: buttons.add(Box.createHorizontalStrut(5));
151: buttons.add(cancelButton);
152: buttons.add(Box.createHorizontalStrut(5));
153: buttons.add(finishButton);
154: } else {
155: buttons.add(Box.createHorizontalStrut(5));
156: buttons.add(finishButton);
157: buttons.add(Box.createHorizontalStrut(5));
158: buttons.add(cancelButton);
159: }
160: finishButton.addActionListener(new ActionListener() {
161: boolean keepGoing = false;
162:
163: private boolean displayWarningAndAskIfWeShouldContinue(
164: String msg, String title) {
165: if (keepGoing)
166: return true;
167: boolean result = JOptionPane.showConfirmDialog(
168: NewProjectWizard.this , msg, title,
169: JOptionPane.OK_CANCEL_OPTION,
170: JOptionPane.WARNING_MESSAGE) == JOptionPane.OK_OPTION;
171: if (result)
172: keepGoing = true;
173: return result;
174:
175: }
176:
177: public void actionPerformed(ActionEvent evt) {
178:
179: for (int i = 0; i < analyzeModel.getSize(); i++) {
180: File temp = new File((String) analyzeModel.get(i));
181: if (!temp.exists()
182: && directoryOrArchive.accept(temp)) {
183: if (!displayWarningAndAskIfWeShouldContinue(
184: temp.getName()
185: + " "
186: + edu.umd.cs.findbugs.L10N
187: .getLocalString(
188: "dlg.invalid_txt",
189: " is invalid."),
190: edu.umd.cs.findbugs.L10N
191: .getLocalString(
192: "dlg.error_ttl",
193: "Can't locate file")))
194: return;
195:
196: }
197: }
198:
199: for (int i = 0; i < sourceModel.getSize(); i++) {
200: File temp = new File((String) sourceModel.get(i));
201: if (!temp.exists()
202: && directoryOrArchive.accept(temp)) {
203: if (!displayWarningAndAskIfWeShouldContinue(
204: temp.getName()
205: + " "
206: + edu.umd.cs.findbugs.L10N
207: .getLocalString(
208: "dlg.invalid_txt",
209: " is invalid."),
210: edu.umd.cs.findbugs.L10N
211: .getLocalString(
212: "dlg.error_ttl",
213: "Can't locate file")))
214: return;
215: }
216: }
217: for (int i = 0; i < auxModel.getSize(); i++) {
218: File temp = new File((String) auxModel.get(i));
219: if (!temp.exists()
220: && directoryOrArchive.accept(temp)) {
221: if (!displayWarningAndAskIfWeShouldContinue(
222: temp.getName()
223: + " "
224: + edu.umd.cs.findbugs.L10N
225: .getLocalString(
226: "dlg.invalid_txt",
227: " is invalid."),
228: edu.umd.cs.findbugs.L10N
229: .getLocalString(
230: "dlg.error_ttl",
231: "Can't locate file")))
232: return;
233: }
234: }
235: Project p;
236: boolean resetSettings;
237: if (project == null) {
238: p = new Project();
239: resetSettings = true;
240: } else {
241: p = project;
242: resetSettings = false;
243: }
244: //First clear p's old files, otherwise we can't remove a file once an analysis has been performed on it
245: int numOldFiles = p.getFileCount();
246: for (int x = 0; x < numOldFiles; x++)
247: p.removeFile(0);
248:
249: int numOldAuxFiles = p.getNumAuxClasspathEntries();
250: for (int x = 0; x < numOldAuxFiles; x++)
251: p.removeAuxClasspathEntry(0);
252:
253: int numOldSrc = p.getNumSourceDirs();
254: for (int x = 0; x < numOldSrc; x++)
255: p.removeSourceDir(0);
256:
257: //Now that p is cleared, we can add in all the correct files.
258: for (int i = 0; i < analyzeModel.getSize(); i++)
259: p.addFile((String) analyzeModel.get(i));
260: for (int i = 0; i < auxModel.getSize(); i++)
261: p.addAuxClasspathEntry((String) auxModel.get(i));
262: for (int i = 0; i < sourceModel.getSize(); i++)
263: p.addSourceDir((String) sourceModel.get(i));
264: p.setProjectName(projectName.getText());
265: if (keepGoing) {
266: MainFrame.getInstance().setProject(p);
267: List<String> possibleDirectories = p
268: .getSourceDirList();
269: MainFrame.getInstance().setSourceFinder(
270: new SourceFinder());
271: MainFrame.getInstance().getSourceFinder()
272: .setSourceBaseList(possibleDirectories);
273: } else if (project == null
274: || (projectChanged && JOptionPane
275: .showConfirmDialog(
276: NewProjectWizard.this ,
277: edu.umd.cs.findbugs.L10N
278: .getLocalString(
279: "dlg.project_settings_changed_lbl",
280: "Project settings have been changed. Perform a new analysis with the changed files?"),
281: edu.umd.cs.findbugs.L10N
282: .getLocalString(
283: "dlg.redo_analysis_question_lbl",
284: "Redo analysis?"),
285: JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION))
286: new AnalyzingDialog(p, resetSettings);
287:
288: if (reconfig == true)
289: MainFrame.getInstance().setProjectChanged(true);
290:
291: String name = p.getProjectName();
292: if (name == null) {
293: name = Project.UNNAMED_PROJECT;
294: Debug.println("PROJECT NAME IS NULL!!");
295: }
296: MainFrame.getInstance().setTitle(
297: MainFrame.TITLE_START_TXT + name);
298:
299: dispose();
300: }
301: });
302: cancelButton.addActionListener(new ActionListener() {
303: public void actionPerformed(ActionEvent evt) {
304: dispose();
305: }
306: });
307:
308: JPanel south = new JPanel(new BorderLayout());
309: south.add(new JSeparator(), BorderLayout.NORTH);
310: south.add(buttons, BorderLayout.EAST);
311:
312: if (curProject != null) {
313: for (String i : curProject.getFileList())
314: analyzeModel.addElement(i);
315: //If the project had no classes in it, disable the finish button until classes are added.
316: if (curProject.getFileList().size() == 0)
317: this .finishButton.setEnabled(false);
318: for (String i : curProject.getAuxClasspathEntryList())
319: auxModel.addElement(i);
320: for (String i : curProject.getSourceDirList())
321: sourceModel.addElement(i);
322: projectName.setText(curProject.getProjectName());
323: } else {
324: //If project is null, disable finish button until classes are added
325: finishButton.setEnabled(false);
326: }
327:
328: //loadPanel(0);
329: loadAllPanels(mainPanel);
330: add(mainPanel, BorderLayout.CENTER);
331: add(south, BorderLayout.SOUTH);
332: add(createTextFieldPanel("Project name (i.e., description)",
333: projectName), BorderLayout.NORTH);
334:
335: setDefaultCloseOperation(DISPOSE_ON_CLOSE);
336:
337: // pack();
338: setModal(true);
339: setVisible(true);
340: }
341:
342: private JComponent createTextFieldPanel(String label,
343: JTextField textField) {
344: JPanel myPanel = new JPanel(new BorderLayout());
345:
346: myPanel.add(new JLabel(label), BorderLayout.NORTH);
347: myPanel.add(textField, BorderLayout.CENTER);
348:
349: return myPanel;
350: }
351:
352: /**
353: * @param label TODO
354: *
355: */
356: private JPanel createFilePanel(final String label,
357: final JList list, final DefaultListModel listModel,
358: final int fileSelectionMode, final FileFilter filter) {
359: JPanel myPanel = new JPanel(new GridBagLayout());
360: GridBagConstraints gbc = new GridBagConstraints();
361: gbc.gridx = 0;
362: gbc.gridy = 0;
363: gbc.gridheight = 1;
364: gbc.gridwidth = 2;
365: gbc.weightx = 1;
366: gbc.weighty = 0;
367: gbc.anchor = GridBagConstraints.WEST;
368: myPanel.add(new JLabel(label), gbc);
369: gbc.gridx = 0;
370: gbc.gridy = 1;
371: gbc.gridheight = 3;
372: gbc.gridwidth = 1;
373: gbc.weightx = 1;
374: gbc.weighty = 1;
375: gbc.fill = GridBagConstraints.BOTH;
376: myPanel.add(new JScrollPane(list), gbc);
377: list.setModel(listModel);
378: gbc.gridx = 1;
379: gbc.gridy = 1;
380: gbc.gridheight = 1;
381: gbc.gridwidth = 1;
382: gbc.weightx = 0;
383: gbc.weighty = 0;
384: gbc.fill = GridBagConstraints.HORIZONTAL;
385: final JButton addButton = new JButton(edu.umd.cs.findbugs.L10N
386: .getLocalString("dlg.add_btn", "Add"));
387: myPanel.add(addButton, gbc);
388: gbc.gridx = 1;
389: gbc.gridy = 2;
390: gbc.insets = new Insets(5, 0, 0, 0);
391: final JButton removeButton = new JButton(
392: edu.umd.cs.findbugs.L10N.getLocalString(
393: "dlg.remove_btn", "Remove"));
394: myPanel.add(removeButton, gbc);
395: gbc.gridx = 1;
396: gbc.gridy = 3;
397: gbc.insets = new Insets(0, 0, 0, 0);
398: myPanel.add(Box.createGlue(), gbc);
399: myPanel.setBorder(border);
400: addButton.addActionListener(new ActionListener() {
401: public void actionPerformed(ActionEvent evt) {
402: chooser.setFileSelectionMode(fileSelectionMode);
403: chooser.setMultiSelectionEnabled(true);
404:
405: //Removes all the file filters currently in the chooser.
406: for (FileFilter ff : chooser.getChoosableFileFilters()) {
407: chooser.removeChoosableFileFilter(ff);
408: }
409:
410: chooser.setFileFilter(filter);
411:
412: if (chooser.showOpenDialog(NewProjectWizard.this ) == JFileChooser.APPROVE_OPTION) {
413: File[] selectedFiles = chooser.getSelectedFiles();
414: for (File selectedFile : selectedFiles) {
415: listModel.addElement(selectedFile
416: .getAbsolutePath());
417: }
418: projectChanged = true;
419: // If this is the primary class directories add button, set it to enable the finish button of the main dialog
420: if (label
421: .equals(edu.umd.cs.findbugs.L10N
422: .getLocalString(
423: "dlg.class_jars_dirs_lbl",
424: "Class archives and directories to analyze:")))
425: finishButton.setEnabled(true);
426: }
427: }
428: });
429: removeButton.addActionListener(new ActionListener() {
430: public void actionPerformed(ActionEvent evt) {
431: if (list.getSelectedValues().length > 0)
432: projectChanged = true;
433: for (Object i : list.getSelectedValues())
434: listModel.removeElement(i);
435: //If this is the primary class directories remove button, set it to disable finish when there are no class files being analyzed
436: if (listModel.size() == 0
437: && label
438: .equals(edu.umd.cs.findbugs.L10N
439: .getLocalString(
440: "dlg.class_jars_dirs_lbl",
441: "Class archives and directories to analyze:")))
442: finishButton.setEnabled(false);
443: }
444: });
445: return myPanel;
446: }
447:
448: /*
449: private void loadPanel(final int index)
450: {
451: SwingUtilities.invokeLater(new Runnable()
452: {
453: public void run()
454: {
455: remove(wizardPanels[currentPanel]);
456: currentPanel = index;
457: add(wizardPanels[index], BorderLayout.CENTER);
458: backButton.setEnabled(index > 0);
459: nextButton.setEnabled(index < wizardPanels.length - 1);
460: validate();
461: repaint();
462: }
463: });
464: }
465: */
466: private void loadAllPanels(final JPanel mainPanel) {
467: SwingUtilities.invokeLater(new Runnable() {
468: public void run() {
469: int numPanels = wizardComponents.length;
470: for (int i = 0; i < numPanels; i++)
471: mainPanel.remove(wizardComponents[i]);
472: for (int i = 0; i < numPanels; i++)
473: mainPanel.add(wizardComponents[i]);
474: validate();
475: repaint();
476: }
477: });
478: }
479:
480: @Override
481: public void addNotify() {
482: super .addNotify();
483:
484: for (JComponent component : wizardComponents) {
485: setFontSizeHelper(component.getComponents(), Driver
486: .getFontSize());
487: }
488:
489: pack();
490:
491: int width = super .getWidth();
492:
493: if (width < 600)
494: width = 600;
495: setSize(new Dimension(width, 500));
496: setLocationRelativeTo(MainFrame.getInstance());
497: }
498: }
|