Package org.openiaml.model.diagram.helpers

Source Code of org.openiaml.model.diagram.helpers.GeneratedElementHandler

/**
*
*/
package org.openiaml.model.diagram.helpers;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.gmf.runtime.common.core.command.CommandResult;
import org.eclipse.gmf.runtime.common.core.command.ICommand;
import org.eclipse.gmf.runtime.diagram.core.commands.DeleteCommand;
import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
import org.eclipse.gmf.runtime.emf.commands.core.command.AbstractTransactionalCommand;
import org.openiaml.model.diagram.helpers.inference.EmfInferenceHandler;
import org.openiaml.model.helpers.EdgeTypes;
import org.openiaml.model.helpers.EdgeTypes.EdgeType;
import org.openiaml.model.inference.EcoreCreateElementsHelper;
import org.openiaml.model.inference.InferenceException;
import org.openiaml.model.model.Event;
import org.openiaml.model.model.GeneratedElement;
import org.openiaml.model.model.NamedElement;

/**
* <p>
* A handler called when deleting elements. If the user is
* trying to delete a generated element that is being used by
* non-generated elements, they should ask if they still want to
* confirm deleting it.
* </p>
*
* <p>
* Currently, only incoming non-generated edges are considered:
* {@link #getIncomingNonGeneratedRelationships(GeneratedElement)}
* </p>
*
* @author jmwright
*
*/
public class GeneratedElementHandler {
 
  // all elements that are important in some way
  private List<GeneratedElement> elementsFound = new ArrayList<GeneratedElement>();
 
  // contains elements that also require confirmation
  private Map<GeneratedElement, List<EObject>> containsDirectEdges = new HashMap<GeneratedElement, List<EObject>>();
 
  // elements generated by this element that would also be deleted, that also require confirmation
  private Map<GeneratedElement, List<EObject>> relatedGenerated = new HashMap<GeneratedElement, List<EObject>>();

  // the directly incoming/outgoing edges found
  private Map<EObject, Map<EObject, EObject>> directEdgesFound = new HashMap<EObject, Map<EObject,EObject>>();

  // an editing domain to delete further elements
  private TransactionalEditingDomain editingDomain;

  // all GeneratedElement elements selected
  private List<GeneratedElement> selectedElements = new ArrayList<GeneratedElement>();
 
  /**
   * Populate through the selection of ShapeNodeEditParts
   * (hopefully) and identify which elements require input
   * from the user to delete from.
   *
   * @param selected
   */
  public GeneratedElementHandler(Object[] selected) {
   
    List<GeneratedElement> elementsToCheck = new ArrayList<GeneratedElement>();
   
    // iterate over the selected elements, and
    for (Object o : selected) {
      if (o instanceof IGraphicalEditPart) {
        IGraphicalEditPart part = (IGraphicalEditPart) o;
       
        // it must be a GeneratedElement...
        if (part.resolveSemanticElement() instanceof GeneratedElement) {
          GeneratedElement g = (GeneratedElement) part.resolveSemanticElement();
         
          elementsToCheck.add(g);
        }
       
        if (part.getEditingDomain() != null) {
          editingDomain = part.getEditingDomain();
        }
      }
    }
   
    checkElements(elementsToCheck);
   
  }
 
  private void checkElements(List<GeneratedElement> elementsToCheck) {   
    for (GeneratedElement g : elementsToCheck) {
      checkElement(g);
    }
  }
 
  private void checkElement(GeneratedElement g) {
    // add a copy of this element always
    selectedElements.add(g);

    // that is currently generated
    if (g.isIsGenerated()) {
      // and has an incoming non-generated relationship           
      Map<EObject,EObject> incoming = getIncomingNonGeneratedRelationships(g);
     
      if (!incoming.isEmpty()) {
        // save it
        elementsFound.add(g);
        directEdgesFound.put(g, incoming);
      }
     
      // or contain elements that have incoming edges
      for (EObject content : g.eContents()) {
        if (content instanceof GeneratedElement) {
          GeneratedElement ge = (GeneratedElement) content;
          GeneratedElementHandler handler = new GeneratedElementHandler(ge);
          if (handler.needsConfirmation()) {
            if (!elementsFound.contains(g)) {
              elementsFound.add(g);
            }
            if (containsDirectEdges.get(g) == null) {
              containsDirectEdges.put(g, new ArrayList<EObject>());
            }
            containsDirectEdges.get(g).add(ge);
          }
        }
      }
     
      // or generated elements which will also be deleted
      GeneratedElementDeleter deleter = new GeneratedElementDeleter(g);
      for (EObject d : deleter.getElementsToDelete()) {
        if (d instanceof GeneratedElement) {
          GeneratedElement ge = (GeneratedElement) d;
          GeneratedElementHandler handler = new GeneratedElementHandler(ge);
          if (handler.needsConfirmation()) {
            if (!elementsFound.contains(g)) {
              elementsFound.add(g);
            }
            if (relatedGenerated.get(g) == null) {
              relatedGenerated.put(g, new ArrayList<EObject>());
            }
            relatedGenerated.get(g).add(ge);
          }
        }
      }
     
    }
  }

