/*******************************************************************************
* Copyright (c) 2016 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is made available under the terms of the
* Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.windup.ui.internal.services;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Named;
import org.apache.commons.lang.ArrayUtils;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
import org.eclipse.e4.ui.services.IServiceConstants;
import org.eclipse.e4.ui.workbench.modeling.EPartService;
import org.eclipse.e4.ui.workbench.modeling.EPartService.PartState;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.source.IAnnotationModel;
import org.eclipse.jface.text.source.IVerticalRulerInfo;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.internal.e4.compatibility.CompatibilityPart;
import org.eclipse.ui.texteditor.AbstractMarkerAnnotationModel;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.ITextEditor;
import org.eclipse.ui.texteditor.ITextEditorExtension;
import org.jboss.tools.windup.model.domain.WindupMarker;
import org.jboss.tools.windup.ui.WindupUIPlugin;
import org.jboss.tools.windup.ui.internal.Messages;
import org.jboss.tools.windup.ui.internal.explorer.IssueExplorer;
import org.jboss.tools.windup.ui.internal.explorer.QuickfixService;
import org.jboss.tools.windup.ui.internal.issues.IssueDetailsView;
import org.jboss.tools.windup.windup.Hint;
import org.jboss.tools.windup.windup.Issue;
import org.jboss.tools.windup.windup.QuickFix;
import com.google.common.collect.Lists;
/**
* Service for populating active editor context menu.
*/
@SuppressWarnings("restriction")
public class ContextMenuService implements MouseListener, IMenuListener {
private static final IMarker[] EMPTY = new IMarker[0];
private IVerticalRulerInfo ruler;
private ITextEditor editor;
@Inject private MarkerService markerService;
@Inject private EPartService partService;
@Inject private QuickfixService quickfixService;
private List<IMarker> markers = Lists.newArrayList();
private WindupAction SHOW_IN_EXPLORER_ACTION = new WindupAction(Messages.showInIssueExplorer,
WindupUIPlugin.getImageDescriptor(WindupUIPlugin.IMG_WINDUP), () -> {
MPart part = partService.showPart(IssueExplorer.VIEW_ID, PartState.ACTIVATE);
CompatibilityPart compatPart = (CompatibilityPart)part.getObject();
IssueExplorer view = (IssueExplorer)compatPart.getPart();
view.showIssue(markers.get(0));
});
private WindupAction SHOW_DETAILS_ACTION = new WindupAction(Messages.showIssueDetails,
WindupUIPlugin.getImageDescriptor(WindupUIPlugin.IMG_WINDUP), () -> {
MPart part = partService.showPart(IssueDetailsView.ID, PartState.ACTIVATE);
IssueDetailsView view = (IssueDetailsView)part.getObject();
view.showIssueDetails(markers.get(0));
});
private void previewQuickFix() {
IMarker marker = markers.get(0);
Issue issue = markerService.find(marker);
if (issue instanceof Hint) {
Hint hint = (Hint)issue;
quickfixService.previewQuickFix(hint, marker);
}
}
private void applyQuickFix() {
IMarker marker = markers.get(0);
Issue issue = markerService.find(marker);
if (issue instanceof Hint) {
for (QuickFix quickfix : issue.getQuickFixes()) {
quickfixService.applyQuickFix(quickfix);
}
}
}
private void markAsFixed() {
IMarker marker = markers.get(0);
Issue issue = markerService.find(marker);
markerService.setFixed(issue);
}
private class WindupAction extends Action {
private Runnable runner;
public WindupAction(String label, ImageDescriptor descriptor, Runnable runner) {
super(label, descriptor);
this.runner = runner;
}
@Override
public void run() {
runner.run();
}
}
@Inject
private void execute(@Named(IServiceConstants.ACTIVE_PART) MPart part) {
if (editor != null) {
if (ruler != null) {
Control control = ruler.getControl();
if (control != null && !control.isDisposed()) {
control.removeMouseListener(this);
}
}
if (editor instanceof ITextEditorExtension) {
((ITextEditorExtension)editor).removeRulerContextMenuListener(this);
}
editor = null;
ruler = null;
}
if (part != null) {
Object client = part.getObject();
if (client instanceof CompatibilityPart) {
IWorkbenchPart workbenchPart = ((CompatibilityPart) client).getPart();
if (!(workbenchPart instanceof ITextEditor)) {
workbenchPart = workbenchPart.getAdapter(ITextEditor.class);
}
if (workbenchPart instanceof ITextEditor) {
this.editor = (ITextEditor)workbenchPart;
if (editor instanceof ITextEditorExtension) {
((ITextEditorExtension)editor).addRulerContextMenuListener(this);
}
this.ruler = (IVerticalRulerInfo)editor.getAdapter(IVerticalRulerInfo.class);
if (ruler != null) {
Control control = ruler.getControl();
if (control != null && !control.isDisposed()) {
control.addMouseListener(this);
}
}
}
else {
this.editor = null;
this.ruler = null;
}
}
}
}
@Override
public void mouseDoubleClick(MouseEvent e) {}
@Override
public void mouseDown(MouseEvent e) {}
@Override
public void mouseUp(MouseEvent e) {}
@Override
public void menuAboutToShow(IMenuManager manager) {
markers.clear();
IResource resource = (IResource) editor.getEditorInput().getAdapter(IFile.class);
if(resource == null){
return;
}
IMarker[] allMarkers = getMarkers(resource, IResource.DEPTH_ZERO);
if(allMarkers.length == 0) {
return;
}
AbstractMarkerAnnotationModel model = getModel();
IDocument document = getDocument();
for (int i = 0; i < allMarkers.length; i++) {
if (includesRulerLine(model.getMarkerPosition(allMarkers[i]), document)) {
if (isWindupMarker(allMarkers[i])) {
markers.add(allMarkers[i]);
}
}
}
if (!markers.isEmpty()) {
manager.add(SHOW_IN_EXPLORER_ACTION);
manager.add(SHOW_DETAILS_ACTION);
IMarker marker = markers.get(0);
Issue issue = markerService.find(marker);
if (!issue.isStale() && !issue.isFixed() && !issue.getQuickFixes().isEmpty()) {
manager.add(new WindupAction(Messages.PreviewQuickFix, null, this::previewQuickFix));
manager.add(new WindupAction(Messages.ApplyQuickFix, null, this::applyQuickFix));
}
if (!issue.isStale() && !issue.isFixed()) {
manager.add(new WindupAction(Messages.MarkAsFixed,
WindupUIPlugin.getImageDescriptor(WindupUIPlugin.IMG_FIXED),
this::markAsFixed));
}
}
}
private static boolean isWindupMarker(IMarker marker) {
return marker != null && marker.exists();
}
private boolean includesRulerLine(Position position, IDocument document) {
if (position != null && ruler != null) {
try {
int markerLine = document.getLineOfOffset(position.getOffset());
int line = ruler.getLineOfLastMouseButtonActivity();
if (line == markerLine) {
return true;
}
} catch (BadLocationException e) {
WindupUIPlugin.log(e);
}
}
return false;
}
private static IMarker[] getMarkers(IResource fileOrFolder, int depth) {
if(fileOrFolder.getType() == IResource.PROJECT) {
if(!fileOrFolder.isAccessible()) {
return EMPTY;
}
}
try {
IMarker[] markers1 = fileOrFolder.findMarkers(WindupMarker.WINDUP_HINT_MARKER_ID, true, depth);
IMarker[] markers2 = fileOrFolder.findMarkers(WindupMarker.WINDUP_CLASSIFICATION_MARKER_ID, true, depth);
return (IMarker[]) ArrayUtils.addAll(markers1, markers2);
} catch (CoreException e) {
WindupUIPlugin.log(e);
}
return EMPTY;
}
private AbstractMarkerAnnotationModel getModel() {
if(editor == null) {
return null;
}
IDocumentProvider provider = editor.getDocumentProvider();
IAnnotationModel model = provider.getAnnotationModel(editor.getEditorInput());
if (model instanceof AbstractMarkerAnnotationModel) {
return (AbstractMarkerAnnotationModel) model;
}
return null;
}
private IDocument getDocument() {
IDocumentProvider provider = editor.getDocumentProvider();
return provider.getDocument(editor.getEditorInput());
}
}