/***************************************************************************
* Copyright (c) 2008 Conselleria de Infraestructuras y Transporte,
* Generalitat de la Comunitat Valenciana . All rights reserved. This program
* and the accompanying materials are 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: Francisco Javier Cano Muñoz (Prodevelop) - initial api implementation
*
******************************************************************************/
package org.eclipse.papyrus.uml.diagram.common.providers;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
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.draw2d.FlowLayout;
import org.eclipse.draw2d.Label;
import org.eclipse.emf.transaction.util.TransactionUtil;
import org.eclipse.emf.workspace.util.WorkspaceSynchronizer;
import org.eclipse.gef.EditDomain;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.editparts.AbstractConnectionEditPart;
import org.eclipse.gmf.runtime.common.core.service.AbstractProvider;
import org.eclipse.gmf.runtime.common.core.service.IOperation;
import org.eclipse.gmf.runtime.common.ui.resources.FileChangeManager;
import org.eclipse.gmf.runtime.common.ui.resources.IFileObserver;
import org.eclipse.gmf.runtime.diagram.core.util.ViewUtil;
import org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart;
import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramEditDomain;
import org.eclipse.gmf.runtime.diagram.ui.services.decorator.AbstractDecorator;
import org.eclipse.gmf.runtime.diagram.ui.services.decorator.CreateDecoratorsOperation;
import org.eclipse.gmf.runtime.diagram.ui.services.decorator.IDecorator;
import org.eclipse.gmf.runtime.diagram.ui.services.decorator.IDecoratorProvider;
import org.eclipse.gmf.runtime.diagram.ui.services.decorator.IDecoratorTarget;
import org.eclipse.gmf.runtime.draw2d.ui.mapmode.MapModeUtil;
import org.eclipse.gmf.runtime.notation.Diagram;
import org.eclipse.gmf.runtime.notation.Edge;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.papyrus.uml.diagram.common.Activator;
import org.eclipse.swt.graphics.Image;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;
/**
* A provider giving the decorations to use in the diagram validation.
*
* @author <a href="mailto:fjcano@prodevelop.es">Francisco Javier Cano Muñoz</a>
*
*/
public class DiagramValidationDecoratorProvider extends AbstractProvider implements IDecoratorProvider {
private static final String KEY = "validationStatus";
private static final String MARKER_TYPE = "es.cv.gvcase.mdt.common.validation.diagnostic";
private static MarkerObserver fileObserver;
private static Map<Object, Object> allDecorators = new HashMap<Object, Object>();
public void createDecorators(IDecoratorTarget decoratorTarget) {
EditPart editPart = (EditPart)decoratorTarget.getAdapter(EditPart.class);
if(editPart instanceof GraphicalEditPart || editPart instanceof AbstractConnectionEditPart) {
Object model = editPart.getModel();
if((model instanceof View)) {
View view = (View)model;
if(!(view instanceof Edge) && !view.isSetElement()) {
return;
}
}
EditDomain ed = editPart.getViewer().getEditDomain();
if(!(ed instanceof DiagramEditDomain)) {
return;
}
decoratorTarget.installDecorator(KEY, new StatusDecorator(decoratorTarget));
}
}
public boolean provides(IOperation operation) {
if(!(operation instanceof CreateDecoratorsOperation)) {
return false;
}
IDecoratorTarget decoratorTarget = ((CreateDecoratorsOperation)operation).getDecoratorTarget();
View view = (View)decoratorTarget.getAdapter(View.class);
return view != null;
}
public static void refreshDecorators(View view) {
refreshDecorators(ViewUtil.getIdStr(view), view.getDiagram());
}
private static void refreshDecorators(String viewId, Diagram diagram) {
final List<?> decorators = viewId != null ? (List<?>)allDecorators.get(viewId) : null;
if(decorators == null || decorators.isEmpty() || diagram == null) {
return;
}
final Diagram fdiagram = diagram;
PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
public void run() {
try {
TransactionUtil.getEditingDomain(fdiagram).runExclusive(new Runnable() {
public void run() {
for(Iterator<?> it = decorators.iterator(); it.hasNext();) {
IDecorator decorator = (IDecorator)it.next();
decorator.refresh();
}
}
});
} catch (Exception e) {
Activator.getDefault().logError("Decorator refresh failure", e); //$NON-NLS-1$
}
}
});
}
public static class StatusDecorator extends AbstractDecorator {
private String viewId;
public StatusDecorator(IDecoratorTarget decoratorTarget) {
super(decoratorTarget);
try {
final View view = (View)getDecoratorTarget().getAdapter(View.class);
TransactionUtil.getEditingDomain(view).runExclusive(new Runnable() {
public void run() {
StatusDecorator.this.viewId = view != null ? ViewUtil.getIdStr(view) : null;
}
});
} catch (Exception e) {
Activator.getDefault().logError("ViewID access failure", e); //$NON-NLS-1$
}
}
public void refresh() {
removeDecoration();
View view = (View)getDecoratorTarget().getAdapter(View.class);
if(view == null || view.eResource() == null) {
return;
}
EditPart editPart = (EditPart)getDecoratorTarget().getAdapter(EditPart.class);
if(editPart == null || editPart.getViewer() == null) {
return;
}
// query for all the validation markers of the current resource
String elementId = ViewUtil.getIdStr(view);
if(elementId == null) {
return;
}
int severity = IMarker.SEVERITY_INFO;
IMarker foundMarker = null;
IResource resource = WorkspaceSynchronizer.getFile(view.eResource());
if(resource == null || !resource.exists()) {
return;
}
IMarker[] markers = null;
try {
markers = resource.findMarkers(MARKER_TYPE, true, IResource.DEPTH_INFINITE);
} catch (CoreException e) {
Activator.getDefault().logError("Validation markers refresh failure", e); //$NON-NLS-1$
}
if(markers == null || markers.length == 0) {
return;
}
Label toolTip = null;
for(int i = 0; i < markers.length; i++) {
IMarker marker = markers[i];
String attribute = marker.getAttribute(org.eclipse.gmf.runtime.common.ui.resources.IMarker.ELEMENT_ID, ""); //$NON-NLS-1$
if(attribute.equals(elementId)) {
int nextSeverity = marker.getAttribute(IMarker.SEVERITY, IMarker.SEVERITY_INFO);
Image nextImage = getImage(nextSeverity);
if(foundMarker == null) {
foundMarker = marker;
toolTip = new Label(marker.getAttribute(IMarker.MESSAGE, ""), //$NON-NLS-1$
nextImage);
} else {
if(toolTip.getChildren().isEmpty()) {
Label comositeLabel = new Label();
FlowLayout fl = new FlowLayout(false);
fl.setMinorSpacing(0);
comositeLabel.setLayoutManager(fl);
comositeLabel.add(toolTip);
toolTip = comositeLabel;
}
toolTip.add(new Label(marker.getAttribute(IMarker.MESSAGE, ""), //$NON-NLS-1$
nextImage));
}
severity = (nextSeverity > severity) ? nextSeverity : severity;
}
}
if(foundMarker == null) {
return;
}
// add decoration
if(editPart instanceof org.eclipse.gef.GraphicalEditPart) {
if(view instanceof Edge) {
setDecoration(getDecoratorTarget().addConnectionDecoration(getImage(severity), 50, true));
} else {
int margin = -1;
if(editPart instanceof org.eclipse.gef.GraphicalEditPart) {
margin = MapModeUtil.getMapMode(((org.eclipse.gef.GraphicalEditPart)editPart).getFigure()).DPtoLP(margin);
}
setDecoration(getDecoratorTarget().addShapeDecoration(getImage(severity), IDecoratorTarget.Direction.NORTH_EAST, margin, true));
}
getDecoration().setToolTip(toolTip);
}
}
private Image getImage(int severity) {
String imageName = ISharedImages.IMG_OBJS_ERROR_TSK;
switch(severity) {
case IMarker.SEVERITY_ERROR:
imageName = ISharedImages.IMG_OBJS_ERROR_TSK;
break;
case IMarker.SEVERITY_WARNING:
imageName = ISharedImages.IMG_OBJS_WARN_TSK;
break;
default:
imageName = ISharedImages.IMG_OBJS_INFO_TSK;
}
return PlatformUI.getWorkbench().getSharedImages().getImage(imageName);
}
public void activate() {
if(viewId == null) {
return;
}
// add self to global decorators registry
@SuppressWarnings("unchecked")
List<Object> list = (List)allDecorators.get(viewId);
if(list == null) {
list = new ArrayList<Object>(2);
list.add(this);
allDecorators.put(viewId, list);
} else if(!list.contains(this)) {
list.add(this);
}
// start listening to changes in resources
View view = (View)getDecoratorTarget().getAdapter(View.class);
if(view == null) {
return;
}
Diagram diagramView = view.getDiagram();
if(diagramView == null) {
return;
}
if(fileObserver == null) {
FileChangeManager.getInstance().addFileObserver(fileObserver = new MarkerObserver(diagramView));
}
}
public void deactivate() {
if(viewId == null) {
return;
}
// remove self from global decorators registry
@SuppressWarnings("unchecked")
List<Object> list = (List)allDecorators.get(viewId);
if(list != null) {
list.remove(this);
if(list.isEmpty()) {
allDecorators.remove(viewId);
}
}
// stop listening to changes in resources if there are no more
// decorators
if(fileObserver != null && allDecorators.isEmpty()) {
FileChangeManager.getInstance().removeFileObserver(fileObserver);
fileObserver = null;
}
super.deactivate();
}
}
static class MarkerObserver implements IFileObserver {
private Diagram diagram;
private MarkerObserver(Diagram diagram) {
this.diagram = diagram;
}
public void handleFileRenamed(IFile oldFile, IFile file) {
}
public void handleFileMoved(IFile oldFile, IFile file) {
}
public void handleFileDeleted(IFile file) {
}
public void handleFileChanged(IFile file) {
}
public void handleMarkerAdded(IMarker marker) {
if(marker.getAttribute(org.eclipse.gmf.runtime.common.ui.resources.IMarker.ELEMENT_ID, null) != null) {
handleMarkerChanged(marker);
}
}
@SuppressWarnings("unchecked")
public void handleMarkerDeleted(IMarker marker, Map attributes) {
String viewId = (String)attributes.get(org.eclipse.gmf.runtime.common.ui.resources.IMarker.ELEMENT_ID);
refreshDecorators(viewId, diagram);
}
public void handleMarkerChanged(IMarker marker) {
if(!MARKER_TYPE.equals(getType(marker))) {
return;
}
String viewId = marker.getAttribute(org.eclipse.gmf.runtime.common.ui.resources.IMarker.ELEMENT_ID, ""); //$NON-NLS-1$
refreshDecorators(viewId, diagram);
}
private String getType(IMarker marker) {
try {
return marker.getType();
} catch (CoreException e) {
Activator.getDefault().logError("Validation marker refresh failure", e); //$NON-NLS-1$
return ""; //$NON-NLS-1$
}
}
}
}