Package com.google.gdt.eclipse.designer.gxt.model.widgets

Source Code of com.google.gdt.eclipse.designer.gxt.model.widgets.LayoutContainerInfo

/*******************************************************************************
* Copyright 2011 Google Inc. All Rights Reserved.
*
* 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package com.google.gdt.eclipse.designer.gxt.model.widgets;

import com.google.gdt.eclipse.designer.gxt.ExtGwtToolkitDescription;
import com.google.gdt.eclipse.designer.gxt.IExceptionConstants;
import com.google.gdt.eclipse.designer.gxt.model.layout.DefaultLayoutInfo;
import com.google.gdt.eclipse.designer.gxt.model.layout.ImplicitLayoutCreationSupport;
import com.google.gdt.eclipse.designer.gxt.model.layout.ImplicitLayoutVariableSupport;
import com.google.gdt.eclipse.designer.gxt.model.layout.LayoutDataInfo;
import com.google.gdt.eclipse.designer.gxt.model.layout.LayoutInfo;
import com.google.gdt.eclipse.designer.model.widgets.WidgetInfo;

import org.eclipse.wb.core.editor.IContextMenuConstants;
import org.eclipse.wb.core.model.JavaInfo;
import org.eclipse.wb.core.model.ObjectInfo;
import org.eclipse.wb.core.model.association.AssociationObjects;
import org.eclipse.wb.core.model.association.ImplicitObjectAssociation;
import org.eclipse.wb.core.model.broadcast.JavaEventListener;
import org.eclipse.wb.core.model.broadcast.ObjectEventListener;
import org.eclipse.wb.internal.core.model.JavaInfoUtils;
import org.eclipse.wb.internal.core.model.clipboard.ClipboardCommand;
import org.eclipse.wb.internal.core.model.clipboard.JavaInfoMemento;
import org.eclipse.wb.internal.core.model.creation.ConstructorCreationSupport;
import org.eclipse.wb.internal.core.model.creation.CreationSupport;
import org.eclipse.wb.internal.core.model.creation.IImplicitCreationSupport;
import org.eclipse.wb.internal.core.model.description.ComponentDescription;
import org.eclipse.wb.internal.core.model.description.LayoutDescription;
import org.eclipse.wb.internal.core.model.description.helpers.ComponentDescriptionHelper;
import org.eclipse.wb.internal.core.model.description.helpers.LayoutDescriptionHelper;
import org.eclipse.wb.internal.core.model.generation.statement.PureFlatStatementGenerator;
import org.eclipse.wb.internal.core.model.generation.statement.StatementGenerator;
import org.eclipse.wb.internal.core.model.generation.statement.block.BlockStatementGenerator;
import org.eclipse.wb.internal.core.model.util.ObjectInfoAction;
import org.eclipse.wb.internal.core.model.variable.EmptyInvocationVariableSupport;
import org.eclipse.wb.internal.core.model.variable.VariableSupport;
import org.eclipse.wb.internal.core.utils.ast.AstEditor;
import org.eclipse.wb.internal.core.utils.check.Assert;
import org.eclipse.wb.internal.core.utils.reflect.ReflectionUtils;
import org.eclipse.wb.internal.core.utils.state.EditorState;
import org.eclipse.wb.internal.core.utils.ui.ImageImageDescriptor;

import org.eclipse.jdt.core.dom.Statement;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;

import java.util.List;

/**
* Model for <code>LayoutContainer</code>.
*
* @author scheglov_ke
* @coverage ExtGWT.model
*/
public class LayoutContainerInfo extends ScrollContainerInfo {
  private final LayoutContainerInfo m_this = this;

  ////////////////////////////////////////////////////////////////////////////
  //
  // Constructor
  //
  ////////////////////////////////////////////////////////////////////////////
  public LayoutContainerInfo(AstEditor editor,
      ComponentDescription description,
      CreationSupport creationSupport) throws Exception {
    super(editor, description, creationSupport);
    addBroacastListeners();
  }

  ////////////////////////////////////////////////////////////////////////////
  //
  // Initialize
  //
  ////////////////////////////////////////////////////////////////////////////
  private void addBroacastListeners() throws Exception {
    addBroadcastListener(new JavaEventListener() {
      @Override
      public void clipboardCopy(JavaInfo javaInfo, List<ClipboardCommand> commands)
          throws Exception {
        if (javaInfo == m_this) {
          clipboardCopy_addCommands(commands);
        }
      }
    });
    // context menu
    addBroadcastListener(new ObjectEventListener() {
      @Override
      public void addContextMenu(List<? extends ObjectInfo> objects,
          ObjectInfo object,
          IMenuManager manager) throws Exception {
        if (object == m_this) {
          fillContextMenu(manager);
        }
      }
    });
  }

