@Override
  public void performDragOver(DropTargetEvent event) {
    if (!ArtifactTransfer.getInstance().isSupportedType(event.currentDataType)) {
      event.detail = DND.DROP_NONE;
      return;
    }
    final ArtifactData artData = ArtifactTransfer.getInstance().nativeToJava(event.currentDataType);
    if (artData == null) {
      event.detail = DND.DROP_NONE;
      return;
    }
    for (Artifact art : artData.getArtifacts()) {
      if (art.isOfType(CoreArtifactTypes.UniversalGroup)) {
        event.detail = DND.DROP_NONE;
        return;
      }
    }
    Tree tree = treeViewer.getTree();
    TreeItem dragOverTreeItem = tree.getItem(treeViewer.getTree().toControl(event.x, event.y));

    event.feedback = DND.FEEDBACK_EXPAND;
    event.detail = DND.DROP_NONE;

    // Set as COPY if drag item over group (copy versus move will be determined on drop
    if (dragOverTreeItem != null
        && ((GroupExplorerItem) dragOverTreeItem.getData()).isUniversalGroup()) {
      event.detail = DND.DROP_COPY;
      tree.setInsertMark(null, false);
    }
    // Handle re-ordering within same group
    else if (dragOverTreeItem != null
        && !((GroupExplorerItem) dragOverTreeItem.getData()).isUniversalGroup()) {
      GroupExplorerItem dragOverGroupItem = (GroupExplorerItem) dragOverTreeItem.getData();
      IStructuredSelection selectedItem = (IStructuredSelection) treeViewer.getSelection();
      Object obj = selectedItem.getFirstElement();
      if (obj instanceof GroupExplorerItem) {
        GroupExplorerItem droppingGroupItem = (GroupExplorerItem) obj;

        // the group to move must belong to the same group as the member to insert before/after
        if (dragOverGroupItem.getParentItem().equals(droppingGroupItem.getParentItem())) {
          if (isFeedbackAfter) {
            event.feedback = DND.FEEDBACK_INSERT_AFTER;
          } else {
            event.feedback = DND.FEEDBACK_INSERT_BEFORE;
          }
          event.detail = DND.DROP_MOVE;
        }
      } else {
        if (isFeedbackAfter) {
          event.feedback = DND.FEEDBACK_INSERT_AFTER;
        } else {
          event.feedback = DND.FEEDBACK_INSERT_BEFORE;
        }
        event.detail = DND.DROP_COPY;
      }
    } else {
      tree.setInsertMark(null, false);
    }
  }
 public void copyArtifactsToGroup(
     DropTargetEvent event, final GroupExplorerItem dragOverExplorerItem) {
   // Items dropped on Group; simply add items to group
   final Artifact[] artsToRelate = ((ArtifactData) event.data).getArtifacts();
   for (Artifact artifact : artsToRelate) {
     if (!artifact.getBranch().equals(branch)) {
       AWorkbench.popup(
           "ERROR",
           "Cross-branch grouping not supported.\n\nGroup and Artifacts must belong to same branch.");
       return;
     }
   }
   boolean alreadyRelated = true;
   for (Artifact artifact : artsToRelate) {
     if (!dragOverExplorerItem.contains(artifact)) {
       alreadyRelated = false;
       break;
     }
   }
   if (alreadyRelated) {
     AWorkbench.popup("ERROR", "Artifact(s) already related.");
     return;
   }
   try {
     for (Artifact art : artsToRelate) {
       if (!dragOverExplorerItem.contains(art)) {
         dragOverExplorerItem
             .getArtifact()
             .addRelation(CoreRelationTypes.Universal_Grouping__Members, art);
       }
     }
     dragOverExplorerItem.getArtifact().persist("Drag and drop: copy artifacts to group");
   } catch (Exception ex) {
     OseeLog.log(Activator.class, OseeLevel.SEVERE_POPUP, ex);
   }
 }
  @Override
  public void performDrop(DropTargetEvent event) {
    try {
      TreeItem dragOverTreeITem =
          treeViewer.getTree().getItem(treeViewer.getTree().toControl(event.x, event.y));

      // This should always be true as all items are Group Explorer Items
      if (dragOverTreeITem.getData() instanceof GroupExplorerItem) {
        final GroupExplorerItem dragOverExplorerItem =
            (GroupExplorerItem) dragOverTreeITem.getData();

        // Drag item dropped ON universal group item
        if (dragOverExplorerItem.isUniversalGroup()) {

          // Drag item came from inside Group Explorer
          if (event.data instanceof ArtifactData) {
            // If event originated outside, it's a copy event;
            // OR if event is inside and ctrl is down, this is a copy; add items to group
            if (!((ArtifactData) event.data).getSource().equals(viewId)
                || ((ArtifactData) event.data).getSource().equals(viewId) && isCtrlPressed) {
              copyArtifactsToGroup(event, dragOverExplorerItem);
            }
            // Else this is a move
            else {
              IStructuredSelection selectedItem = (IStructuredSelection) treeViewer.getSelection();
              Iterator<?> iterator = selectedItem.iterator();
              final Set<Artifact> insertArts = new HashSet<Artifact>();
              while (iterator.hasNext()) {
                Object obj = iterator.next();
                if (obj instanceof GroupExplorerItem) {
                  insertArts.add(((GroupExplorerItem) obj).getArtifact());
                }
              }
              GroupExplorerItem parentUnivGroupItem =
                  ((GroupExplorerItem) selectedItem.getFirstElement()).getParentItem();
              final Artifact parentArtifact = parentUnivGroupItem.getArtifact();
              final Artifact targetArtifact = dragOverExplorerItem.getArtifact();

              for (Artifact artifact : insertArts) {
                // Remove item from old group
                parentArtifact.deleteRelation(
                    CoreRelationTypes.Universal_Grouping__Members, artifact);
                // Add items to new group
                targetArtifact.addRelation(CoreRelationTypes.Universal_Grouping__Members, artifact);
              }
              Artifacts.persistInTransaction(
                  "Group Explorer - Drag/Drop", parentArtifact, targetArtifact);
            }
          }
        }
        // Drag item dropped before or after group member
        else if (!dragOverExplorerItem.isUniversalGroup()) {

          if (event.data instanceof ArtifactData) {

            GroupExplorerItem parentUnivGroupItem = null;
            // Drag item came from inside Group Explorer
            if (((ArtifactData) event.data).getSource().equals(viewId)) {
              IStructuredSelection selectedItem = (IStructuredSelection) treeViewer.getSelection();
              Iterator<?> iterator = selectedItem.iterator();
              Set<Artifact> insertArts = new HashSet<Artifact>();
              while (iterator.hasNext()) {
                Object obj = iterator.next();
                if (obj instanceof GroupExplorerItem) {
                  insertArts.add(((GroupExplorerItem) obj).getArtifact());
                }
              }
              parentUnivGroupItem =
                  ((GroupExplorerItem) selectedItem.getFirstElement()).getParentItem();
              insertArts.toArray(new Artifact[insertArts.size()]);

              Artifact parentArtifact = parentUnivGroupItem.getArtifact();
              Artifact targetArtifact = dragOverExplorerItem.getArtifact();

              for (Artifact art : insertArts) {
                parentArtifact.setRelationOrder(
                    CoreRelationTypes.Universal_Grouping__Members,
                    targetArtifact,
                    isFeedbackAfter,
                    art);
                targetArtifact = art;
              }
              parentArtifact.persist(getClass().getSimpleName());
            }
            // Drag item came from outside Group Explorer
            else {
              List<Artifact> insertArts = Arrays.asList(((ArtifactData) event.data).getArtifacts());
              parentUnivGroupItem = dragOverExplorerItem.getParentItem();
              insertArts.toArray(new Artifact[insertArts.size()]);

              Artifact parentArtifact = parentUnivGroupItem.getArtifact();
              Artifact targetArtifact = dragOverExplorerItem.getArtifact();

              for (Artifact art : insertArts) {
                parentArtifact.addRelation(
                    RelationOrderBaseTypes.USER_DEFINED,
                    CoreRelationTypes.Universal_Grouping__Members,
                    targetArtifact,
                    isFeedbackAfter,
                    art,
                    "");
              }
              parentArtifact.persist(getClass().getSimpleName());
            }
          }
        }
        treeViewer.refresh(dragOverExplorerItem);
      }

      isFeedbackAfter = false;
    } catch (Exception ex) {
      OseeLog.log(Activator.class, OseeLevel.SEVERE_POPUP, ex);
    }
  }