/**
   * Cancel the drag operation. The default implementation will return the dragElement to its
   * original location in the model.
   */
  public void cancelDrag() {
    if (dragPH == null) return;

    // if the dragElement is *not* directly after the placeholder we have to return it there
    List<MUIElement> phParentsKids = dragPH.getParent().getChildren();
    if (phParentsKids.indexOf(dragElement) != phParentsKids.indexOf(dragPH) + 1) {
      dragElement.setToBeRendered(false);
      if (dragElement.getParent() != null)
        dragElement.getParent().getChildren().remove(dragElement);
      phParentsKids.add(phParentsKids.indexOf(dragPH) + 1, dragElement);
      dragElement.setVisible(true);
      dragElement.setToBeRendered(true);
    }
  }
  private void createElement(MUIElement element) {
    if (modelService.isHostedElement(element, workbenchWindow)) {
      // assume the client has full control
      return;
    }

    MPlaceholder placeholder = element.getCurSharedRef();
    if (placeholder != null) {
      element.setToBeRendered(true);
      element = placeholder;
    }

    // render this element
    element.setToBeRendered(true);

    // render all of its parents
    MUIElement parentWindow = workbenchWindow;
    // determine the top parent that needs to be forcibly created
    MUIElement target = null;
    MElementContainer<MUIElement> parent = element.getParent();
    while (parent != null && parent != parentWindow) {
      parent.setToBeRendered(true);
      if (parent.getWidget() == null) {
        target = parent;
      }
      parent = parent.getParent();
    }
    if (target != null) {
      // force the element's parent hierarchy to be created
      engine.createGui(target);
    }
    // ask the engine to create the element
    if (element.getWidget() == null) engine.createGui(element);

    parent = element.getParent();
    if (parent != null && parent.getChildren().size() == 1) {
      // if we're the only child, set ourselves as the selected element
      parent.setSelectedElement(element);
    }
  }
  private void showElementInWindow(MWindow window, MUIElement element) {
    MUIElement parent = element.getParent();
    if (parent == null) {
      MPlaceholder ph = findPlaceholderFor(window, element);
      if (ph != null) {
        element = ph;
        parent = element.getParent();
      }
    }

    if (parent == null && element instanceof MWindow) {
      // no parent but is a window, could be a detached window then
      parent = (MUIElement) ((EObject) element).eContainer();
      if (parent != null) {
        // Force the element to be rendered
        if (!element.isToBeRendered()) {
          element.setToBeRendered(true);
        }

        if (window != parent) {
          showElementInWindow(window, parent);
        }
      }
    } else if (parent != null) {
      // Force the element to be rendered
      if (!element.isToBeRendered()) {
        element.setToBeRendered(true);
      }

      @SuppressWarnings("unchecked")
      MElementContainer<MUIElement> container = (MElementContainer<MUIElement>) parent;
      container.setSelectedElement(element);
      if (window != parent) {
        showElementInWindow(window, parent);
      }
    }
  }
  @Override
  public void bringToTop(MUIElement element) {
    if (element instanceof MApplication) {
      return;
    }

    MWindow window = getTopLevelWindowFor(element);
    if (window == element) {
      if (!element.isToBeRendered()) {
        element.setToBeRendered(true);
      }

      window.getParent().setSelectedElement(window);
    } else {
      showElementInWindow(window, element);
    }
    UIEvents.publishEvent(UIEvents.UILifeCycle.BRINGTOTOP, element);
  }
  /**
   * Start a drag operation on the given element.
   *
   * @param element The element to drag
   */
  public void dragStart(DnDInfo info) {
    // cache a placeholder where the element started (NOTE: this also prevents the parent from
    // being auto-removed by going 'empty'
    if (dragElement.getParent() != null) {
      if (dragElement instanceof MStackElement)
        dragPH = AdvancedFactoryImpl.eINSTANCE.createPlaceholder();
      else if (dragElement instanceof MPartStack)
        dragPH = BasicFactoryImpl.eINSTANCE.createPartSashContainer();
      else if (dragElement instanceof MTrimElement)
        dragPH = MenuFactoryImpl.eINSTANCE.createToolControl();

      dragPH.setElementId(DRAG_PLACEHOLDER_ID);
      dragPH.setToBeRendered(false);

      List<MUIElement> kids = dragElement.getParent().getChildren();
      kids.add(kids.indexOf(dragElement), dragPH);
    }

    dropAgent = dndManager.getDropAgent(dragElement, info);
    if (dropAgent != null) dropAgent.dragEnter(dragElement, info);
  }
  public Object createWidget(final MUIElement element, Object parent) {
    MPlaceholder ph = (MPlaceholder) element;
    final MUIElement ref = ph.getRef();
    ref.setCurSharedRef(ph);

    List<MPlaceholder> renderedRefs = renderedMap.get(ref);
    if (renderedRefs == null) {
      renderedRefs = new ArrayList<MPlaceholder>();
      renderedMap.put(ref, renderedRefs);
    }

    if (!renderedRefs.contains(ph)) renderedRefs.add(ph);

    Composite newComp = new Composite((Composite) parent, SWT.NONE);
    newComp.setLayout(new FillLayout());

    Control refWidget = (Control) ref.getWidget();
    if (refWidget == null) {
      ref.setToBeRendered(true);
      refWidget = (Control) renderingEngine.createGui(ref, newComp, getContextForParent(ref));
    } else {
      if (refWidget.getParent() != newComp) {
        refWidget.setParent(newComp);
      }
    }

    if (ref instanceof MContext) {
      IEclipseContext context = ((MContext) ref).getContext();
      IEclipseContext newParentContext = getContext(ph);
      if (context.getParent() != newParentContext) {
        context.setParent(newParentContext);
      }
    }

    return newComp;
  }
  @Override
  public void hidePart(MPart part, boolean force) {
    if (isInContainer(part)) {
      MPlaceholder sharedRef = part.getCurSharedRef();
      MUIElement toBeRemoved = getRemoveTarget(part);
      MElementContainer<MUIElement> parent = getParent(toBeRemoved);
      List<MUIElement> children = parent.getChildren();

      // check if we're a placeholder but not actually the shared ref of the part
      if (toBeRemoved != part && toBeRemoved instanceof MPlaceholder && sharedRef != toBeRemoved) {
        toBeRemoved.setToBeRendered(false);

        // if so, not much to do, remove ourselves if necessary but that's it
        if (force || part.getTags().contains(REMOVE_ON_HIDE_TAG)) {
          parent.getChildren().remove(toBeRemoved);
        }
        return;
      }

      boolean isActiveChild = isActiveChild(part);
      MPart activationCandidate = null;
      // check if we're the active child
      if (isActiveChild) {
        // get the activation candidate if we are
        activationCandidate = partActivationHistory.getNextActivationCandidate(getParts(), part);
      }

      MPerspective thePersp = modelService.getPerspectiveFor(toBeRemoved);
      boolean needNewSel =
          thePersp == null || !thePersp.getTags().contains("PerspClosing"); // $NON-NLS-1$
      if (needNewSel) {
        if (parent.getSelectedElement() == toBeRemoved) {
          // if we're the selected element and we're going to be hidden, need to select
          // something else
          MUIElement candidate = partActivationHistory.getSiblingSelectionCandidate(part);
          candidate =
              candidate == null
                  ? null
                  : candidate.getCurSharedRef() == null ? candidate : candidate.getCurSharedRef();
          if (candidate != null && children.contains(candidate)) {
            parent.setSelectedElement(candidate);
          } else {
            for (MUIElement child : children) {
              if (child != toBeRemoved && child.isToBeRendered()) {
                parent.setSelectedElement(child);
                break;
              }
            }
          }
        }

        if (activationCandidate == null) {
          // nothing else to activate and we're the active child, deactivate
          if (isActiveChild) {
            part.getContext().deactivate();
          }
        } else {
          // activate our candidate
          activate(activationCandidate);
        }
      }

      if (toBeRemoved != null) {
        toBeRemoved.setToBeRendered(false);
      } else {
        part.setToBeRendered(false);
      }

      if (parent.getSelectedElement() == toBeRemoved) {
        parent.setSelectedElement(null);
      }

      if (force || part.getTags().contains(REMOVE_ON_HIDE_TAG)) {
        children.remove(toBeRemoved);
      }
      // remove ourselves from the activation history also since we're being hidden
      partActivationHistory.forget(getWindow(), part, toBeRemoved == part);
    }
  }