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

Source Code of com.google.gdt.eclipse.designer.uibinder.model.widgets.GridInfo$Cell

/*******************************************************************************
* 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.uibinder.model.widgets;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
import com.google.gdt.eclipse.designer.GwtToolkitDescription;
import com.google.gdt.eclipse.designer.uibinder.Activator;

import org.eclipse.wb.core.model.ObjectInfo;
import org.eclipse.wb.core.model.broadcast.ObjectEventListener;
import org.eclipse.wb.core.model.broadcast.ObjectInfoDelete;
import org.eclipse.wb.core.model.broadcast.ObjectInfoPresentationDecorateText;
import org.eclipse.wb.core.model.broadcast.ObjectInfoTreeComplete;
import org.eclipse.wb.draw2d.geometry.Rectangle;
import org.eclipse.wb.internal.core.model.util.ObjectInfoAction;
import org.eclipse.wb.internal.core.utils.GenericsUtils;
import org.eclipse.wb.internal.core.utils.execution.RunnableEx;
import org.eclipse.wb.internal.core.utils.reflect.ReflectionUtils;
import org.eclipse.wb.internal.core.utils.xml.DocumentElement;
import org.eclipse.wb.internal.core.xml.editor.DesignContextMenuProvider;
import org.eclipse.wb.internal.core.xml.model.AbstractComponentInfo;
import org.eclipse.wb.internal.core.xml.model.EditorContext;
import org.eclipse.wb.internal.core.xml.model.XmlObjectInfo;
import org.eclipse.wb.internal.core.xml.model.association.Associations;
import org.eclipse.wb.internal.core.xml.model.broadcast.XmlObjectMove;
import org.eclipse.wb.internal.core.xml.model.creation.CreationSupport;
import org.eclipse.wb.internal.core.xml.model.creation.TagCreationSupport;
import org.eclipse.wb.internal.core.xml.model.description.ComponentDescription;
import org.eclipse.wb.internal.core.xml.model.description.ComponentDescriptionHelper;
import org.eclipse.wb.internal.core.xml.model.utils.XmlObjectUtils;

import org.eclipse.jface.action.IMenuManager;
import org.eclipse.swt.graphics.Image;

import org.apache.commons.lang.StringUtils;

import java.util.List;
import java.util.Map;

/**
* Model for <code>com.google.gwt.user.client.ui.Grid</code> in GWT UiBinder.
*
* @author scheglov_ke
* @coverage GWT.UiBinder.model
*/
public final class GridInfo extends PanelInfo {
  ////////////////////////////////////////////////////////////////////////////
  //
  // Constructor
  //
  ////////////////////////////////////////////////////////////////////////////
  public GridInfo(EditorContext context,
      ComponentDescription description,
      CreationSupport creationSupport) throws Exception {
    super(context, description, creationSupport);
    parseRowsCells();
    decorateCellText();
    removeEmptyCustomCell();
    contributeCellContextMenu();
  }

  ////////////////////////////////////////////////////////////////////////////
  //
  // Broadcasts
  //
  ////////////////////////////////////////////////////////////////////////////
  /**
   * Parses "row", "cell" and "customCell" elements into appropriate models.
   */
  private void parseRowsCells() {
    addBroadcastListener(new ObjectInfoTreeComplete() {
      public void invoke() throws Exception {
        Map<DocumentElement, CustomCell> customCells = Maps.newHashMap();
        DocumentElement gridElement = getElement();
        for (DocumentElement rowElement : gridElement.getChildren()) {
          if (rowElement.getTagLocal().equals("row")) {
            Row row = new Row(rowElement);
            addChild(row);
            for (DocumentElement cellElement : rowElement.getChildren()) {
              if (cellElement.getTagLocal().equals("cell")) {
                HtmlCell cell = new HtmlCell(cellElement);
                row.addChild(cell);
              }
              if (cellElement.getTagLocal().equals("customCell")) {
                CustomCell cell = new CustomCell(cellElement);
                row.addChild(cell);
                customCells.put(cellElement, cell);
              }
            }
          }
        }
        // re-bind Widget children to "customCell" models
        for (WidgetInfo widget : getChildrenWidgets()) {
          DocumentElement cellElement = widget.getElement().getParent();
          CustomCell cell = customCells.get(cellElement);
          removeChild(widget);
          cell.addChild(widget);
        }
      }
    });
  }

