/*
* FindBugs - Find bugs in Java programs
* Copyright (C) 2003,2004 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
*/
/*
* RunAnalysisDialog.java
*
* Created on April 1, 2003, 3:22 PM
*/
package edu.umd.cs.findbugs.gui;
import java.awt.event.WindowEvent;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import edu.umd.cs.findbugs.FindBugsProgress;
import edu.umd.cs.findbugs.L10N;
/**
* A modal dialog to run the actual FindBugs analysis on a project.
* The analysis is done in a separate thread, so that the GUI can
* still stay current while the analysis is running. We provide support
* for reporting the progress of the analysis, and for asynchronously
* cancelling the analysis before it completes.
*
* @author David Hovemeyer
*/
public class RunAnalysisDialog extends javax.swing.JDialog {
private static final long serialVersionUID = 1L;
private class RunAnalysisProgress implements FindBugsProgress {
private int goal, count;
private synchronized int getGoal() {
return goal;
}
private synchronized int getCount() {
return count;
}
public void reportNumberOfArchives(final int numArchives) {
beginStage(L10N.getLocalString("msg.scanningarchives_txt", "Scanning archives"), numArchives);
}
public void finishArchive() {
step();
}
public void startAnalysis(int numClasses) {
beginStage(L10N.getLocalString("msg.analysingclasses_txt", "Analyzing classes"), numClasses);
}
public void finishClass() {
step();
}
public void finishPerClassAnalysis() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
stageNameLabel.setText(L10N.getLocalString("msg.finishedanalysis_txt", "Finishing analysis"));
}
});
}
private void beginStage(final String stageName, final int goal) {
synchronized (this) {
this.count = 0;
this.goal = goal;
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
int goal = getGoal();
stageNameLabel.setText(stageName);
countValueLabel.setText("0/" + goal);
progressBar.setMaximum(goal);
progressBar.setValue(0);
}
});
}
private void step() {
synchronized (this) {
count++;
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
int count = getCount();
int goal = getGoal();
countValueLabel.setText(count + "/" + goal);
progressBar.setValue(count);
}
});
}
public void predictPassCount(int[] classesPerPass) {
// noop
}
public void startArchive(String name) {
// noop
}
}
private final AnalysisRun analysisRun;
private Thread analysisThread;
private boolean completed;
private Exception fatalException;
private int analysisPriority;
/**
* Creates new form RunAnalysisDialog
*/
public RunAnalysisDialog(java.awt.Frame parent, AnalysisRun analysisRun_, int analysisPriority) {
super(parent, true);
initComponents();
this.analysisRun = analysisRun_;
this.completed = false;
this.analysisPriority = analysisPriority;
// Create a progress callback to give the user feedback
// about how far along we are.
final FindBugsProgress progress = new RunAnalysisProgress();
// This is the thread that will actually run the analysis.
this.analysisThread = new Thread() {
@Override
public void run() {
try {
analysisRun.execute(progress);
setCompleted(true);
} catch (java.io.IOException e) {
setException(e);
} catch (InterruptedException e) {
// We don't need to do anything here.
// The completed flag is not set, so the frame
// will know that the analysis did not complete.
} catch (Exception e) {
setException(e);
}
// Send a message to the dialog that it should close
// That way, it goes away without any need for user intervention
SwingUtilities.invokeLater(new Runnable() {
public void run() {
closeDialog(new WindowEvent(RunAnalysisDialog.this, WindowEvent.WINDOW_CLOSING));
}
});
}
};
}
public synchronized void setCompleted(boolean completed) {
this.completed = completed;
}
/**
* The creator of the dialog may call this method to find out whether
* or not the analysis completed normally.
*/
public synchronized boolean isCompleted() {
return completed;
}
public synchronized void setException(Exception e) {
fatalException = e;
}
/**
* Determine whether or not a fatal exception occurred
* during analysis.
*/
public synchronized boolean exceptionOccurred() {
return fatalException != null;
}
/**
* Get the exception that abnormally terminated the analysis.
*/
public synchronized Exception getException() {
return fatalException;
}
/**
* This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
private void initComponents() {//GEN-BEGIN:initComponents
java.awt.GridBagConstraints gridBagConstraints;
findBugsLabel = new javax.swing.JLabel();
countLabel = new javax.swing.JLabel();
progressLabel = new javax.swing.JLabel();
progressBar = new javax.swing.JProgressBar();
cancelButton = new javax.swing.JButton();
jSeparator1 = new javax.swing.JSeparator();
stageLabel = new javax.swing.JLabel();
stageNameLabel = new javax.swing.JLabel();
topVerticalFiller = new javax.swing.JLabel();
bottomVerticalFiller = new javax.swing.JLabel();
countValueLabel = new javax.swing.JLabel();
getContentPane().setLayout(new java.awt.GridBagLayout());
setTitle("Run Analysis");
this.setTitle(L10N.getLocalString("dlg.runanalysis_ttl", "Run Analysis"));
addWindowListener(new java.awt.event.WindowAdapter() {
@Override
public void windowClosing(java.awt.event.WindowEvent evt) {
closeDialog(evt);
}
@Override
public void windowOpened(java.awt.event.WindowEvent evt) {
formWindowOpened(evt);
}
});
findBugsLabel.setBackground(new java.awt.Color(0, 0, 204));
findBugsLabel.setFont(new java.awt.Font("Dialog", 1, 24));
findBugsLabel.setForeground(new java.awt.Color(255, 255, 255));
findBugsLabel.setText("Find Bugs!");
findBugsLabel.setOpaque(true);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridwidth = 2;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(0, 0, 3, 0);
getContentPane().add(findBugsLabel, gridBagConstraints);
countLabel.setFont(new java.awt.Font("Dialog", 0, 12));
countLabel.setText("Count:");
countLabel.setText(L10N.getLocalString("dlg.count_lbl", "Count:"));
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 3;
gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
getContentPane().add(countLabel, gridBagConstraints);
progressLabel.setFont(new java.awt.Font("Dialog", 0, 12));
progressLabel.setText("Progress:");
progressLabel.setText(L10N.getLocalString("dlg.progress_lbl", "Progress:"));
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 5;
gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
getContentPane().add(progressLabel, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 5;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.insets = new java.awt.Insets(0, 3, 0, 3);
getContentPane().add(progressBar, gridBagConstraints);
cancelButton.setFont(new java.awt.Font("Dialog", 0, 12));
cancelButton.setText("Cancel");
cancelButton.setText(L10N.getLocalString("dlg.cancel_btn", "Cancel"));
cancelButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cancelButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 8;
gridBagConstraints.gridwidth = 2;
gridBagConstraints.insets = new java.awt.Insets(3, 0, 3, 0);
getContentPane().add(cancelButton, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 7;
gridBagConstraints.gridwidth = 2;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
getContentPane().add(jSeparator1, gridBagConstraints);
stageLabel.setFont(new java.awt.Font("Dialog", 0, 12));
stageLabel.setText("Stage:");
stageLabel.setText(L10N.getLocalString("dlg.stage_lbl", "Stage:"));
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 2;
gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
getContentPane().add(stageLabel, gridBagConstraints);
stageNameLabel.setFont(new java.awt.Font("Dialog", 0, 12));
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 2;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
getContentPane().add(stageNameLabel, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 6;
gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
gridBagConstraints.weighty = 0.5;
getContentPane().add(topVerticalFiller, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
gridBagConstraints.weighty = 0.5;
getContentPane().add(bottomVerticalFiller, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 3;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
gridBagConstraints.insets = new java.awt.Insets(0, 3, 0, 0);
getContentPane().add(countValueLabel, gridBagConstraints);
pack();
}//GEN-END:initComponents
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
int option = JOptionPane.showConfirmDialog(this, L10N.getLocalString("msg.cancelanalysis_txt", "Cancel analysis?"), L10N.getLocalString("msg.analyze_txt", "Analysis"),
JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
if (option == JOptionPane.YES_OPTION) {
// All we need to do to cancel the analysis is to interrupt
// the analysis thread.
analysisThread.interrupt();
}
}//GEN-LAST:event_cancelButtonActionPerformed
private void formWindowOpened(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowOpened
// Here is where we actually kick off the analysis thread.
// Lower the priority of the analysis thread to leave more
// CPU for interactive tasks.
analysisThread.setPriority(analysisPriority);
analysisThread.start();
}//GEN-LAST:event_formWindowOpened
/**
* Closes the dialog
*/
private void closeDialog(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_closeDialog
setVisible(false);
dispose();
}//GEN-LAST:event_closeDialog
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel bottomVerticalFiller;
private javax.swing.JButton cancelButton;
private javax.swing.JLabel countLabel;
private javax.swing.JLabel countValueLabel;
private javax.swing.JLabel findBugsLabel;
private javax.swing.JSeparator jSeparator1;
private javax.swing.JProgressBar progressBar;
private javax.swing.JLabel progressLabel;
private javax.swing.JLabel stageLabel;
private javax.swing.JLabel stageNameLabel;
private javax.swing.JLabel topVerticalFiller;
// End of variables declaration//GEN-END:variables
}