/*
* FindBugs - Find Bugs in Java programs
* Copyright (C) 2006, University of Maryland
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307, USA
*/
package edu.umd.cs.findbugs.gui2;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.File;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;
import javax.swing.filechooser.FileFilter;
import javax.swing.plaf.basic.BasicComboBoxRenderer;
import edu.umd.cs.findbugs.BugCollection;
import edu.umd.cs.findbugs.Project;
import edu.umd.cs.findbugs.cloud.CloudFactory;
import edu.umd.cs.findbugs.cloud.CloudPlugin;
import edu.umd.cs.findbugs.util.Util;
/**
* The User Interface for creating a Project and editing it after the fact.
* @author Reuven
*
*/
@SuppressWarnings("serial")
public class NewProjectWizard extends FBDialog
{
private EmptyBorder border = new EmptyBorder(5, 5, 5, 5);
private Project project;
private boolean projectChanged = false;
private boolean projectNameChanged = false;
private FBFileChooser chooser = new FBFileChooser();
private FileFilter directoryOrArchive = new FileFilter()
{
@Override
public boolean accept(File f)
{
String fileName = f.getName().toLowerCase();
return f.isDirectory() || fileName.endsWith(".jar") || fileName.endsWith(".ear") || fileName.endsWith(".war") || fileName.endsWith(".zip") || fileName.endsWith(".sar") || fileName.endsWith(".class");
}
@Override
public String getDescription()
{
return edu.umd.cs.findbugs.L10N.getLocalString("file.accepted_extensions", "Class archive files (*.class, *.[jwes]ar, *.zip)");
}
};
private JList analyzeList = new JList();
private DefaultListModel analyzeModel = new DefaultListModel();
private JTextField projectName = new JTextField();
private JList auxList = new JList();
private DefaultListModel auxModel = new DefaultListModel();
private JList sourceList = new JList();
private DefaultListModel sourceModel = new DefaultListModel();
private JButton finishButton = new JButton(edu.umd.cs.findbugs.L10N.getLocalString("dlg.finish_btn", "Finish"));
private JButton cancelButton = new JButton(edu.umd.cs.findbugs.L10N.getLocalString("dlg.cancel_btn", "Cancel"));
private JComboBox cloudSelector = new JComboBox();
private JComponent[] wizardComponents = new JComponent[4];
private int currentPanel;
static class CloudComboBoxRenderer extends BasicComboBoxRenderer {
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
CloudPlugin plugin = (CloudPlugin) value;
if (isSelected) {
setBackground(list.getSelectionBackground());
setForeground(list.getSelectionForeground());
if (-1 < index) {
if (plugin == null)
list.setToolTipText("No cloud plugin specified by project");
else
list.setToolTipText(plugin.getDetails());
}
} else {
setBackground(list.getBackground());
setForeground(list.getForeground());
}
setFont(list.getFont());
setText((value == null) ? "" : plugin.getDescription());
return this;
}
}
public NewProjectWizard()
{
this(null);
finishButton.setEnabled(false);
}
/**
* @param curProject the project to populate from, or null to start a new one
*/
public NewProjectWizard(Project curProject)
{
project = curProject;
boolean temp = false;
if(curProject == null)
setTitle(edu.umd.cs.findbugs.L10N.getLocalString("dlg.new_item", "New Project"));
else{
setTitle(edu.umd.cs.findbugs.L10N.getLocalString("dlg.reconfig", "Reconfigure"));
temp = true;
}
final boolean reconfig = temp;
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new GridLayout(wizardComponents.length,1));
wizardComponents[0] = createFilePanel(edu.umd.cs.findbugs.L10N.getLocalString("dlg.class_jars_dirs_lbl", "Class archives and directories to analyze:"),
analyzeList, analyzeModel, JFileChooser.FILES_AND_DIRECTORIES, directoryOrArchive, "Choose Class Archives and Directories to Analyze", false);
wizardComponents[1] = createFilePanel(edu.umd.cs.findbugs.L10N.getLocalString("dlg.aux_class_lbl", "Auxiliary class locations:"),
auxList, auxModel, JFileChooser.FILES_AND_DIRECTORIES, directoryOrArchive, "Choose Auxilliary Class Archives and Directories", false);
wizardComponents[2] = createFilePanel(edu.umd.cs.findbugs.L10N.getLocalString("dlg.source_dirs_lbl", "Source directories:"), sourceList, sourceModel, JFileChooser.FILES_AND_DIRECTORIES, null, "Choose Source Directories", true);
JPanel cloudPanel = new JPanel(new BorderLayout());
cloudPanel.add(new JLabel("Bug cloud"), BorderLayout.NORTH);
cloudPanel.add(cloudSelector, BorderLayout.CENTER);
wizardComponents[3] = cloudPanel;
cloudSelector.setRenderer(new CloudComboBoxRenderer());
cloudSelector.addItem(null);
for(CloudPlugin c : CloudFactory.getRegisteredClouds().values()) {
cloudSelector.addItem(c);
}
if (project != null && project.getCloudId() != null) {
CloudPlugin c = CloudFactory.getRegisteredClouds().get(project.getCloudId());
cloudSelector.setSelectedItem(c);
}
JPanel buttons = new JPanel();
buttons.setLayout(new BoxLayout(buttons, BoxLayout.X_AXIS));
if (MainFrame.isMacLookAndFeel()) {
buttons.add(Box.createHorizontalStrut(5));
buttons.add(cancelButton);
buttons.add(Box.createHorizontalStrut(5));
buttons.add(finishButton);
} else {
buttons.add(Box.createHorizontalStrut(5));
buttons.add(finishButton);
buttons.add(Box.createHorizontalStrut(5));
buttons.add(cancelButton);
}
finishButton.addActionListener(new ActionListener()
{
boolean keepGoing = false;
private boolean displayWarningAndAskIfWeShouldContinue(String msg, String title) {
if (keepGoing) return true;
boolean result = JOptionPane.showConfirmDialog(NewProjectWizard.this, msg, title, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.OK_OPTION;
if (result) keepGoing = true;
return result;
}
public void actionPerformed(ActionEvent evt)
{
for (int i = 0; i < analyzeModel.getSize(); i++){
File temp = new File((String)analyzeModel.get(i));
if(!temp.exists() && directoryOrArchive.accept(temp)) {
if (!displayWarningAndAskIfWeShouldContinue(temp.getName()+" " + edu.umd.cs.findbugs.L10N.getLocalString("dlg.invalid_txt", " is invalid."),
edu.umd.cs.findbugs.L10N.getLocalString("dlg.error_ttl", "Can't locate file"))) return;
}
}
for (int i = 0; i < sourceModel.getSize(); i++){
File temp = new File((String)sourceModel.get(i));
if(!temp.exists() && directoryOrArchive.accept(temp)) {
if (!displayWarningAndAskIfWeShouldContinue(temp.getName()+" " + edu.umd.cs.findbugs.L10N.getLocalString("dlg.invalid_txt", " is invalid."),
edu.umd.cs.findbugs.L10N.getLocalString("dlg.error_ttl", "Can't locate file"))) return;
}
}
for (int i = 0; i < auxModel.getSize(); i++){
File temp = new File((String)auxModel.get(i));
if(!temp.exists() && directoryOrArchive.accept(temp)) {
if (!displayWarningAndAskIfWeShouldContinue(temp.getName()+" " + edu.umd.cs.findbugs.L10N.getLocalString("dlg.invalid_txt", " is invalid."),
edu.umd.cs.findbugs.L10N.getLocalString("dlg.error_ttl", "Can't locate file"))) return;
}
}
Project p;
String oldCloudId = null;
boolean resetSettings;
if (project==null)
{
p=new Project();
resetSettings=true;
}
else
{
p=project;
oldCloudId = project.getCloudId();
resetSettings=false;
}
//First clear p's old files, otherwise we can't remove a file once an analysis has been performed on it
int numOldFiles= p.getFileCount();
for (int x=0; x< numOldFiles;x++)
p.removeFile(0);
int numOldAuxFiles=p.getNumAuxClasspathEntries();
for (int x=0; x< numOldAuxFiles;x++)
p.removeAuxClasspathEntry(0);
int numOldSrc=p.getNumSourceDirs();
for (int x=0; x< numOldSrc;x++)
p.removeSourceDir(0);
//Now that p is cleared, we can add in all the correct files.
for (int i = 0; i < analyzeModel.getSize(); i++)
p.addFile((String) analyzeModel.get(i));
for (int i = 0; i < auxModel.getSize(); i++)
p.addAuxClasspathEntry((String) auxModel.get(i));
for (int i = 0; i < sourceModel.getSize(); i++)
p.addSourceDir((String) sourceModel.get(i));
p.setProjectName(projectName.getText());
CloudPlugin cloudPlugin = (CloudPlugin) cloudSelector.getSelectedItem();
String newCloudId;
if (cloudPlugin != null) {
newCloudId = cloudPlugin.getId();
} else
newCloudId = null;
p.setCloudId(newCloudId);
if (keepGoing) {
MainFrame.getInstance().setProject(p);
}
else if (project == null || (projectChanged && JOptionPane.showConfirmDialog(NewProjectWizard.this, edu.umd.cs.findbugs.L10N.getLocalString("dlg.project_settings_changed_lbl", "Project settings have been changed. Perform a new analysis with the changed files?"), edu.umd.cs.findbugs.L10N.getLocalString("dlg.redo_analysis_question_lbl", "Redo analysis?"), JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION))
new AnalyzingDialog(p,resetSettings);
else if (!Util.nullSafeEquals(newCloudId, oldCloudId)) {
BugCollection bugs = MainFrame.getInstance().bugCollection;
bugs.reinitializeCloud();
}
if(reconfig == true)
MainFrame.getInstance().setProjectChanged(true);
String name = p.getProjectName();
if(name == null){
name = Project.UNNAMED_PROJECT;
Debug.println("PROJECT NAME IS NULL!!");
}
if(projectNameChanged){
MainFrame.getInstance().setTitle(MainFrame.TITLE_START_TXT + name);
}
dispose();
}
});
cancelButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt)
{
dispose();
}
});
JPanel south = new JPanel(new BorderLayout());
south.add(new JSeparator(), BorderLayout.NORTH);
south.add(buttons, BorderLayout.EAST);
if (curProject != null)
{
for (String i : curProject.getFileList())
analyzeModel.addElement(i);
//If the project had no classes in it, disable the finish button until classes are added.
if (curProject.getFileList().size()==0)
this.finishButton.setEnabled(false);
for (String i : curProject.getAuxClasspathEntryList())
auxModel.addElement(i);
for (String i : curProject.getSourceDirList())
sourceModel.addElement(i);
projectName.setText(curProject.getProjectName());
projectName.addKeyListener(new KeyAdapter() {
@Override
public void keyTyped(KeyEvent e) {
projectNameChanged = true;
}
});
}
else
{
//If project is null, disable finish button until classes are added
finishButton.setEnabled(false);
}
//loadPanel(0);
loadAllPanels(mainPanel);
add(mainPanel, BorderLayout.CENTER);
add(south, BorderLayout.SOUTH);
add(createTextFieldPanel("Project name (i.e., description)", projectName),
BorderLayout.NORTH);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
// pack();
setModal(true);
setVisible(true);
}
private JComponent createTextFieldPanel(String label, JTextField textField) {
JPanel myPanel = new JPanel(new BorderLayout());
myPanel.add(new JLabel(label), BorderLayout.NORTH);
myPanel.add(textField, BorderLayout.CENTER);
return myPanel;
}
/**
* @param label TODO
*
*/
private JPanel createFilePanel(final String label, final JList list,
final DefaultListModel listModel, final int fileSelectionMode, final FileFilter filter,
final String dialogTitle, boolean wizard) {
JPanel myPanel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.gridheight = 1;
gbc.gridwidth = 2;
gbc.weightx = 1;
gbc.weighty = 0;
gbc.anchor = GridBagConstraints.WEST;
myPanel.add(new JLabel(label), gbc);
gbc.gridx = 0;
gbc.gridy = 1;
gbc.gridheight = 3;
gbc.gridwidth = 1;
gbc.weightx = 1;
gbc.weighty = 1;
gbc.fill = GridBagConstraints.BOTH;
myPanel.add(new JScrollPane(list), gbc);
list.setModel(listModel);
gbc.gridx = 1;
gbc.gridy = 1;
gbc.gridheight = 1;
gbc.gridwidth = 1;
gbc.weightx = 0;
gbc.weighty = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
final JButton addButton = new JButton(edu.umd.cs.findbugs.L10N.getLocalString("dlg.add_btn", "Add"));
myPanel.add(addButton, gbc);
gbc.gridx = 1;
gbc.gridy = 2;
gbc.insets = new Insets(5, 0, 0, 0);
final JButton removeButton = new JButton(edu.umd.cs.findbugs.L10N.getLocalString("dlg.remove_btn", "Remove"));
myPanel.add(removeButton, gbc);
gbc.gridx = 1;
gbc.gridy = 3;
final JButton wizardButton = new JButton("Wizard");
if (wizard)
{
final NewProjectWizard thisGUI = this;
myPanel.add(wizardButton, gbc);
wizardButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt)
{
final Project tempProject = new Project();
for (int i = 0; i < analyzeModel.getSize(); i++)
tempProject.addFile((String) analyzeModel.get(i));
for (int i = 0; i < auxModel.getSize(); i++)
tempProject.addAuxClasspathEntry((String) auxModel.get(i));
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
final SourceDirectoryWizard dialog = new SourceDirectoryWizard(new javax.swing.JFrame(), true, tempProject, thisGUI);
dialog.addWindowListener(new java.awt.event.WindowAdapter() {
@Override
public void windowClosing(java.awt.event.WindowEvent e) {
if(dialog.discover != null && dialog.discover.isAlive())
dialog.discover.interrupt();
}
});
dialog.setVisible(true);
}
});
}
});
}
gbc.insets = new Insets(0, 0, 0, 0);
myPanel.add(Box.createGlue(), gbc);
myPanel.setBorder(border);
addButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt)
{
chooser.setFileSelectionMode(fileSelectionMode);
chooser.setMultiSelectionEnabled(true);
chooser.setApproveButtonText("Choose");
chooser.setDialogTitle(dialogTitle);
//Removes all the file filters currently in the chooser.
for(FileFilter ff : chooser.getChoosableFileFilters()){
chooser.removeChoosableFileFilter(ff);
}
chooser.setFileFilter(filter);
if (chooser.showOpenDialog(NewProjectWizard.this) == JFileChooser.APPROVE_OPTION)
{
File[] selectedFiles = chooser.getSelectedFiles();
for(File selectedFile : selectedFiles)
{
listModel.addElement(selectedFile.getAbsolutePath());
}
projectChanged = true;
// If this is the primary class directories add button, set it to enable the finish button of the main dialog
if (label.equals(edu.umd.cs.findbugs.L10N.getLocalString("dlg.class_jars_dirs_lbl", "Class archives and directories to analyze:")))
finishButton.setEnabled(true);
}
}
});
removeButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt)
{
if (list.getSelectedValues().length > 0)
projectChanged = true;
for (Object i : list.getSelectedValues())
listModel.removeElement(i);
//If this is the primary class directories remove button, set it to disable finish when there are no class files being analyzed
if (listModel.size()==0 && label.equals(edu.umd.cs.findbugs.L10N.getLocalString("dlg.class_jars_dirs_lbl", "Class archives and directories to analyze:")))
finishButton.setEnabled(false);
}
});
return myPanel;
}
/*
private void loadPanel(final int index)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
remove(wizardPanels[currentPanel]);
currentPanel = index;
add(wizardPanels[index], BorderLayout.CENTER);
backButton.setEnabled(index > 0);
nextButton.setEnabled(index < wizardPanels.length - 1);
validate();
repaint();
}
});
}
*/
private void loadAllPanels(final JPanel mainPanel)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
int numPanels = wizardComponents.length;
for(int i=0; i<numPanels; i++)
mainPanel.remove(wizardComponents[i]);
for(int i=0; i<numPanels; i++)
mainPanel.add(wizardComponents[i]);
validate();
repaint();
}
});
}
@Override
public void addNotify(){
super.addNotify();
for(JComponent component : wizardComponents){
setFontSizeHelper(component.getComponents(), Driver.getFontSize());
}
pack();
int width = super.getWidth();
if(width < 600)
width = 600;
setSize(new Dimension(width, 500));
setLocationRelativeTo(MainFrame.getInstance());
}
/**
* @param foundModel
*/
public void setSourceDirecs(DefaultListModel foundModel) {
for(int i = 0; i < foundModel.size(); i++)
{
this.sourceModel.addElement(foundModel.getElementAt(i));
}
}
}