  /**
   * Only check one generated element, rather than a list of them.
   */
  public GeneratedElementHandler(GeneratedElement ge) {
    checkElement(ge);
  }

  /**
   * @param target
   */
  public GeneratedElementHandler(IGraphicalEditPart target) {
    if (target.resolveSemanticElement() instanceof GeneratedElement) {
      checkElement((GeneratedElement) target.resolveSemanticElement());
    } else {
      throw new IllegalArgumentException("EditPart does not resolve to GeneratedElement");
    }
  }

  /**
   * Check a list of generated elements.
   *
   * @param result
   */
  public GeneratedElementHandler(List<GeneratedElement> result, TransactionalEditingDomain domain) {
    for (GeneratedElement ge : result) {
      checkElement(ge);
    }
    this.editingDomain = domain;
  }
 
  /**
   * Find all the relationships and target objects from this
   * generated element.
   *
   * @param g
   * @return a map of (relationship, target node)
   */
  private Map<EObject, EObject> getIncomingNonGeneratedRelationships(
      GeneratedElement g) {
   
    Map<EObject,EObject> result = new HashMap<EObject,EObject>();

    for (EdgeType typ : EdgeTypes.getAllEdgeTypes()) {
      // WireSource
      if (typ.getEdgeSource().isInstance(g)) {
        // find the EOpposite (outWires)
        EReference opposite = typ.getFromOpposite();
       
        // get results as a list
        List<Object> edges = new ArrayList<Object>();
        if (opposite.isMany()) {
          List<?> e2 = (List<?>) g.eGet(opposite);
          for (Object e : e2)
            edges.add(e);
        } else {
          edges.add(g.eGet(opposite));
        }
               
        for (Object edge : edges) {
          // if it's a NON-generated element that has been generated, add it to the list
          if (edge instanceof GeneratedElement) {
            GeneratedElement edge2 = (GeneratedElement) edge;
           
            if (!edge2.isIsGenerated()) {
              EReference target = typ.getToRef();
             
              Object reverse = edge2.eGet(target);
              if (reverse == null)
                continue;
             
              if (!(reverse instanceof EObject)) {
                throw new IllegalArgumentException("Object '" + reverse + "' is not an EObject, resolved reference = '" + target + "' of edgeType " + typ);
              }
              result.put(edge2, (EObject) reverse);
            }
          }
        }
      }
     
      // WireDestination
      if (typ.getEdgeDestination().isInstance(g)) {
        // find the EOpposite (inWires)
        EReference opposite = typ.getToOpposite();
       
        // get results as a list
        List<Object> edges = new ArrayList<Object>();
        if (opposite.isMany()) {
          List<?> e2 = (List<?>) g.eGet(opposite);
          for (Object e : e2)
            edges.add(e);
        } else {
          edges.add(g.eGet(opposite));
        }
               
        for (Object edge : edges) {
          // if it's a NON-generated element that has been generated, add it to the list
          if (edge instanceof GeneratedElement) {
            GeneratedElement edge2 = (GeneratedElement) edge;
           
            if (!edge2.isIsGenerated()) {
              EReference target = typ.getFromRef();
             
              Object reverse = edge2.eGet(target);
              if (reverse == null)
                continue;
             
              if (!(reverse instanceof EObject)) {
                throw new IllegalArgumentException("Object '" + reverse + "' is not an EObject, resolved reference = '" + target + "' of edgeType " + typ);
              }
              result.put(edge2, (EObject) reverse);
            }
          }
        }
      }
    }
   
    return result;
  }

  /**
   * @return
   */
  public boolean needsConfirmation() {
    return !elementsFound.isEmpty()
      || !containsDirectEdges.isEmpty()
      || !relatedGenerated.isEmpty();
  }

  /**
   * @return
   */
  public List<? extends EObject> getConfirmationElements() {
    return elementsFound;
  }

  /**
   * @param relationship
   * @return
   */
  public EObject getTarget(EObject element, EObject relationship) {
    return directEdgesFound.get(element).get(relationship);
  }

  /**
   * Make a pretty description string of the relationship to
   * a given target.
   *
   * @param relationship
   * @param target
   * @return
   */
  public String formatRelationship(EObject relationship, EObject target) {
    return formatElement(relationship) + " connecting to " + formatElement(target);
   
  }

