Java tutorial
/******************************************************************************* * 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); } } }