Package at.bestsolution.efxclipse.runtime.workbench.renderers.base

Source Code of at.bestsolution.efxclipse.runtime.workbench.renderers.base.BaseStackRenderer

/*******************************************************************************
* Copyright (c) 2012 BestSolution.at and others.
* 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:
*     Tom Schindl<tom.schindl@bestsolution.at> - initial API and implementation
*******************************************************************************/
package at.bestsolution.efxclipse.runtime.workbench.renderers.base;

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

import javax.annotation.PostConstruct;
import javax.inject.Inject;

import org.eclipse.e4.core.contexts.ContextInjectionFactory;
import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.e4.core.services.events.IEventBroker;
import org.eclipse.e4.ui.model.application.MApplication;
import org.eclipse.e4.ui.model.application.ui.MContext;
import org.eclipse.e4.ui.model.application.ui.MElementContainer;
import org.eclipse.e4.ui.model.application.ui.MUIElement;
import org.eclipse.e4.ui.model.application.ui.advanced.MPlaceholder;
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
import org.eclipse.e4.ui.model.application.ui.basic.MPartStack;
import org.eclipse.e4.ui.model.application.ui.basic.MStackElement;
import org.eclipse.e4.ui.model.application.ui.basic.MWindow;
import org.eclipse.e4.ui.workbench.UIEvents;
import org.eclipse.e4.ui.workbench.modeling.EPartService;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventHandler;

import at.bestsolution.efxclipse.runtime.workbench.base.rendering.AbstractRenderer;
import at.bestsolution.efxclipse.runtime.workbench.base.rendering.RendererFactory;
import at.bestsolution.efxclipse.runtime.workbench.renderers.base.widget.WCallback;
import at.bestsolution.efxclipse.runtime.workbench.renderers.base.widget.WLayoutedWidget;
import at.bestsolution.efxclipse.runtime.workbench.renderers.base.widget.WPlaceholderWidget;
import at.bestsolution.efxclipse.runtime.workbench.renderers.base.widget.WStack;
import at.bestsolution.efxclipse.runtime.workbench.renderers.base.widget.WStack.WStackItem;

@SuppressWarnings("restriction")
public abstract class BaseStackRenderer<N, I, IC> extends BaseRenderer<MPartStack, WStack<N, I, IC>> {
  // private static final String MAP_ITEM_KEY = "fx.rendering.stackitem";
 
  @Inject
  RendererFactory factory;
 
  @Inject
  MApplication application;
 
  boolean inLazyInit;
 
  @PostConstruct
  void init(IEventBroker eventBroker) {
    eventBroker.subscribe(UIEvents.ElementContainer.TOPIC_CHILDREN, new EventHandler() {

      @Override
      public void handleEvent(Event event) {
        Object changedObj = event.getProperty(UIEvents.EventTags.ELEMENT);
        if (changedObj instanceof MPartStack) {
          MPartStack parent = (MPartStack) changedObj;
          if (BaseStackRenderer.this == parent.getRenderer()) {
            String eventType = (String) event.getProperty(UIEvents.EventTags.TYPE);
           
            if (UIEvents.EventTypes.ADD.equals(eventType)) {
              MUIElement element = (MUIElement) event.getProperty(UIEvents.EventTags.NEW_VALUE);
              handleChildAddition(parent, (MStackElement) element);
            } else if (UIEvents.EventTypes.REMOVE.equals(eventType)) {
              MUIElement element = (MUIElement) event.getProperty(UIEvents.EventTags.OLD_VALUE);
              handleChildRemove(parent, (MStackElement) element);
            }
          }
        }
      }
    });
    eventBroker.subscribe(UIEvents.ElementContainer.TOPIC_SELECTEDELEMENT, new EventHandler() {

      @Override
      public void handleEvent(Event event) {
        Object changedObj = event.getProperty(UIEvents.EventTags.ELEMENT);
        if (changedObj instanceof MPartStack) {
          MPartStack parent = (MPartStack) changedObj;
          if (BaseStackRenderer.this == parent.getRenderer()) {
            String eventType = (String) event.getProperty(UIEvents.EventTags.TYPE);
            if (UIEvents.EventTypes.SET.equals(eventType)) {
              MUIElement newValue = (MUIElement) event.getProperty(UIEvents.EventTags.NEW_VALUE);
              MUIElement oldValue = (MUIElement) event.getProperty(UIEvents.EventTags.OLD_VALUE);
              handleSelectedElement(parent, (MStackElement) oldValue, (MStackElement) newValue);
            }
          }
        }
      }
    });
    eventBroker.subscribe(UIEvents.UIElement.TOPIC_VISIBLE, new EventHandler() {
     
      @Override
      public void handleEvent(Event event) {
        MUIElement changedObj = (MUIElement) event.getProperty(UIEvents.EventTags.ELEMENT);
        if( changedObj.isToBeRendered() ) {
          MUIElement parent = changedObj.getParent();
          if( parent != null ) {
            if( BaseStackRenderer.this == parent.getRenderer() ) {
              MPartStack stack = (MPartStack) parent;
              String eventType = (String) event.getProperty(UIEvents.EventTags.TYPE);
              if (UIEvents.EventTypes.SET.equals(eventType)) {
                Boolean newValue = (Boolean) event.getProperty(UIEvents.EventTags.NEW_VALUE);
                if( newValue.booleanValue() ) {
                  //TODO Is childRendered not dangerous to call here??
                  childRendered(stack, changedObj);
                } else {
                  hideChild(stack, changedObj);
                }
              }
            } 
          }
        }
      }
    });
  }