  /**
   * Get the confirmation message for a particular element
   * which was identified to need confirmation.
   *
   * @param element
   * @return
   */
  public String getConfirmationMessage(EObject element) {
   
    String message = "";
    if (directEdgesFound.get(element) != null) {   
      message = "The generated element '" + formatElement(element) + "' is connected to the following non-generated elements:\n";
      int pos = 0;
      for (EObject relationship : directEdgesFound.get(element).keySet()) {
        if (pos++ > 5) {
          message += "\n[more]";
          break;
        }
        EObject target = getTarget(element, relationship);
        message += "\n" + formatRelationship(relationship, target);
      }
    }
   
    if (containsDirectEdges.get(element) != null) {
      if (!message.isEmpty()) {
        message += "\n\n";
      }
     
      message += "The generated element '" + formatElement(element) + "' contains elements which are connected to non-generated elements:\n";
      int pos = 0;
      for (EObject e : containsDirectEdges.get(element)) {
        if (pos++ > 5) {
          message += "\n[more]";
          break;
        }
        message += "\n" + formatElement(e);
      }
    }

    if (relatedGenerated.get(element) != null) {
      if (!message.isEmpty()) {
        message += "\n\n";
      }
     
      message += "Deleting '" + formatElement(element) + "' will also delete these generated elements, currently in use:\n";
      int pos = 0;
      for (EObject e : relatedGenerated.get(element)) {
        if (pos++ > 5) {
          message += "\n[more]";
          break;
        }
        message += "\n" + formatElement(e);
      }
    }

    return message;
  }

  /**
   * Format an EObject as "ClassName 'name'"
   *
   * @param element
   * @return
   */
  public String formatElement(EObject element) {
    if (element instanceof NamedElement) {
      NamedElement ne = (NamedElement) element;
      if (ne instanceof Event && ne.getName() == null) {
        return ne.eClass().getName() + " " + ne.eContainingFeature().getName();
      } else {
        return ne.eClass().getName() + " '" + ne.getName() + "'";
      }
    }
    return element.toString();
  }
 
  /**
   * Actually deletes an element.
   *
   * @param selected
   * @param monitor
   * @param info
   * @param diagramEditPart
   * @throws InferenceException
   * @throws ExecutionException
   */
  public void deleteElement(EcoreCreateElementsHelper helper, EObject selected, IProgressMonitor monitor, IAdaptable info, IGraphicalEditPart diagramEditPart) throws InferenceException, ExecutionException {
 
    // if the element has no container, it shouldn't exist anymore in the model?
    if (selected.eContainer() != null) {               
      helper.deleteElement(selected, selected.eContainer(), selected.eContainingFeature());
     
      // is this element currently contained within the current
      // edit part?
      IGraphicalEditPart contained = elementContainedWithin(selected, diagramEditPart);
      if (contained != null) {
        // it is: delete the node from the current display               
        DeleteCommand command2 = new DeleteCommand(editingDomain, contained.getPrimaryView());
        command2.execute(monitor, info);
      }
    }
  }

  /**
   * Delete the other generated elements that should be deleted. Does not delete
   * the actual selected element.
   *
   * @see #deleteElement(EcoreCreateElementsHelper, EObject, IProgressMonitor, IAdaptable, IGraphicalEditPart)
   * @param diagramEditPart the current edit part in order to refresh it, or null
   */
  public void deleteOtherElements(final IGraphicalEditPart diagramEditPart) {
    if (editingDomain == null)
      throw new RuntimeException("Cannot delete related elements; we do not have an editing domain.");
   
    ICommand command = new AbstractTransactionalCommand(editingDomain, "delete related elements", Collections.EMPTY_LIST) {

      @Override
      protected CommandResult doExecuteWithResult(
          IProgressMonitor monitor, IAdaptable info)
          throws ExecutionException {
       
        try {
          // we don't want to just delete related elements;
          // we want to delete _all_ elements
          for (GeneratedElement selected : selectedElements) {
            EcoreCreateElementsHelper helper = new EmfInferenceHandler(
                editingDomain,
                Collections.EMPTY_LIST,
                monitor,
                info,
                selected.eResource() );
           
            // get all elements to delete
            List<EObject> toDelete = new GeneratedElementDeleter(selected).getElementsToDelete();
           
            for (EObject d : toDelete) {
              deleteElement(helper, d, monitor, info, diagramEditPart);
            }
          }
         
          if (diagramEditPart != null)
            diagramEditPart.refresh();
        } catch (InferenceException e) {
          throw new ExecutionException(e.getMessage(), e);
        }
       
        return CommandResult.newOKCommandResult();
      }

    };
   
    try {
      command.execute(new NullProgressMonitor(), null);
    } catch (ExecutionException e) {
      throw new RuntimeException(e.getMessage(), e);
    }
   
  }

  /**
   * Is the given eobject rendered in the current edit part?
   * Return the edit part rendering the object, or null
   * if none is found.
   *
   * @param d
   * @param diagramEditPart
   * @return
   */
  private IGraphicalEditPart elementContainedWithin(EObject d,
      IGraphicalEditPart diagramEditPart) {
   
    for (Object obj : diagramEditPart.getChildren()) {
      if (obj instanceof IGraphicalEditPart) {
        IGraphicalEditPart p = (IGraphicalEditPart) obj;
        if (d.equals(p.resolveSemanticElement()))
          return p;
      }
    }
    return null;
   
  }
 
  /**
   * What other elements should we delete for the given selection?
   *
   * @return
   */
  public List<EObject> getOtherElementsToDelete() {
   
    List<EObject> result = new ArrayList<EObject>();
    for (EObject from : relatedGenerated.keySet()) {
      result.addAll(relatedGenerated.get(from));
    }
    return result;
   
  }

}
TOP

Related Classes of org.openiaml.model.diagram.helpers.GeneratedElementHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.