  /**
   * Fill context menu {@link IMenuManager}.
   */
  protected void fillContextMenu(IMenuManager manager) throws Exception {
    if (hasLayout()) {
      // add "Set layout"
      IMenuManager layoutsManager = new MenuManager("Set layout");
      manager.appendToGroup(IContextMenuConstants.GROUP_LAYOUT, layoutsManager);
      fillLayoutsManager(layoutsManager);
    }
  }

  /**
   * Fills given {@link IMenuManager} with {@link IAction}s for setting new {@link LayoutInfo} on
   * this {@link CompositeInfo}.
   */
  public void fillLayoutsManager(IMenuManager layoutsManager) throws Exception {
    // add layout items
    final AstEditor editor = getEditor();
    ClassLoader editorLoader = EditorState.get(editor).getEditorLoader();
    List<LayoutDescription> descriptions =
        LayoutDescriptionHelper.get(ExtGwtToolkitDescription.INSTANCE);
    for (final LayoutDescription description : descriptions) {
      final Class<?> layoutClass = editorLoader.loadClass(description.getLayoutClassName());
      final String creationId = description.getCreationId();
      ComponentDescription layoutComponentDescription =
          ComponentDescriptionHelper.getDescription(editor, layoutClass);
      ObjectInfoAction action = new ObjectInfoAction(this) {
        @Override
        protected void runEx() throws Exception {
          description.ensureLibraries(editor.getJavaProject());
          LayoutInfo layout =
              (LayoutInfo) JavaInfoUtils.createJavaInfo(
                  getEditor(),
                  layoutClass,
                  new ConstructorCreationSupport(creationId, true));
          setLayout(layout);
        }
      };
      action.setText(description.getName());
      action.setImageDescriptor(new ImageImageDescriptor(layoutComponentDescription.getIcon()));
      layoutsManager.add(action);
    }
  }

  @Override
  public void createExposedChildren() throws Exception {
    super.createExposedChildren();
    initialize_createImplicitLayout();
  }

  ////////////////////////////////////////////////////////////////////////////
  //
  // Layout
  //
  ////////////////////////////////////////////////////////////////////////////
  private static final String KEY_LAYOUT_HAS = "layout.has";
  /**
   * We set this key during {@link #setLayout(LayoutInfo)} to prevent implicit {@link LayoutInfo}
   * activation during layout replacement.
   */
  public static final String KEY_DONT_SET_IMPLICIT_LAYOUT = "KEY_DONT_SET_IMPLICIT_LAYOUT";

  /**
   * @return <code>true</code> if {@link WidgetInfo} of this {@link LayoutContainerInfo} can have
   *         {@link LayoutDataInfo}.
   */
  public boolean hasLayoutData() {
    return hasLayout();
  }

  /**
   * @return <code>true</code> if this {@link LayoutContainerInfo} can have {@link LayoutInfo}.
   */
  public final boolean hasLayout() {
    if (isPlaceholder()) {
      return false;
    }
    return JavaInfoUtils.hasTrueParameter(this, KEY_LAYOUT_HAS);
  }

  private void initialize_createImplicitLayout() throws Exception {
    if (hasLayout()) {
      if (initialize_hasExplicitLayout()) {
        return;
      }
      // prepare for creation
      AstEditor editor = getEditor();
      Object layout = ReflectionUtils.invokeMethod(getObject(), "getLayout()");
      // check if same implicit already exists
      if (initialize_removeImplicitLayout(layout)) {
        return;
      }
      // create layout model
      LayoutInfo implicitLayout;
      CreationSupport creationSupport = new ImplicitLayoutCreationSupport(this);
      if (layout == null) {
        implicitLayout = createDefaultImplicitLayout(editor, creationSupport);
      } else {
        Class<?> layoutClass = layout.getClass();
        implicitLayout =
            (LayoutInfo) JavaInfoUtils.createJavaInfo(editor, layoutClass, creationSupport);
      }
      // set variable support
      VariableSupport variableSupport = new ImplicitLayoutVariableSupport(implicitLayout);
      implicitLayout.setVariableSupport(variableSupport);
      // set association
      implicitLayout.setAssociation(new ImplicitObjectAssociation(this));
      // add as child
      addChildFirst(implicitLayout);
    }
  }