  /**
   * Decorates text of {@link Cell} with short excerpt of its content.
   */
  private void decorateCellText() {
    addBroadcastListener(new ObjectInfoPresentationDecorateText() {
      public void invoke(ObjectInfo object, String[] text) throws Exception {
        if (object instanceof HtmlCell && isParentOf(object)) {
          DocumentElement element = ((HtmlCell) object).getElement();
          int beginIndex = element.getOpenTagOffset() + element.getOpenTagLength();
          int endIndex = element.getCloseTagOffset();
          String contentText = getContext().getContent().substring(beginIndex, endIndex);
          contentText = contentText.trim();
          contentText = StringUtils.substring(contentText, 0, 15);
          text[0] += " " + contentText;
        }
      }
    });
  }

  /**
   * {@link CustomCell} should always have a {@link WidgetInfo} child, so when it looses it, we
   * should remove {@link CustomCell} too.
   */
  private void removeEmptyCustomCell() {
    addBroadcastListener(new XmlObjectMove() {
      @Override
      public void after(XmlObjectInfo child, ObjectInfo oldParent, ObjectInfo newParent)
          throws Exception {
        if (oldParent instanceof CustomCell && isParentOf(oldParent)) {
          oldParent.delete();
        }
      }
    });
    addBroadcastListener(new ObjectInfoDelete() {
      @Override
      public void after(ObjectInfo parent, ObjectInfo child) throws Exception {
        if (parent instanceof CustomCell && isParentOf(parent) && !parent.isDeleting()) {
          parent.delete();
        }
      }
    });
  }

  private void contributeCellContextMenu() {
    addBroadcastListener(new ObjectEventListener() {
      @Override
      public void addContextMenu(List<? extends ObjectInfo> objects,
          ObjectInfo object,
          IMenuManager manager) throws Exception {
        if (object instanceof Cell && isParentOf(object)) {
          final Cell cell = (Cell) object;
          final Row row = (Row) cell.getParent();
          addAction(manager, "Insert cell", "insertCell", new RunnableEx() {
            public void run() throws Exception {
              createCell(row, cell);
            }
          });
          addAction(manager, "Append cell", "appendCell", new RunnableEx() {
            public void run() throws Exception {
              Cell nextCell = GenericsUtils.getNextOrNull(row.getCells(), cell);
              createCell(row, nextCell);
            }
          });
        }
      }

      private void addAction(IMenuManager manager,
          String text,
          String iconName,
          final RunnableEx runnable) {
        Image icon = Activator.getImage("info/Grid/" + iconName + ".png");
        manager.appendToGroup(DesignContextMenuProvider.GROUP_TOP, new ObjectInfoAction(
            GridInfo.this, text, icon) {
          @Override
          protected void runEx() throws Exception {
            runnable.run();
          }
        });
      }

      private void createCell(Row row, Cell nextCell) throws Exception {
        HtmlCell newCell = new HtmlCell();
        row.command_CREATE(newCell, nextCell);
        newCell.getElement().setText("New cell", false);
        row.getBroadcastObject().select(ImmutableList.of(newCell));
      }
    });
  }

  ////////////////////////////////////////////////////////////////////////////
  //
  // Access
  //
  ////////////////////////////////////////////////////////////////////////////
  /**
   * @return the {@link Row} children.
   */
  public List<Row> getRows() {
    return getChildren(Row.class);
  }

  ////////////////////////////////////////////////////////////////////////////
  //
  // Refresh
  //
  ////////////////////////////////////////////////////////////////////////////
  @Override
  protected void refresh_fetch() throws Exception {
    setElementsForParts();
    super.refresh_fetch();
  }

