package de.ovgu.cide.mining.recommendationmanager;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;
import java.util.Map.Entry;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.ui.JavaUI;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.texteditor.ITextEditor;
import de.ovgu.cide.features.IFeature;
import de.ovgu.cide.mining.database.ApplicationController;
import de.ovgu.cide.mining.database.model.AElement;
import de.ovgu.cide.mining.database.model.AICategories;
import de.ovgu.cide.mining.database.recommendationengine.ARecommendationContextCollection;
import de.ovgu.cide.mining.events.AElementPreviewEvent;
import de.ovgu.cide.mining.events.AElementViewCountChangedEvent;
import de.ovgu.cide.mining.events.AElementsNonColorChangedEvent;
import de.ovgu.cide.mining.events.AElementsPostColorChangedEvent;
import de.ovgu.cide.mining.events.AElementsPostNonColorChangedEvent;
import de.ovgu.cide.mining.events.AInitEvent;
import de.ovgu.cide.mining.events.ARecommenderElementSelectedEvent;
import de.ovgu.cide.mining.events.ARecommenderElementSelectedEvent.EVENT_TYPE;
import de.ovgu.cide.mining.logging.EvalLogging;
public class RecommendationManagerView extends ViewPart implements Observer {
/**
* The ID of the view as specified by the extension.
*/
public static final String ID = "de.ovgu.cide.mining.recommendationmanager";
public static enum MESSAGE_TYPE {
WARNING, ERROR, INFO, ELEMENT, NONE
}
Image imgError;
Image imgWarning;
Image imgInfo;
Image imgElment;
private TableViewer viewer;
private Table tree;
private TableColumn[] columns;
private Label infoLabel;
private Label infoIconLabel;
private Action deleteElementAction;
private Action doubleClickAction;
private Action selectionChangedAction;
private Action printViewAction;
private RecommendationContentProvider contentProvider;
private RecommendationSorter sorter;
ApplicationController AC;
/**
* This is a callback that will allow us to create the viewer and initialize
* it.
*/
public void createPartControl(Composite parent) {
AC = ApplicationController.getInstance();
imgWarning = PlatformUI.getWorkbench().getSharedImages().getImage(
ISharedImages.IMG_OBJS_WARN_TSK);
imgError = PlatformUI.getWorkbench().getSharedImages().getImage(
ISharedImages.IMG_OBJS_ERROR_TSK);
imgInfo = PlatformUI.getWorkbench().getSharedImages().getImage(
ISharedImages.IMG_OBJS_INFO_TSK);
imgElment = PlatformUI.getWorkbench().getSharedImages().getImage(
ISharedImages.IMG_OBJ_FILE);
Composite workArea = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
layout.marginWidth = 0;
layout.marginHeight = 0;
layout.horizontalSpacing = 0;
layout.verticalSpacing = 0;
workArea.setLayout(layout);
Composite infoArea = new Composite(workArea, SWT.NONE);
layout = new GridLayout();
layout.numColumns = 2;
infoArea.setLayout(layout);
GridData data = new GridData();
data.horizontalAlignment = SWT.FILL;
data.verticalAlignment = SWT.TOP;
data.grabExcessHorizontalSpace = true;
infoArea.setLayoutData(data);
infoIconLabel = new Label(infoArea, SWT.LEFT);
data = new GridData();
data.horizontalAlignment = SWT.LEFT;
data.verticalAlignment = SWT.CENTER;
infoIconLabel.setLayoutData(data);
infoLabel = new Label(infoArea, SWT.LEFT);
data = new GridData();
data.horizontalAlignment = SWT.FILL;
data.verticalAlignment = SWT.TOP;
data.grabExcessHorizontalSpace = true;
infoLabel.setLayoutData(data);
Composite line = new Composite(workArea, SWT.NONE);
line.setBackground(parent.getShell().getDisplay().getSystemColor(
SWT.COLOR_GRAY));
data = new GridData();
data.horizontalAlignment = SWT.FILL;
data.verticalAlignment = SWT.TOP;
data.grabExcessHorizontalSpace = true;
data.heightHint = 1;
line.setLayoutData(data);
Composite viewerArea = new Composite(workArea, SWT.NONE);
data = new GridData();
data.horizontalAlignment = SWT.FILL;
data.verticalAlignment = SWT.FILL;
data.grabExcessHorizontalSpace = true;
data.grabExcessVerticalSpace = true;
viewerArea.setLayoutData(data);
viewerArea.setLayout(new FillLayout());
tree = new Table(viewerArea, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL
| SWT.VIRTUAL);
viewer = new TableViewer(tree);
viewer.setUseHashlookup(true);
tree.setHeaderVisible(true);
tree.setLinesVisible(true);
columns = new TableColumn[9];
columns[0] = new TableColumn(tree, SWT.LEFT);
columns[0].setText("Name");
columns[0].setWidth(250);
columns[1] = new TableColumn(tree, SWT.LEFT);
columns[1].setText("Type-Prio.");
columns[1].setWidth(50);
columns[2] = new TableColumn(tree, SWT.CENTER);
columns[2].setText("Value");
columns[2].setWidth(50);
columns[3] = new TableColumn(tree, SWT.CENTER);
columns[3].setText("Reasons");
columns[3].setWidth(200);
columns[4] = new TableColumn(tree, SWT.CENTER);
columns[4].setText("Supports");
columns[4].setWidth(50);
columns[5] = new TableColumn(tree, SWT.CENTER);
columns[5].setText("> Value for");
columns[5].setWidth(100);
columns[6] = new TableColumn(tree, SWT.CENTER);
columns[6].setText("Range");
columns[6].setWidth(80);
columns[7] = new TableColumn(tree, SWT.CENTER);
columns[7].setText("Length");
columns[7].setWidth(80);
columns[8] = new TableColumn(tree, SWT.CENTER);
columns[8].setText("Views");
columns[8].setWidth(50);
// columns[2] = new TableColumn(table, SWT.CENTER);
// columns[2].setWidth(155);
// columns[2].setText("Type");
contentProvider = new RecommendationContentProvider();
viewer.setContentProvider(contentProvider);
viewer.setLabelProvider(new RecommendationLabelProvider(this));
createSorter();
tree.setItemCount(recommendations.size());
viewer.setInput(new Recommendation[0]);
makeActions();
hookContextMenu();
hookDoubleClickAction();
hookSelectionChangedAction();
contributeToActionBars();
isInit = false;
checkIsIntialized();
AC.addObserver(this);
}
private void createSorter() {
Comparator<Recommendation>[] comparators = new Comparator[9];
comparators[0] = new Comparator<Recommendation>() {
public int compare(Recommendation o1, Recommendation o2) {
return o1.element.getDisplayName().compareTo(
o2.element.getDisplayName());
}
};
comparators[1] = new Comparator<Recommendation>() {
public int compare(Recommendation o1, Recommendation o2) {
return RecommendationLabelProvider.getTypePriority(o1)
- RecommendationLabelProvider.getTypePriority(o2);
}
};
// recommendation value
comparators[2] = new Comparator<Recommendation>() {
public int compare(Recommendation o1, Recommendation o2) {
if (o1.context.getSupportValue() > o2.context.getSupportValue())
return 1;
if (o1.context.getSupportValue() < o2.context.getSupportValue())
return -1;
return 0;
}
};
// recommendation reason
comparators[3] = new Comparator<Recommendation>() {
public int compare(Recommendation o1, Recommendation o2) {
return o1.context.getSupportReasons().compareTo(
o2.context.getSupportReasons());
}
};
// supports
comparators[4] = new Comparator<Recommendation>() {
public int compare(Recommendation o1, Recommendation o2) {
return (o1.context.getContexts().size() - o2.context
.getContexts().size());
}
};
comparators[5] = new Comparator<Recommendation>() {
public int compare(Recommendation o1, Recommendation o2) {
return 0;
}
};
// range
comparators[6] = new Comparator<Recommendation>() {
public int compare(Recommendation o1, Recommendation o2) {
if (o1.element.getStartPosition() < o2.element
.getStartPosition())
return -1;
if (o1.element.getStartPosition() > o2.element
.getStartPosition())
return 1;
if (o1.element.getLength() < o2.element.getLength())
return -1;
if (o1.element.getLength() > o2.element.getLength())
return 1;
return 0;
}
};
// range
comparators[7] = new Comparator<Recommendation>() {
public int compare(Recommendation o1, Recommendation o2) {
return o1.element.getLength() - o2.element.getLength();
}
};
// views
comparators[8] = new Comparator<Recommendation>() {
public int compare(Recommendation o1, Recommendation o2) {
return RecommendationLabelProvider.getViewCount(o1)
- RecommendationLabelProvider.getViewCount(o2);
}
};
sorter = new RecommendationSorter(viewer, columns, comparators);
viewer.setSorter(sorter);
}
public void setInfoMessage(String msg, MESSAGE_TYPE type) {
if (type == MESSAGE_TYPE.NONE)
infoIconLabel.setImage(null);
else if (type == MESSAGE_TYPE.ERROR)
infoIconLabel.setImage(imgError);
else if (type == MESSAGE_TYPE.WARNING)
infoIconLabel.setImage(imgWarning);
else if (type == MESSAGE_TYPE.INFO)
infoIconLabel.setImage(imgInfo);
else if (type == MESSAGE_TYPE.ELEMENT)
infoIconLabel.setImage(imgElment);
infoLabel.setToolTipText(msg);
infoLabel.setText(msg);
}
public Table getTree() {
return tree;
}
public TableViewer getTreeViewer() {
return viewer;
}
private void hookContextMenu() {
MenuManager menuMgr = new MenuManager("#PopupMenu");
menuMgr.setRemoveAllWhenShown(true);
menuMgr.addMenuListener(new IMenuListener() {
public void menuAboutToShow(IMenuManager manager) {
RecommendationManagerView.this.fillContextMenu(manager);
}
});
Menu menu = menuMgr.createContextMenu(viewer.getControl());
viewer.getControl().setMenu(menu);
getSite().registerContextMenu(menuMgr, viewer);
}
private void fillContextMenu(IMenuManager manager) {
manager.add(deleteElementAction);
// Other plug-ins can contribute there actions here
manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
}
private void contributeToActionBars() {
IActionBars bars = getViewSite().getActionBars();
fillLocalToolBar(bars.getToolBarManager());
}
private void fillLocalToolBar(IToolBarManager manager) {
manager.add(deleteElementAction);
// manager.add(printViewAction);
manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
}
private void showMessage(String message) {
MessageDialog.openInformation(viewer.getControl().getShell(),
"Non Feature Manager", message);
}
// private Set<AIElement> getElementsInElementRange(AIElement sourceElement)
// {
//
// //FIND RELATED ELEMENTS
//
// int start = sourceElement.getStartPosition();
// int end = start + sourceElement.getLength();
// int CUHash = sourceElement.getCompelationUnitHash();
//
// Set<AIElement> elements = new HashSet<AIElement>();
//
// for(AIElement element : AC.getAllElements()) {
// if (element.getCompelationUnitHash() != CUHash)
// continue;
//
// if (element.getStartPosition() < start)
// continue;
//
// if ((element.getStartPosition() + element.getLength()) > end)
// continue;
//
// elements.add(element);
//
// }
//
// return elements;
//
// }
private void makeActions() {
deleteElementAction = new Action() {
public void run() {
ISelection selection = viewer.getSelection();
Object selectedRecommendation = ((IStructuredSelection) selection)
.getFirstElement();
Map<AElement, IFeature> elementsToAdd = new HashMap<AElement, IFeature>();
if (!(selectedRecommendation instanceof Recommendation))
return;
if (currentColor == null)
return;
AElement sourceElement = ((Recommendation) selectedRecommendation).element;
IFeature feature = currentColor;
elementsToAdd.put(sourceElement, feature);
// add also all elements which are included in this element
// for (AIElement subElement :
// getElementsInElementRange(sourceElement)) {
// elementsToAdd.put(subElement,feature);
// }
if (elementsToAdd.size() > 0)
AC.fireEvent(new AElementsNonColorChangedEvent(this,
elementsToAdd, new HashMap<AElement, IFeature>()));
}
};
deleteElementAction.setText("Hide Recommendation");
deleteElementAction
.setToolTipText("Mark as - recommendation does not belong to feature.");
deleteElementAction.setImageDescriptor(PlatformUI.getWorkbench()
.getSharedImages().getImageDescriptor(
ISharedImages.IMG_TOOL_DELETE));
deleteElementAction.setDisabledImageDescriptor(PlatformUI
.getWorkbench().getSharedImages().getImageDescriptor(
ISharedImages.IMG_TOOL_DELETE_DISABLED));
deleteElementAction.setEnabled(false);
selectionChangedAction = new Action() {
public void run() {
deleteElementAction.setEnabled(false);
ISelection selection = viewer.getSelection();
Object obj = ((IStructuredSelection) selection)
.getFirstElement();
if (!(obj instanceof Recommendation))
return;
Recommendation node = (Recommendation) obj;
if (node.element.getCategory() == AICategories.FEATURE)
return;
deleteElementAction.setEnabled(true);
int cuHash, start, len;
cuHash = node.element.getCompelationUnitHash();
ICompilationUnit cu = AC.getICompilationUnit(cuHash);
start = node.element.getStartPosition();
len = node.element.getLength();
EvalLogging.getInstance().selectRecommendation(cu, start, len,
node.context.getSupportValue());
try {
AC.fireEvent(new AElementPreviewEvent(
RecommendationManagerView.this));
IEditorPart javaEditor;
javaEditor = JavaUI.openInEditor(cu);
if ((start >= 0) && (javaEditor instanceof ITextEditor)) {
((ITextEditor) javaEditor).selectAndReveal(start, len);
}
}
catch (PartInitException e) {
e.printStackTrace();
} catch (JavaModelException e) {
e.printStackTrace();
}
}
};
}
private void hookDoubleClickAction() {
viewer.addDoubleClickListener(new IDoubleClickListener() {
public void doubleClick(DoubleClickEvent event) {
// doubleClickAction.run();
}
});
}
private void hookSelectionChangedAction() {
viewer.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
// TODO Auto-generated method stub
selectionChangedAction.run();
}
});
}
/**
* Passing the focus request to the viewer's control.
*/
public void setFocus() {
viewer.getControl().setFocus();
}
private ARecommenderElementSelectedEvent curEvent;
public void update(Observable o, Object arg) {
if (o.equals(AC)) {
if (arg instanceof AInitEvent) {
setInfoMessage("Database created for "
+ ((AInitEvent) arg).getProject().getName(),
MESSAGE_TYPE.INFO);
isInit = true;
} else if (arg instanceof AElementViewCountChangedEvent) {
getTreeViewer().refresh();
} else if (arg instanceof ARecommenderElementSelectedEvent) {
curEvent = (ARecommenderElementSelectedEvent) arg;
updateRecommendations(curEvent);
} else if (arg instanceof AElementsPostColorChangedEvent) {
updateRecommendations(curEvent);
} else if (arg instanceof AElementsPostNonColorChangedEvent) {
updateRecommendations(curEvent);
}
}
}
private void updateRecommendations(
final ARecommenderElementSelectedEvent event) {
Job update = new Job("Update recommendations") {
@Override
protected IStatus run(IProgressMonitor monitor) {
calculateRecommendations(event);
EvalLogging.getInstance()
.updateRecommendations(recommendations);
Display.getDefault().syncExec(new Runnable() {
public void run() {
if (!recommendations.isEmpty()) {
setInfoMessage(
"Recommendations for selected element",
MESSAGE_TYPE.INFO);
} else {
setInfoMessage(
"There are no recommendations for the selected element.",
MESSAGE_TYPE.WARNING);
}
getTreeViewer().getTable().setItemCount(
recommendations.size());
getTreeViewer().setInput(
recommendations.toArray(new Recommendation[0]));
}
});
return Status.OK_STATUS;
}
};
update.setPriority(Job.SHORT);
update.schedule();
}
private boolean checkIsIntialized() {
if (isInit)
return true;
IProject project = AC.getInitializedProject();
if (project == null) {
setInfoMessage("Database has not been created for Feature Mining",
MESSAGE_TYPE.ERROR);
return false;
}
setInfoMessage("Database created for " + project.getName(),
MESSAGE_TYPE.INFO);
isInit = true;
return true;
}
static class Recommendation implements IAdaptable {
public Recommendation(AElement e, ARecommendationContextCollection c) {
element = e;
context = c;
}
AElement element;
ARecommendationContextCollection context;
public Object getAdapter(Class adapter) {
return null;
}
}
List<Recommendation> recommendations = new ArrayList<Recommendation>();
IFeature currentColor;
public void calculateRecommendations(ARecommenderElementSelectedEvent event) {
if (event == null) {
recommendations = new ArrayList<Recommendation>();
} else {
// BUILD TREE TO DISPLAY
Map<AElement, ARecommendationContextCollection> providedRecommendations;
if (event.getType().equals(EVENT_TYPE.ELEMENT)) {
AElement sourceElement = event.getElement();
providedRecommendations = AC.getRecommendations(event
.getColor(), sourceElement);
} else {
providedRecommendations = AC.getRecommendations(event
.getColor(), event.getStart(), event.getEnd(), event
.getCuHash());
}
this.currentColor = event.getColor();
recommendations = new ArrayList<Recommendation>();
for (Entry<AElement, ARecommendationContextCollection> entry : providedRecommendations
.entrySet()) {
recommendations.add(new Recommendation(entry.getKey(), entry
.getValue()));
}
}
}
private boolean isInit;
}