  /**
   * @return the implicit {@link LayoutInfo} for this container. Usually {@link DefaultLayoutInfo} ,
   *         so some containers (such as FormPanel) may not have implicit layout set in constructor,
   *         but we still know that some more specific {@link LayoutInfo} should be used.
   */
  protected LayoutInfo createDefaultImplicitLayout(AstEditor editor, CreationSupport creationSupport)
      throws Exception {
    return new DefaultLayoutInfo(editor, creationSupport);
  }

  /**
   * @return <code>true</code> if explicit layout was already set, so we should not try to find
   *         implicit layout anymore.
   */
  private boolean initialize_hasExplicitLayout() {
    List<LayoutInfo> layouts = getChildren(LayoutInfo.class);
    return !layouts.isEmpty()
        && !(layouts.get(0).getCreationSupport() instanceof ImplicitLayoutCreationSupport);
  }

  /**
   * We may call {@link #initialize_createImplicitLayout()} many times, may be after each
   * {@link Statement}, so before adding new implicit layout we should remove existing one.
   *
   * @return <code>true</code> if {@link LayoutInfo} with same object already exists, so it was not
   *         removed and no need for creating new implicit {@link LayoutInfo}.
   */
  private boolean initialize_removeImplicitLayout(Object layoutObject) throws Exception {
    for (JavaInfo child : getChildrenJava()) {
      if (child.getCreationSupport() instanceof ImplicitLayoutCreationSupport) {
        if (child.getObject() != layoutObject) {
          return true;
        }
        ImplicitLayoutCreationSupport creationSupport =
            (ImplicitLayoutCreationSupport) child.getCreationSupport();
        creationSupport.removeForever();
        break;
      }
    }
    return false;
  }

  /**
   * @return the current {@link LayoutInfo} for this composite. Can not return <code>null</code>.
   *
   * @throws IllegalStateException
   *           if no {@link LayoutInfo} found.
   */
  public final LayoutInfo getLayout() {
    Assert.isTrueException(hasLayout(), IExceptionConstants.NO_LAYOUT_EXPECTED, this);
    // try to find layout
    for (ObjectInfo child : getChildren()) {
      if (child instanceof LayoutInfo) {
        return (LayoutInfo) child;
      }
    }
    // composite that has layout, should always have some layout model
    throw new IllegalStateException("Composite should always have layout");
  }

  /**
   * Sets new {@link LayoutInfo}.
   */
  public final void setLayout(LayoutInfo newLayout) throws Exception {
    putArbitraryValue(KEY_DONT_SET_IMPLICIT_LAYOUT, Boolean.TRUE);
    startEdit();
    try {
      // remove old layout
      {
        LayoutInfo oldLayout = getLayout();
        oldLayout.delete();
      }
      // prepare StatementGenerator
      StatementGenerator statementGenerator;
      if (JavaInfoUtils.hasTrueParameter(newLayout, "layout.setInBlock")) {
        statementGenerator = BlockStatementGenerator.INSTANCE;
      } else {
        statementGenerator = PureFlatStatementGenerator.INSTANCE;
      }
      // set new layout
      VariableSupport variableSupport =
          new EmptyInvocationVariableSupport(newLayout, "%parent%.setLayout(%child%)", 0);
      JavaInfoUtils.add(
          newLayout,
          variableSupport,
          statementGenerator,
          AssociationObjects.invocationChildNull(),
          this,
          null);
    } finally {
      endEdit();
      putArbitraryValue(KEY_DONT_SET_IMPLICIT_LAYOUT, Boolean.FALSE);
    }
  }

  ////////////////////////////////////////////////////////////////////////////
  //
  // Clipboard
  //
  ////////////////////////////////////////////////////////////////////////////
  /**
   * Adds commands for coping this {@link LayoutContainerInfo}.
   */
  protected void clipboardCopy_addCommands(List<ClipboardCommand> commands) throws Exception {
    if (hasLayout()) {
      LayoutInfo layout = getLayout();
      if (layout.getCreationSupport() instanceof IImplicitCreationSupport) {
        // no need to set implicit layout
      } else {
        final JavaInfoMemento layoutMemento = JavaInfoMemento.createMemento(layout);
        commands.add(new ClipboardCommand() {
          private static final long serialVersionUID = 0L;

          @Override
          public void execute(JavaInfo javaInfo) throws Exception {
            LayoutContainerInfo composite = (LayoutContainerInfo) javaInfo;
            LayoutInfo newLayout = (LayoutInfo) layoutMemento.create(javaInfo);
            composite.setLayout(newLayout);
            layoutMemento.apply();
          }
        });
      }
    }
  }
}
TOP

Related Classes of com.google.gdt.eclipse.designer.gxt.model.widgets.LayoutContainerInfo

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.