  MPart getPart(MUIElement element) {
    if( element instanceof MPlaceholder ) {
      return (MPart) ((MPlaceholder) element).getRef();
    } else if (element instanceof MElementContainer<?>) {
      @SuppressWarnings("unchecked")
      MElementContainer<MUIElement> container = (MElementContainer<MUIElement>) element;
      element = container.getSelectedElement();
      if ((element == null) && !container.getChildren().isEmpty()) {
        element = container.getChildren().get(0);
      }
      return getPart(element);
    } else {
      return (MPart) element;
    }
  }
 
  @Override
  protected void initWidget(final MPartStack element, final WStack<N, I, IC> widget) {
    super.initWidget(element, widget);
    widget.setMouseSelectedItemCallback(new WCallback<WStackItem<I, IC>, Void>() {

      @Override
      public Void call(WStackItem<I, IC> param) {
        if (param.getDomElement() != null) {
          activatationJob(element,getPart(param.getDomElement()),true);
        }

        return null;
      }
    });
    widget.setKeySelectedItemCallback(new WCallback<WStackItem<I, IC>, Void>() {

      @Override
      public Void call(WStackItem<I, IC> param) {
        if (param.getDomElement() != null) {
          activatationJob(element,getPart(param.getDomElement()),false);
        }

        return null;
      }
    });
   
    widget.registerActivationCallback(new WCallback<Boolean, Void>() {
     
      @Override
      public Void call(Boolean param) {
        if( param.booleanValue() && element.getSelectedElement() != null ) {
          activatationJob(element,getPart(element.getSelectedElement()), true);
        }
        return null;
      }
    });
  }
 
  private void activatationJob(MPartStack stackToActivate, final MPart p, final boolean focus) {
    if( shouldActivate(stackToActivate) ) {
      activate(p, focus)
    }
  }

  private boolean shouldActivate(MPartStack stackToActivate) {
    if (inContentProcessing(stackToActivate)) {
      return false;
    }
   
    if (application != null) {
      IEclipseContext applicationContext = application.getContext();
      IEclipseContext activeChild = applicationContext
          .getActiveChild();
      if (activeChild == null
          || activeChild.get(MWindow.class) != application
              .getSelectedElement()
          || application.getSelectedElement() != modelService
              .getTopLevelWindowFor(stackToActivate)) {
        return false;
      }
    }
    return true;
  }
 
  @Override
  public void doProcessContent(MPartStack element) {
    WStack<N, I, IC> stack = getWidget(element);
    List<WStackItem<I, IC>> items = new ArrayList<WStackItem<I, IC>>();
    WStackItem<I, IC> initalItem = null;

    for (MStackElement e : element.getChildren()) {
      // Precreate the rendering context for the subitem
      AbstractRenderer<MStackElement, ?> renderer = factory.getRenderer(e);
      if (renderer != null && e.isToBeRendered() && e.isVisible() ) {
        WStackItem<I, IC> item = createStackItem(stack, e, renderer);
        items.add(item);

        if (e == element.getSelectedElement()) {
          initalItem = item;
        }
      }
    }

    if (!items.isEmpty()) {
      if (initalItem == null || items.size() == 1 || items.get(0) == initalItem) {
        stack.addItems(items);
      } else {
        stack.addItem(initalItem);
        if (items.get(items.size() - 1) == initalItem) {
          stack.addItems(0, items.subList(0, items.size() - 1));
        } else {
          int idx = items.indexOf(initalItem);
          stack.addItems(0, items.subList(0, idx));
          stack.addItems(items.subList(idx + 1, items.size()));
        }

      }
    }

    stack.selectItem(stack.getItems().indexOf(initalItem));
  }

  private WStackItem<I, IC> createStackItem(WStack<N, I, IC> stack, final MStackElement e, AbstractRenderer<MStackElement, ?> renderer) {
    IEclipseContext context = renderer.setupRenderingContext(e);
    WStackItem<I, IC> item = ContextInjectionFactory.make(stack.getStackItemClass(), context);
    item.setDomElement(e);
    item.setInitCallback(new WCallback<WStackItem<I, IC>, IC>() {

      @SuppressWarnings("unchecked")
      @Override
      public IC call(WStackItem<I, IC> param) {
        inLazyInit = true;
        try {
          WLayoutedWidget<MStackElement> widget = engineCreateWidget(e);
          if (widget != null) {
            return (IC) widget.getStaticLayoutNode();
          }
          return null;         
        } finally {
          inLazyInit = false;
        }
      }
    });
    item.setOnCloseCallback(new WCallback<WStack.WStackItem<I, IC>, Boolean>() {

      @Override
      public Boolean call(WStackItem<I, IC> param) {
        return ! handleStackItemClose(e, param);
      }
    });

    return item;
  }