  /**
   * Sets DOM elements for {@link GridElement} models.
   */
  private void setElementsForParts() throws Exception {
    Object bodyElement = ReflectionUtils.invokeMethod(getObject(), "getBodyElement()");
    List<Row> rows = getRows();
    Object[] rowElements = getDOM().getChildren(bodyElement);
    for (int i = 0; i < rowElements.length; i++) {
      Object rowElement = rowElements[i];
      if (i < rows.size()) {
        Row row = rows.get(i);
        row.setElement(rowElement);
      }
    }
  }

  ////////////////////////////////////////////////////////////////////////////
  //
  // Commands
  //
  ////////////////////////////////////////////////////////////////////////////
  public void command_MOVE(Row row, Row nextRow) throws Exception {
    XmlObjectUtils.move(row, Associations.direct(), this, nextRow);
  }

  public void command_ADD(Cell cell, Row nextRow) throws Exception {
    Row newRow = command_addNewRow(nextRow);
    newRow.command_MOVE(cell, null);
  }

  public void command_CREATE(WidgetInfo newWidget, Row nextRow) throws Exception {
    Row newRow = command_addNewRow(nextRow);
    newRow.command_CREATE(newWidget, null);
  }

  public void command_ADD(WidgetInfo widget, Row nextRow) throws Exception {
    Row newRow = command_addNewRow(nextRow);
    newRow.command_ADD(widget, null);
  }

  private Row command_addNewRow(Row nextRow) throws Exception {
    Row newRow = new Row();
    XmlObjectUtils.add(newRow, Associations.direct(), this, nextRow);
    return newRow;
  }

  ////////////////////////////////////////////////////////////////////////////
  //
  // GridElement
  //
  ////////////////////////////////////////////////////////////////////////////
  private final Map<String, ComponentDescription> m_gridElementDescriptions = Maps.newTreeMap();

  private ComponentDescription getElementDescription(String name) throws Exception {
    ComponentDescription description = m_gridElementDescriptions.get(name);
    if (description == null) {
      description = new ComponentDescription(Object.class);
      description.setToolkit(GwtToolkitDescription.INSTANCE);
      description.setIcon(ComponentDescriptionHelper.getIcon(
          getContext(),
          getDescription().getComponentClass(),
          "_" + name));
      m_gridElementDescriptions.put(name, description);
    }
    return description;
  }

  public class GridElement extends AbstractComponentInfo {
    private Rectangle m_absoluteBounds;

    ////////////////////////////////////////////////////////////////////////////
    //
    // Constructor
    //
    ////////////////////////////////////////////////////////////////////////////
    public GridElement(ComponentDescription description, DocumentElement element) throws Exception {
      super(GridInfo.this.getContext(), description, new TagCreationSupport(element));
    }

    public GridElement(ComponentDescription description, String tag) throws Exception {
      super(GridInfo.this.getContext(),
          description,
          new TagCreationSupport(GridInfo.this.getElement().getTagNS() + tag));
    }

    @Override
    public Rectangle getAbsoluteBounds() {
      return m_absoluteBounds;
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Refresh
    //
    ////////////////////////////////////////////////////////////////////////////
    @Override
    protected void refresh_fetch() throws Exception {
      fetchBounds();
      super.refresh_fetch();
    }

    private void fetchBounds() {
      Object element = getObject();
      // absolute bounds
      m_absoluteBounds = getState().getAbsoluteBounds(element);
      // model/parent bounds
      Rectangle bounds = m_absoluteBounds.getCopy();
      AbstractComponentInfo parent = (AbstractComponentInfo) getParent();
      bounds.translate(parent.getAbsoluteBounds().getLocation().getNegated());
      bounds.translate(parent.getClientAreaInsets().getNegated());
      setModelBounds(bounds);
    }
  }
  ////////////////////////////////////////////////////////////////////////////
  //
  // Row
  //
  ////////////////////////////////////////////////////////////////////////////
  public final class Row extends GridElement {
    ////////////////////////////////////////////////////////////////////////////
    //
    // Constructor
    //
    ////////////////////////////////////////////////////////////////////////////
    public Row() throws Exception {
      super(getElementDescription("row"), "row");
    }

