/*
* FindBugs Eclipse Plug-in.
* Copyright (C) 2003 - 2004, Peter Friese
*
* 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 de.tobject.findbugs.view;
import java.util.Calendar;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.annotation.CheckForNull;
import org.eclipse.core.resources.IMarker;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.ISelectionService;
import org.eclipse.ui.IWorkbenchPart;
import de.tobject.findbugs.FindbugsPlugin;
import de.tobject.findbugs.reporter.MarkerUtil;
import de.tobject.findbugs.reporter.MarkerUtil.BugCollectionAndInstance;
import edu.umd.cs.findbugs.BugInstance;
import edu.umd.cs.findbugs.I18N;
import edu.umd.cs.findbugs.cloud.Cloud;
import edu.umd.cs.findbugs.cloud.Cloud.CloudListener;
import edu.umd.cs.findbugs.cloud.Cloud.CloudTask;
/**
* View which shows bug annotations.
*
* @author Phil Crosby
* @author Andrei Loskutov
* @version 2.0
* @since 19.04.2004
*/
public class UserAnnotationsView extends AbstractFindbugsView {
private String userAnnotation;
private String firstVersionText;
private String cloudText;
private @CheckForNull
BugCollectionAndInstance theBug;
private Text userAnnotationTextField;
private Text cloudTextField;
private Label firstVersionLabel;
private Combo designationComboBox;
private SigninStatusBox signinStatusBox;
private ISelectionListener selectionListener;
private final ExecutorService executor = Executors.newCachedThreadPool();
private Cloud lastCloud;
private final CloudListener cloudListener = new CloudListener() {
public void statusUpdated() {
// noop
}
public void issueUpdated(BugInstance bug) {
BugCollectionAndInstance bug2 = theBug;
if (bug2 != null && bug.equals(bug2.getBugInstance())) {
updateBugInfo();
}
}
public void taskStarted(CloudTask task) {
// noop
}
};
private IWorkbenchPart contributingPart;
public UserAnnotationsView() {
userAnnotation = "";
firstVersionText = "";
cloudText = "";
}
@Override
public Composite createRootControl(Composite parent) {
Composite main = new Composite(parent, SWT.VERTICAL);
main.setLayout(new GridLayout(2, false));
// main.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, true));
designationComboBox = new Combo(main, SWT.LEFT | SWT.DROP_DOWN | SWT.READ_ONLY);
designationComboBox.setToolTipText("My bug designation");
designationComboBox.setLayoutData(new GridData());
for (String s : I18N.instance().getUserDesignationKeys(true)) {
designationComboBox.add(I18N.instance().getUserDesignation(s));
}
designationComboBox.addSelectionListener(new SelectionListener() {
public void widgetSelected(SelectionEvent e) {
final BugCollectionAndInstance bug = theBug;
if (bug == null) {
return;
}
final BugInstance bugInstance = bug.getBugInstance();
if (bugInstance == null) {
return;
}
final int selectionIndex = designationComboBox.getSelectionIndex();
executor.submit(new Runnable() {
public void run() {
bugInstance.setUserDesignationKeyIndex(selectionIndex, bug.getBugCollection());
}
});
}
public void widgetDefaultSelected(SelectionEvent e) {
widgetSelected(e);
}
});
// designationComboBox.setSize(designationComboBox.computeSize(
// SWT.DEFAULT, SWT.DEFAULT));
designationComboBox.setEnabled(false);
signinStatusBox = new SigninStatusBox(main, SWT.NONE);
signinStatusBox.setLayoutData(new GridData(GridData.CENTER, GridData.CENTER, false, false));
firstVersionLabel = new Label(main, SWT.LEFT);
firstVersionLabel.setToolTipText("The earliest version in which the bug was present");
firstVersionLabel.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER, false, false));
userAnnotationTextField = new Text(main, SWT.LEFT | SWT.WRAP | SWT.BORDER);
userAnnotationTextField.setToolTipText("My bug comments");
userAnnotationTextField.setEnabled(false);
GridData uatfData = new GridData(GridData.FILL_BOTH);
uatfData.horizontalSpan = 2;
userAnnotationTextField.setLayoutData(uatfData);
userAnnotationTextField.addFocusListener(new FocusAdapter() {
@Override
public void focusLost(FocusEvent e) {
final BugCollectionAndInstance bug = theBug;
if (bug != null && bug.getBugInstance() != null) {
final String txt = userAnnotationTextField.getText();
executor.submit(new Runnable() {
public void run() {
bug.getBugInstance().setAnnotationText(txt, bug.getBugCollection());
}
});
}
}
});
Label cloudLabel = new Label(main, SWT.LEFT);
cloudLabel.setText("Cloud info:");
GridData lData = new GridData(SWT.LEFT, SWT.TOP, true, false);
lData.horizontalSpan = 2;
cloudLabel.setLayoutData(lData);
cloudTextField = new Text(main, SWT.LEFT | SWT.WRAP | SWT.BORDER | SWT.READ_ONLY);
cloudTextField.setToolTipText("This information about this issue was retrieved from the cloud");
GridData ctfData = new GridData(GridData.FILL_BOTH);
ctfData.horizontalSpan = 2;
cloudTextField.setLayoutData(ctfData);
// Add selection listener to detect click in problems view or bug tree
// view
ISelectionService theService = getSite().getWorkbenchWindow().getSelectionService();
selectionListener = new MarkerSelectionListener(this);
theService.addSelectionListener(selectionListener);
return main;
}
@Override
public void dispose() {
if (selectionListener != null) {
getSite().getWorkbenchWindow().getSelectionService().removeSelectionListener(selectionListener);
selectionListener = null;
}
if (lastCloud != null) {
lastCloud.removeListener(cloudListener);
}
signinStatusBox.dispose();
contributingPart = null;
super.dispose();
}
/**
* Updates the control using the current window size and the contents of the
* title and description fields.
*/
private void updateDisplay() {
firstVersionLabel.setSize(firstVersionLabel.computeSize(SWT.DEFAULT, SWT.DEFAULT));
}
/**
* Set the content to be displayed
*/
public void setContent(BugCollectionAndInstance bci) {
this.theBug = bci;
updateBugInfo();
}
private void updateBugInfo() {
BugCollectionAndInstance theBug2 = theBug;
if (theBug2 == null) {
setCloud(null);
this.userAnnotationTextField.setEnabled(false);
this.designationComboBox.setEnabled(false);
this.userAnnotation = "";
this.firstVersionText = "";
this.cloudText = "";
} else {
BugInstance bug = theBug2.getBugInstance();
long timestamp = theBug2.getBugCollection().getAppVersionFromSequenceNumber(bug.getFirstVersion()).getTimestamp();
String firstVersion = "First seen: " + convertTimestamp(timestamp);
Cloud cloud = theBug2.getBugCollection().getCloud();
setCloud(cloud);
if (cloud.canStoreUserAnnotation(bug)) {
String userDesignation = cloud.getUserEvaluation(bug);
this.userAnnotation = (userDesignation == null) ? "" : userDesignation.trim();
this.firstVersionText = firstVersion.trim();
this.cloudText = cloud.getCloudReport(bug);
this.userAnnotationTextField.setEnabled(true);
this.designationComboBox.setEnabled(true);
int comboIndex = bug.getUserDesignationKeyIndex();
if (comboIndex == -1) {
FindbugsPlugin.getDefault().logError("Cannot find user designation");
} else {
designationComboBox.select(comboIndex);
}
} else {
this.userAnnotationTextField.setEnabled(false);
this.designationComboBox.setEnabled(false);
this.userAnnotation = "";
this.firstVersionText = "";
this.cloudText = "";
}
}
userAnnotationTextField.setText(userAnnotation);
firstVersionLabel.setText(firstVersionText);
cloudTextField.setText(cloudText);
updateDisplay();
}
private void setCloud(Cloud cloud) {
signinStatusBox.setCloud(cloud);
if (cloud != lastCloud) {
if (lastCloud != null) {
lastCloud.removeListener(cloudListener);
}
if (cloud != null) {
cloud.addListener(cloudListener);
}
lastCloud = cloud;
}
}
/**
* Show the details of a FindBugs marker in the view. Brings the view to the
* foreground.
*
* @param thePart
*
* @param marker
* may be null, or marker containing the bug pattern to show
* details for
*/
private void showInView(IMarker marker) {
BugCollectionAndInstance bci = marker == null ? null : MarkerUtil.findBugCollectionAndInstanceForMarker(marker);
setContent(bci);
}
@Override
public void markerSelected(IWorkbenchPart thePart, IMarker newMarker) {
contributingPart = thePart;
showInView(newMarker);
if (!isVisible()) {
activate();
}
}
private static String convertTimestamp(long timestamp) {
if (timestamp == -2) {
return "ERROR - Timestamp not found";
}
if (timestamp == -1) {
return "First version analyzed";
}
Calendar theCalendar = Calendar.getInstance();
theCalendar.setTimeInMillis(System.currentTimeMillis());
theCalendar.set(theCalendar.get(Calendar.YEAR), theCalendar.get(Calendar.MONTH), theCalendar.get(Calendar.DATE), 0, 0, 0);
long beginningOfToday = theCalendar.getTimeInMillis();
long beginningOfYesterday = beginningOfToday - 86400000;
theCalendar.setTimeInMillis(timestamp);
String timeString = theCalendar.getTime().toString();
if (timestamp >= beginningOfToday) {
return "Today " + timeString.substring(timeString.indexOf(":") - 2, timeString.indexOf(":") + 3);
} else if (timestamp >= beginningOfYesterday) {
return "Yesterday " + timeString.substring(timeString.indexOf(":") - 2, timeString.indexOf(":") + 3);
} else {
return timeString.substring(0, timeString.indexOf(":") + 3);
}
}
@Override
public void setFocus() {
designationComboBox.setFocus();
}
@Override
protected void fillLocalToolBar(IToolBarManager manager) {
// noop
}
public IWorkbenchPart getContributingPart() {
return contributingPart;
}
}