@Override
  public void detach(MPartSashContainerElement element, int x, int y, int width, int height) {
    // If we're showing through a placehoilder then detach it...
    if (element.getCurSharedRef() != null) {
      element = element.getCurSharedRef();
    }

    // Determine the correct parent for the new window
    MWindow window = getTopLevelWindowFor(element);
    MPerspective thePersp = getPerspectiveFor(element);

    MTrimmedWindow newWindow = MBasicFactory.INSTANCE.createTrimmedWindow();

    newWindow.setX(x);
    newWindow.setY(y);
    newWindow.setWidth(width);
    newWindow.setHeight(height);

    element.getParent().getChildren().remove(element);
    MWindowElement uiRoot = wrapElementForWindow(element);
    newWindow.getChildren().add(uiRoot);

    if (thePersp != null) {
      thePersp.getWindows().add(newWindow);
    } else if (window != null) {
      window.getWindows().add(newWindow);
    }
  }
  @Override
  public int countRenderableChildren(MUIElement element) {
    if (!(element instanceof MElementContainer<?>)) {
      return 0;
    }

    @SuppressWarnings("unchecked")
    MElementContainer<MUIElement> container = (MElementContainer<MUIElement>) element;
    int count = 0;
    List<MUIElement> kids = container.getChildren();
    for (MUIElement kid : kids) {
      if (kid.isToBeRendered()) {
        count++;
      }
    }

    if (element instanceof MPerspective) {
      MPerspective perspective = (MPerspective) element;
      for (MWindow window : perspective.getWindows()) {
        if (window.isToBeRendered()) {
          count++;
        }
      }
    }
    return count;
  }
  boolean isInContainer(MElementContainer<?> container, MUIElement element) {
    for (Object object : container.getChildren()) {
      if (object == element) {
        return true;
      } else if (object instanceof MElementContainer<?>) {
        if (isInContainer((MElementContainer<?>) object, element)) {
          return true;
        }
      } else if (object instanceof MPlaceholder) {
        MUIElement ref = ((MPlaceholder) object).getRef();
        if (ref == element) {
          return true;
        } else if (ref instanceof MElementContainer<?>) {
          if (isInContainer((MElementContainer<?>) ref, element)) {
            return true;
          }
        }
      } else if (object instanceof MPerspective) {
        MPerspective persp = (MPerspective) object;
        for (MWindow dw : persp.getWindows()) {
          if (isInContainer(dw, element)) return true;
        }
      } else if (object instanceof MWindow) {
        MWindow win = (MWindow) object;
        for (MWindow dw : win.getWindows()) {
          if (isInContainer(dw, element)) return true;
        }
      }
    }

    if (container instanceof MWindow) {
      MWindow win = (MWindow) container;
      for (MWindow dw : win.getWindows()) {
        if (isInContainer(dw, element)) return true;
      }
    }

    if (container instanceof MPerspective) {
      MPerspective persp = (MPerspective) container;
      for (MWindow dw : persp.getWindows()) {
        if (isInContainer(dw, element)) return true;
      }
    }

    return false;
  }
  private <T> void findElementsRecursive(
      MApplicationElement searchRoot,
      Class<T> clazz,
      Selector matcher,
      List<T> elements,
      int searchFlags) {
    Assert.isLegal(searchRoot != null);
    if (searchFlags == 0) {
      return;
    }

    // are *we* a match ?
    boolean classMatch = clazz == null ? true : clazz.isInstance(searchRoot);
    if (classMatch && matcher.select(searchRoot)) {
      if (!elements.contains(searchRoot)) {
        @SuppressWarnings("unchecked")
        T element = (T) searchRoot;
        elements.add(element);
      }
    }
    if (searchRoot instanceof MApplication && (searchFlags == ANYWHERE)) {
      MApplication app = (MApplication) searchRoot;

      List<MApplicationElement> children = new ArrayList<>();
      if (clazz != null) {
        if (clazz.equals(MHandler.class)) {
          children.addAll(app.getHandlers());
        } else if (clazz.equals(MCommand.class)) {
          children.addAll(app.getCommands());
        } else if (clazz.equals(MBindingContext.class)) {
          children.addAll(app.getBindingContexts());
        } else if (clazz.equals(MBindingTable.class) || clazz.equals(MKeyBinding.class)) {
          children.addAll(app.getBindingTables());
        }
        // } else { only look for these if specifically asked.
        // children.addAll(app.getHandlers());
        // children.addAll(app.getCommands());
        // children.addAll(app.getBindingContexts());
        // children.addAll(app.getBindingTables());
      }

      for (MApplicationElement child : children) {
        findElementsRecursive(child, clazz, matcher, elements, searchFlags);
      }
    }

    if (searchRoot instanceof MBindingContext && (searchFlags == ANYWHERE)) {
      MBindingContext bindingContext = (MBindingContext) searchRoot;
      for (MBindingContext child : bindingContext.getChildren()) {
        findElementsRecursive(child, clazz, matcher, elements, searchFlags);
      }
    }

    if (searchRoot instanceof MBindingTable) {
      MBindingTable bindingTable = (MBindingTable) searchRoot;
      for (MKeyBinding child : bindingTable.getBindings()) {
        findElementsRecursive(child, clazz, matcher, elements, searchFlags);
      }
    }

    // Check regular containers
    if (searchRoot instanceof MElementContainer<?>) {
      /*
       * Bug 455281: If given a window with a primary perspective stack,
       * and we're not told to look outside of the perspectives (i.e.,
       * searchFlags is missing OUTSIDE_PERSPECTIVE), then just search the
       * primary perspective stack instead. This ignores special areas
       * like the compat layer's stack holding the Help, CheatSheets, and
       * Intro.
       */
      MElementContainer<?> searchContainer = (MElementContainer<?>) searchRoot;
      MPerspectiveStack primaryStack = null;
      if (searchRoot instanceof MWindow
          && (searchFlags & OUTSIDE_PERSPECTIVE) == 0
          && (primaryStack = getPrimaryPerspectiveStack((MWindow) searchRoot)) != null) {
        searchContainer = primaryStack;
      }
      if (searchContainer instanceof MPerspectiveStack) {
        if ((searchFlags & IN_ANY_PERSPECTIVE) != 0) {
          // Search *all* the perspectives
          MElementContainer<? extends MUIElement> container = searchContainer;
          List<? extends MUIElement> children = container.getChildren();
          for (MUIElement child : children) {
            findElementsRecursive(child, clazz, matcher, elements, searchFlags);
          }
        } else if ((searchFlags & IN_ACTIVE_PERSPECTIVE) != 0) {
          // Only search the currently active perspective, if any
          MPerspective active = ((MPerspectiveStack) searchContainer).getSelectedElement();
          if (active != null) {
            findElementsRecursive(active, clazz, matcher, elements, searchFlags);
          }
        } else if ((searchFlags & IN_SHARED_AREA) != 0) {
          // Only recurse through the shared areas
          List<MArea> areas = findElements(searchContainer, null, MArea.class, null);
          for (MArea area : areas) {
            findElementsRecursive(area, clazz, matcher, elements, searchFlags);
          }
        }
      } else {
        @SuppressWarnings("unchecked")
        MElementContainer<MUIElement> container = (MElementContainer<MUIElement>) searchRoot;
        List<MUIElement> children = container.getChildren();
        for (MUIElement child : children) {
          findElementsRecursive(child, clazz, matcher, elements, searchFlags);
        }
      }
    }

    // Search Trim
    if (searchRoot instanceof MTrimmedWindow && (searchFlags & IN_TRIM) != 0) {
      MTrimmedWindow tw = (MTrimmedWindow) searchRoot;
      List<MTrimBar> bars = tw.getTrimBars();
      for (MTrimBar bar : bars) {
        findElementsRecursive(bar, clazz, matcher, elements, searchFlags);
      }
    }

    // Search Detached Windows
    if (searchRoot instanceof MWindow) {
      MWindow window = (MWindow) searchRoot;
      for (MWindow dw : window.getWindows()) {
        findElementsRecursive(dw, clazz, matcher, elements, searchFlags);
      }

      MMenu menu = window.getMainMenu();
      if (menu != null && (searchFlags & IN_MAIN_MENU) != 0) {
        findElementsRecursive(menu, clazz, matcher, elements, searchFlags);
      }
      // Check for Handlers
      if (searchFlags == ANYWHERE && MHandler.class.equals(clazz)) {
        for (MHandler child : window.getHandlers()) {
          findElementsRecursive(child, clazz, matcher, elements, searchFlags);
        }
      }
    }

    if (searchRoot instanceof MPerspective) {
      MPerspective persp = (MPerspective) searchRoot;
      for (MWindow dw : persp.getWindows()) {
        findElementsRecursive(dw, clazz, matcher, elements, searchFlags);
      }
    }
    // Search shared elements
    if (searchRoot instanceof MPlaceholder) {
      MPlaceholder ph = (MPlaceholder) searchRoot;

      // Don't search in shared areas unless the flag is set
      if (ph.getRef() != null
          && (!(ph.getRef() instanceof MArea) || (searchFlags & IN_SHARED_AREA) != 0)) {
        findElementsRecursive(ph.getRef(), clazz, matcher, elements, searchFlags);
      }
    }

    if (searchRoot instanceof MPart && (searchFlags & IN_PART) != 0) {
      MPart part = (MPart) searchRoot;

      for (MMenu menu : part.getMenus()) {
        findElementsRecursive(menu, clazz, matcher, elements, searchFlags);
      }

      MToolBar toolBar = part.getToolbar();
      if (toolBar != null) {
        findElementsRecursive(toolBar, clazz, matcher, elements, searchFlags);
      }
      if (MHandler.class.equals(clazz)) {
        for (MHandler child : part.getHandlers()) {
          findElementsRecursive(child, clazz, matcher, elements, searchFlags);
        }
      }
    }
  }
  private void safeRemoveGui(MUIElement element) {
    if (removeRoot == null) removeRoot = element;
    renderedElements.remove(element);

    // We call 'hideChild' *before* checking if the actual element
    // has been rendered in order to pick up cases of 'lazy loading'
    MUIElement parent = element.getParent();
    AbstractPartRenderer parentRenderer = parent != null ? getRendererFor(parent) : null;
    if (parentRenderer != null) {
      parentRenderer.hideChild(element.getParent(), element);
    }

    AbstractPartRenderer renderer = getRendererFor(element);

    // If the element hasn't been rendered then this is a NO-OP
    if (renderer != null) {

      if (element instanceof MElementContainer<?>) {
        MElementContainer<MUIElement> container = (MElementContainer<MUIElement>) element;
        MUIElement selectedElement = container.getSelectedElement();
        List<MUIElement> children = container.getChildren();
        for (MUIElement child : children) {
          // remove stuff in the "back" first
          if (child != selectedElement) {
            removeGui(child);
          }
        }

        if (selectedElement != null && children.contains(selectedElement)) {
          // now remove the selected element
          removeGui(selectedElement);
        }
      }

      if (element instanceof MPerspective) {
        MPerspective perspective = (MPerspective) element;
        for (MWindow subWindow : perspective.getWindows()) {
          removeGui(subWindow);
        }
      } else if (element instanceof MWindow) {
        MWindow window = (MWindow) element;
        for (MWindow subWindow : window.getWindows()) {
          removeGui(subWindow);
        }

        if (window instanceof MTrimmedWindow) {
          MTrimmedWindow trimmedWindow = (MTrimmedWindow) window;
          for (MUIElement trimBar : trimmedWindow.getTrimBars()) {
            removeGui(trimBar);
          }
        }
      }

      if (element instanceof MContribution) {
        MContribution contribution = (MContribution) element;
        Object client = contribution.getObject();
        IEclipseContext parentContext = renderer.getContext(element);
        if (parentContext != null && client != null) {
          try {
            ContextInjectionFactory.invoke(client, PersistState.class, parentContext, null);
          } catch (Exception e) {
            if (logger != null) {
              logger.error(e);
            }
          }
        }
      }

      renderer.disposeWidget(element);

      // unset the client object
      if (element instanceof MContribution) {
        MContribution contribution = (MContribution) element;
        Object client = contribution.getObject();
        IEclipseContext parentContext = renderer.getContext(element);
        if (parentContext != null && client != null) {
          try {
            ContextInjectionFactory.uninject(client, parentContext);
          } catch (Exception e) {
            if (logger != null) {
              logger.error(e);
            }
          }
        }
        contribution.setObject(null);
      }

      // dispose the context
      if (element instanceof MContext) {
        clearContext((MContext) element);
      }
    }

    if (removeRoot == element) removeRoot = null;
  }