package LinGUIne.parts.advanced;
import java.util.Collection;
import java.util.LinkedList;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.inject.Named;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.e4.core.di.annotations.Optional;
import org.eclipse.e4.core.services.events.IEventBroker;
import org.eclipse.e4.ui.di.Focus;
import org.eclipse.e4.ui.services.IServiceConstants;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.ListViewer;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
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.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import LinGUIne.events.LinGUIneEvents;
import LinGUIne.extensions.IAnalysisPlugin;
import LinGUIne.extensions.IPropertiesProvider;
import LinGUIne.model.IProjectData;
import LinGUIne.model.Project;
import LinGUIne.model.ProjectManager;
import LinGUIne.model.Result;
import LinGUIne.model.SoftwareModuleManager;
import LinGUIne.utilities.SafeAnalysis;
/**
* Part to provide the user with quick access to all of the available analyses.
*
* @author Pete Maresca
* @author Kyle Mullins
*/
public class QuickAnalysisPart implements IPropertiesProvider {
@Inject
private ProjectManager projectMan;
@Inject
private SoftwareModuleManager softwareModuleMan;
@Inject
private IEventBroker eventBroker;
private ProjectExplorerSelection projectSelection;
private Composite myParent;
private ListViewer lstSoftwareModules;
private ListViewer lstAnalyses;
private Button btnRunAnalysis;
private Composite propertiesView;
private Label lblSelectedAnalysis;
private Text txtDescription;
private Label lblNumFiles;
private Label lblNumJobs;
/**
* Creates a new QuickAnalysisPart and populates its controls.
*/
public QuickAnalysisPart() {
projectSelection = new ProjectExplorerSelection();
}
/**
* Creates the QuickAnalysisView's Composite.
*/
@PostConstruct
public void createComposite(Composite parent){
myParent = parent;
GridLayout layout = new GridLayout(2, true);
parent.setLayout(layout);
Label lblLibraries = new Label(parent, SWT.NONE);
lblLibraries.setText("Software Modules");
Label lblFeatures = new Label(parent, SWT.NONE);
lblFeatures.setText("Analyses");
lstSoftwareModules = new ListViewer(parent, SWT.BORDER | SWT.V_SCROLL);
lstSoftwareModules.getControl().setLayoutData(new GridData(GridData.FILL_BOTH));
lstSoftwareModules.setContentProvider(new IStructuredContentProvider(){
private Collection<String> libraryNames;
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput){
if(newInput != null){
libraryNames = ((SoftwareModuleManager)newInput).
getSoftwareModuleNames();
}
}
@Override
public void dispose() {}
@Override
public Object[] getElements(Object inputElement) {
return libraryNames.toArray();
}
});
lstSoftwareModules.setLabelProvider(new LabelProvider(){
public String getText(Object element){
return element.toString();
}
});
lstSoftwareModules.addSelectionChangedListener(new ISelectionChangedListener(){
@Override
public void selectionChanged(SelectionChangedEvent event) {
IStructuredSelection selection = (IStructuredSelection)event.getSelection();
if(selection.size() > 0){
String softwareModuleName = selection.getFirstElement().toString();
lstAnalyses.setInput(softwareModuleMan.getAnalyses(
softwareModuleName));
btnRunAnalysis.setEnabled(false);
updatePropertiesView(null);
}
}
});
lstAnalyses = new ListViewer(parent, SWT.BORDER | SWT.V_SCROLL);
lstAnalyses.getControl().setLayoutData(new GridData(GridData.FILL_BOTH));
lstAnalyses.setContentProvider(new IStructuredContentProvider() {
private Collection<IAnalysisPlugin> analyses;
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput){
if(newInput != null){
analyses = (Collection<IAnalysisPlugin>)newInput;
}
}
@Override
public void dispose() {}
@Override
public Object[] getElements(Object inputElement) {
return analyses.toArray();
}
});
lstAnalyses.setLabelProvider(new LabelProvider(){
public String getText(Object element){
return ((IAnalysisPlugin)element).getName();
}
});
lstAnalyses.addSelectionChangedListener(new ISelectionChangedListener(){
@Override
public void selectionChanged(SelectionChangedEvent event) {
IStructuredSelection selection = (IStructuredSelection) event.getSelection();
if(selection.size() > 0){
IAnalysisPlugin analysis = (IAnalysisPlugin)selection.getFirstElement();
btnRunAnalysis.setEnabled(true);
updatePropertiesView(analysis);
}
}
});
btnRunAnalysis = new Button(parent, SWT.NONE);
btnRunAnalysis.setText("Run Analysis");
btnRunAnalysis.setEnabled(false);
btnRunAnalysis.addSelectionListener(new SelectionListener(){
@Override
public void widgetSelected(SelectionEvent e) {
IStructuredSelection selection =
(IStructuredSelection)lstAnalyses.getSelection();
IAnalysisPlugin analysis = (IAnalysisPlugin)selection.getFirstElement();
runAnalysis(analysis);
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {}
});
lstSoftwareModules.setInput(softwareModuleMan);
}
@Focus
public void onFocus() {}
/**
* Called whenever the ProjectExplorerSelection changes to trigger an update
* to the view.
*
* @param selection The current selection in the ProjectExplorer.
*/
@Inject
public void setProjectDataSelection(@Optional
@Named(IServiceConstants.ACTIVE_SELECTION)
ProjectExplorerSelection selection){
if(selection != null){
projectSelection = selection;
btnRunAnalysis.setEnabled(btnRunAnalysis.getEnabled() &&
!projectSelection.isEmpty());
int numProjects = 0;
int numFiles = 0;
for(String projectName: projectSelection.getSelectedProjects()){
Collection<String> selectedOGData = projectSelection.
getSelectedOriginalData(projectName);
if(!selectedOGData.isEmpty()){
numProjects++;
numFiles += selectedOGData.size();
}
}
updatePropertiesView(numFiles, numProjects);
}
}
/**
* Gets the properties view, instantiates it if null
*/
@Override
public Composite getProperties(Composite parent){
if(propertiesView == null){
createPropertiesView(parent);
}
return propertiesView;
}
/**
* Creates the properties Composite for the view.
*/
private void createPropertiesView(Composite parent){
propertiesView = new Composite(parent, SWT.NONE);
propertiesView.setLayout(new GridLayout(1, false));
lblSelectedAnalysis = new Label(propertiesView, SWT.NONE);
lblSelectedAnalysis.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
lblSelectedAnalysis.setText("Selected Analysis: ");
Label lblDescription = new Label(propertiesView, SWT.NONE);
lblDescription.setText("Description");
txtDescription = new Text(propertiesView, SWT.BORDER | SWT.V_SCROLL |
SWT.WRAP);
txtDescription.setEditable(false);
txtDescription.setLayoutData(new GridData(GridData.FILL_BOTH));
txtDescription.setBackground(lstAnalyses.getControl().getBackground());
Composite bottomContainer = new Composite(propertiesView, SWT.NONE);
bottomContainer.setLayout(new GridLayout(2, false));
lblNumFiles = new Label(bottomContainer, SWT.NONE);
lblNumFiles.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
lblNumFiles.setText("Selected files: 0");
lblNumJobs = new Label(bottomContainer, SWT.NONE);
lblNumJobs.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
lblNumJobs.setText("Analysis jobs: 0");
}
/**
* Updates the properties Composite with the given data taken from the
* selection in the ProjectExplorer.
*/
private void updatePropertiesView(int numFiles, int numProjects){
if(propertiesView != null){
lblNumFiles.setText("Selected files: " + numFiles);
lblNumJobs.setText("Analysis jobs: " + numProjects);
eventBroker.post(LinGUIneEvents.UILifeCycle.PROPERTIES_VIEW_CHANGED,
this);
}
}
/**
* Updates the properties Composite with the given selected AnalysisPlugin.
*/
private void updatePropertiesView(IAnalysisPlugin analysis){
if(propertiesView != null){
if(analysis != null){
lblSelectedAnalysis.setText("Selected Analysis: " +
analysis.getName());
txtDescription.setText(analysis.getAnalysisDescription());
}
else{
lblSelectedAnalysis.setText("Selected Analysis: ");
txtDescription.setText("");
}
eventBroker.post(LinGUIneEvents.UILifeCycle.PROPERTIES_VIEW_CHANGED,
this);
}
}
/**
* Runs the given AnalysisPlugin if possible.
*/
private void runAnalysis(IAnalysisPlugin analysis){
Shell theShell = myParent.getShell();
LinkedList<SafeAnalysis> safeAnalyses = new LinkedList<SafeAnalysis>();
Collection<Class<? extends Result>> requiredResultTypes =
analysis.getRequiredResultTypes();
Collection<Class<? extends IProjectData>> supportedSourceDataTypes =
analysis.getSupportedSourceDataTypes();
//Compose all valid SafeAnalysis objects that we can
for(String projectName: projectSelection.getSelectedProjects()){
Project destProject = projectMan.getProject(projectName);
LinkedList<IProjectData> sourceData = new LinkedList<IProjectData>();
for(String dataName: projectSelection.getSelectedOriginalData(
projectName)){
IProjectData projData = destProject.getProjectData(dataName);
//Check if all of this ProjectData has the proper Results
//And is of the proper type for the chosen analysis
if(supportedSourceDataTypes.contains(projData.getClass())){
boolean hasAllResults = true;
LinkedList<Result> results = new LinkedList<Result>();
//Some analysis don't require a result type
if(!requiredResultTypes.isEmpty()){
for(Class<? extends Result> resultType: requiredResultTypes){
if(destProject.hasResultType(projData, resultType)){
//All good, carry on
//TODO: Prevent duplicate results from being added here
results.add(destProject.getResultType(projData,
resultType));
}
else{
//Missing required result type
//Either run something else first or leave this out
hasAllResults = false;
}
}
}
if(hasAllResults){
sourceData.add(projData);
sourceData.addAll(results);
}
}
else{
//Unsupported source type for this analysis
}
}
//Only run the analysis if there was some selected original
//ProjectData for this Project that was valid for the analysis
if(!sourceData.isEmpty()){
SafeAnalysis safeAnalysis = new SafeAnalysis(theShell, analysis,
sourceData, destProject);
safeAnalyses.add(safeAnalysis);
}
}
if(safeAnalyses.isEmpty()){
//TODO: warn the user that none of the selections were valid
}
else{
for(SafeAnalysis safeAnalysis: safeAnalyses){
SafeRunner.run(safeAnalysis);
}
}
}
}