    public Row(DocumentElement element) throws Exception {
      super(getElementDescription("row"), element);
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Access
    //
    ////////////////////////////////////////////////////////////////////////////
    /**
     * @return the {@link Cell} children.
     */
    public List<Cell> getCells() {
      return getChildren(Cell.class);
    }

    /**
     * Sets DOM element for this {@link Row} and its {@link Cell} children.
     */
    public void setElement(Object rowElement) throws Exception {
      setObject(rowElement);
      List<Cell> cells = getCells();
      Object[] cellElements = getDOM().getChildren(rowElement);
      for (int i = 0; i < cellElements.length; i++) {
        Object cellElement = cellElements[i];
        if (i < cells.size()) {
          Cell cell = cells.get(i);
          cell.setObject(cellElement);
        }
      }
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Commands
    //
    ////////////////////////////////////////////////////////////////////////////
    public void command_CREATE(Cell cell, Cell nextCell) throws Exception {
      XmlObjectUtils.add(cell, Associations.direct(), this, nextCell);
    }

    public void command_MOVE(Cell cell, Cell nextCell) throws Exception {
      XmlObjectUtils.move(cell, Associations.direct(), this, nextCell);
    }

    public void command_CREATE(WidgetInfo newWidget, Cell nextCell) throws Exception {
      CustomCell newCell = command_addNewCustomCell(nextCell);
      newCell.command_CREATE(newWidget);
    }

    public void command_ADD(WidgetInfo widget, Cell nextCell) throws Exception {
      CustomCell newCell = command_addNewCustomCell(nextCell);
      newCell.command_ADD(widget);
    }

    private CustomCell command_addNewCustomCell(Cell nextCell) throws Exception {
      CustomCell newCell = new CustomCell();
      command_CREATE(newCell, nextCell);
      return newCell;
    }
  }
  ////////////////////////////////////////////////////////////////////////////
  //
  // Cell
  //
  ////////////////////////////////////////////////////////////////////////////
  public class Cell extends GridElement {
    public Cell(ComponentDescription description, DocumentElement element) throws Exception {
      super(description, element);
    }

    public Cell(ComponentDescription description, String tag) throws Exception {
      super(description, tag);
    }
  }
  ////////////////////////////////////////////////////////////////////////////
  //
  // HtmlCell
  //
  ////////////////////////////////////////////////////////////////////////////
  public final class HtmlCell extends Cell {
    public HtmlCell(DocumentElement element) throws Exception {
      super(getElementDescription("cell"), element);
    }

    public HtmlCell() throws Exception {
      super(getElementDescription("cell"), "cell");
    }
  }
  ////////////////////////////////////////////////////////////////////////////
  //
  // CustomCell
  //
  ////////////////////////////////////////////////////////////////////////////
  public final class CustomCell extends Cell {
    ////////////////////////////////////////////////////////////////////////////
    //
    // Constructor
    //
    ////////////////////////////////////////////////////////////////////////////
    public CustomCell(DocumentElement element) throws Exception {
      super(getElementDescription("customCell"), element);
    }

    public CustomCell() throws Exception {
      super(getElementDescription("customCell"), "customCell");
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Command
    //
    ////////////////////////////////////////////////////////////////////////////
    public void command_CREATE(WidgetInfo widget) throws Exception {
      XmlObjectUtils.add(widget, Associations.direct(), this, null);
    }

    public void command_ADD(WidgetInfo widget) throws Exception {
      XmlObjectUtils.move(widget, Associations.direct(), this, null);
    }
  }
}
TOP

Related Classes of com.google.gdt.eclipse.designer.uibinder.model.widgets.GridInfo$Cell

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.