  void handleChildAddition(MPartStack parent, MStackElement element) {
    if( element.isToBeRendered() && element.isVisible() ) {
      int idx = getRenderedIndex(parent, element);

      AbstractRenderer<MStackElement, ?> renderer = factory.getRenderer(element);
      WStack<N, I, IC> stack = getWidget(parent);
      WStackItem<I, IC> item = createStackItem(getWidget(parent), element, renderer);

      stack.addItems(idx, Collections.singletonList(item));
    }
  }

  void handleChildRemove(MPartStack parent, MStackElement element) {
    if( element.isToBeRendered() && element.isVisible() ) {
      hideChild(parent, element);
    }
  }

  void handleSelectedElement(MPartStack parent, MStackElement oldElement, MStackElement newElement) {
    WStack<N, I, IC> stack = getWidget(parent);
    int idx = 0;
    for( WStackItem<I, IC> i : stack.getItems() ) {
      if( i.getDomElement() == newElement ) {
        stack.selectItem(idx);
        showElementRecursive(newElement);
        return;
      }
      idx++;
    }
   
    // Looks like the child is not part of the UI yet (most likely because it got removed using IPR#removeGUI)
    childRendered(parent, newElement);
    stack.selectItem(parent.getChildren().indexOf(newElement));
    // TODO Should we do the traversal before???
    showElementRecursive(newElement);
  }

  boolean handleStackItemClose(MStackElement e, WStackItem<I, IC> item) {
    MPart part = getPart(e);
    if( ! part.isCloseable() ) {
      return false;
    }
   
    IEclipseContext partContext = part.getContext();
    IEclipseContext parentContext = getContextForParent(part);
    // a part may not have a context if it hasn't been rendered
    IEclipseContext context = partContext == null ? parentContext : partContext;
    // Allow closes to be 'canceled'
    EPartService partService = (EPartService) context
        .get(EPartService.class.getName());
    if (partService.savePart(part, true)) {
      partService.hidePart(part);
      return true;
    }
    // the user has canceled out of the save operation, so don't close the
    // part
    return false;
   
  }
 
  @Override
  public void childRendered(MPartStack parentElement, MUIElement element) {
    if( inLazyInit || inContentProcessing(parentElement) || ! element.isVisible() ) {
      return;
    }

    WStack<N, I, IC> stack = getWidget(parentElement);
    for( WStackItem<I, IC> i : stack.getItems() ) {
      if( i.getDomElement() == element ) {
        return;
      }
    }
   
    int idx = getRenderedIndex(parentElement, element);
    AbstractRenderer<MStackElement, ?> renderer = factory.getRenderer(element);
    stack.addItems(idx, Collections.singletonList(createStackItem(stack, (MStackElement)element, renderer)));
  }
 
  @Override
  public void hideChild(MPartStack container, MUIElement changedObj) {
    WStack<N, I, IC> stack = getWidget(container);
    if( stack == null ) {
      return;
    }
   
    WStackItem<I, IC> item = null;
   
    for( WStackItem<I, IC> i : stack.getItems() ) {
      if( i.getDomElement() == changedObj ) {
        item = i;
        break;
      }
    }
   
    if( item != null ) {
      List<WStackItem<I, IC>> l = Collections.singletonList(item);
      stack.removeItems(l);
    }
   
    if( changedObj.getTags().contains(EPartService.REMOVE_ON_HIDE_TAG) ) {
      container.getChildren().remove(changedObj);
    }
  }
 
  private void showElementRecursive(MUIElement element) {
    if( ! element.isToBeRendered() ) {
      return;
    }
   
    if (element instanceof MPlaceholder && element.getWidget() != null) {
      MPlaceholder ph = (MPlaceholder) element;
      MUIElement ref = ph.getRef();
     
      if( ref.getCurSharedRef() != ph ) {
        ref.setCurSharedRef(ph);
        WPlaceholderWidget placeholder = (WPlaceholderWidget) ph.getWidget();
        @SuppressWarnings("unchecked")
        WLayoutedWidget<MUIElement> content = (WLayoutedWidget<MUIElement>) ref.getWidget();
        placeholder.setContent(content);
      }
     
      element = ref;
    }
   
    if (element instanceof MContext) {
      IEclipseContext context = ((MContext) element).getContext();
      if (context != null) {
        IEclipseContext newParentContext = modelService.getContainingContext(element);
        if (context.getParent() != newParentContext) {
          context.setParent(newParentContext);
        }
      }
    }
   
    // Currently not supported in the model but will very likely be in future
    if (element instanceof MElementContainer<?>) {
      MElementContainer<?> container = (MElementContainer<?>) element;
      List<MUIElement> kids = new ArrayList<MUIElement>(
          container.getChildren());
      for (MUIElement childElement : kids) {
        showElementRecursive(childElement);
      }
    }
  }
}
TOP

Related Classes of at.bestsolution.efxclipse.runtime.workbench.renderers.base.BaseStackRenderer

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.