/******************************************************************************* * Copyright (c) 2006 Sybase, Inc. 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: * Sybase, Inc. - initial API and implementation *******************************************************************************/ package org.eclipse.jst.pagedesigner.jsf.ui.elementedit.jsfhtml; import java.util.Iterator; import java.util.List; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.geometry.Point; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.gef.DragTracker; import org.eclipse.gef.EditPart; import org.eclipse.gef.EditPolicy; import org.eclipse.gef.GraphicalEditPart; import org.eclipse.gef.Request; import org.eclipse.gef.commands.Command; import org.eclipse.gef.requests.DropRequest; import org.eclipse.gef.requests.LocationRequest; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jst.jsf.common.dom.TagIdentifier; import org.eclipse.jst.jsf.core.internal.tld.IJSFConstants; import org.eclipse.jst.pagedesigner.actions.single.SelectEditPartAction; import org.eclipse.jst.pagedesigner.editors.PageDesignerActionConstants; import org.eclipse.jst.pagedesigner.editpolicies.DragMoveEditPolicy; import org.eclipse.jst.pagedesigner.editpolicies.ElementResizableEditPolicy; import org.eclipse.jst.pagedesigner.jsf.core.dom.JSFDOMUtil; import org.eclipse.jst.pagedesigner.jsf.ui.JSFUIPlugin; import org.eclipse.jst.pagedesigner.jsf.ui.actions.DeleteHColumnHeaderFooterAction; import org.eclipse.jst.pagedesigner.jsf.ui.actions.DeleteHeaderFooterAction; import org.eclipse.jst.pagedesigner.jsf.ui.actions.InsertHColumnHeaderFooterAction; import org.eclipse.jst.pagedesigner.jsf.ui.actions.InsertHeaderFooterAction; import org.eclipse.jst.pagedesigner.jsf.ui.commands.jsfhtml.DataTableDeleteColumnCommand; import org.eclipse.jst.pagedesigner.jsf.ui.commands.jsfhtml.DataTableDeleteColumnHeaderCommand; import org.eclipse.jst.pagedesigner.jsf.ui.commands.jsfhtml.DataTableDeleteHeaderCommand; import org.eclipse.jst.pagedesigner.jsf.ui.commands.jsfhtml.DataTableInsertColumnCommand; import org.eclipse.jst.pagedesigner.jsf.ui.commands.jsfhtml.DataTableInsertColumnHeaderCommand; import org.eclipse.jst.pagedesigner.jsf.ui.commands.jsfhtml.DataTableInsertHeaderCommand; import org.eclipse.jst.pagedesigner.jsf.ui.elementedit.request.DeleteHColumnHeaderFooterRequest; import org.eclipse.jst.pagedesigner.jsf.ui.elementedit.request.DeleteHeaderFooterRequest; import org.eclipse.jst.pagedesigner.jsf.ui.elementedit.request.InsertHColumnHeaderFooterRequest; import org.eclipse.jst.pagedesigner.jsf.ui.elementedit.request.InsertHeaderFooterRequest; import org.eclipse.jst.pagedesigner.jsf.ui.elementedit.util.DataTableUtil; import org.eclipse.jst.pagedesigner.parts.ElementEditPart; import org.eclipse.jst.pagedesigner.parts.NodeEditPart; import org.eclipse.jst.pagedesigner.tableedit.DeleteRowColumnAction; import org.eclipse.jst.pagedesigner.tableedit.InsertRowColumnAction; import org.eclipse.jst.pagedesigner.tableedit.TableInsertRequest; import org.eclipse.jst.pagedesigner.tableedit.TableResizeRequest; import org.eclipse.jst.pagedesigner.tableedit.TableRowColumnDeleteRequest; import org.eclipse.jst.pagedesigner.tools.ObjectModeDragTracker; import org.eclipse.jst.pagedesigner.validation.caret.ActionData; import org.eclipse.jst.pagedesigner.validation.caret.DefaultPositionRule; import org.eclipse.jst.pagedesigner.validation.caret.DnDPositionValidator; import org.eclipse.jst.pagedesigner.validation.caret.DropActionData; import org.eclipse.jst.pagedesigner.validation.caret.IPositionMediator; import org.eclipse.jst.pagedesigner.validation.caret.Target; import org.eclipse.jst.pagedesigner.validation.caret.DropActionData.DropData; import org.eclipse.jst.pagedesigner.viewer.IHTMLGraphicalViewer; import org.eclipse.swt.graphics.Cursor; import org.eclipse.swt.graphics.Image; import org.eclipse.wst.xml.core.internal.provisional.document.IDOMElement; import org.w3c.dom.Element; import org.w3c.dom.Node; /** * @author mengbo * @version 1.5 */ public class DataTableElementEdit extends DefaultJSFHTMLElementEdit { private final static Action EMPTY_ACTION = new Action() { // TODO: why? }; private final static int FAKE_INDEX = -10; /* (non-Javadoc) * @see org.eclipse.jst.pagedesigner.elementedit.IElementEdit#fillContextMenu(org.eclipse.jface.action.IMenuManager, org.w3c.dom.Element) */ public void fillContextMenu(IMenuManager contextMenu, Element ele) { super.fillContextMenu(contextMenu, ele); final IMenuManager tableMenu = new MenuManager(JSFUIPlugin.getResourceString("ElementEdit.Submenu.DataTable"));//$NON-NLS-1$ final ElementEditPart editPart = (ElementEditPart) ((IDOMElement) ele).getAdapterFor(EditPart.class); // ok, we passed the checking, now let's create the actions. tableMenu.add(EMPTY_ACTION); tableMenu.addMenuListener(new IMenuListener() { public void menuAboutToShow(IMenuManager manager) { tableMenu.removeAll(); fillTableMenu(editPart, FAKE_INDEX, tableMenu); } }); contextMenu.appendToGroup(PageDesignerActionConstants.GROUP_CONTAINER, tableMenu); } /* (non-Javadoc) * @see org.eclipse.jst.pagedesigner.elementedit.IElementEdit#fillContainerContextMenu(org.eclipse.jface.action.IMenuManager, org.eclipse.jst.pagedesigner.parts.ElementEditPart, org.eclipse.jst.pagedesigner.parts.NodeEditPart, org.eclipse.jface.viewers.ISelection) */ public boolean fillContainerContextMenu(IMenuManager contextMenu, final ElementEditPart elePart, NodeEditPart nodePart, ISelection innerSelection) { Element table = (Element) elePart.getModel(); Node node = (Node) nodePart.getModel(); DataTableUtil util = new DataTableUtil(table); Element columnParent = util.findHColumnParent(node); final int cellColumn = util.getColumnIndex(columnParent); final IMenuManager tableMenu = new MenuManager(JSFUIPlugin.getResourceString("ElementEdit.Submenu.DataTable"));//$NON-NLS-1$ // ok, we passed the checking, now let's create the actions. tableMenu.add(EMPTY_ACTION); tableMenu.addMenuListener(new IMenuListener() { public void menuAboutToShow(IMenuManager manager) { tableMenu.removeAll(); fillTableMenu(elePart, cellColumn, tableMenu); } }); contextMenu.appendToGroup(PageDesignerActionConstants.GROUP_CONTAINER, tableMenu); return true; } /** * @param elePart * @param cellColumn * @param tableMenu */ private void fillTableMenu(ElementEditPart elePart, int cellColumn, IMenuManager tableMenu) { SelectEditPartAction action = SelectEditPartAction.create(JSFUIPlugin .getResourceString("ElementEdit.Submenu.DataTable.SelectTable"), elePart);//$NON-NLS-1$ tableMenu.add(action); tableMenu.add(new Separator()); { InsertRowColumnAction insertColumnBeforeAction = new InsertRowColumnAction(JSFUIPlugin .getResourceString("ElementEdit.Submenu.DataTable.InsertColumnBefore"), //$NON-NLS-1$ elePart, cellColumn, false, true); tableMenu.add(insertColumnBeforeAction); InsertRowColumnAction insertColumnAfterAction = new InsertRowColumnAction(JSFUIPlugin .getResourceString("ElementEdit.Submenu.DataTable.InsertColumnAfter"),//$NON-NLS-1$ elePart, cellColumn, false, false); tableMenu.add(insertColumnAfterAction); tableMenu.add(new Separator()); } { DeleteRowColumnAction deleteColumnAction = new DeleteRowColumnAction(JSFUIPlugin .getResourceString("ElementEdit.Submenu.DataTable.DeleteColumn"), //$NON-NLS-1$ elePart, cellColumn, false); tableMenu.add(deleteColumnAction); tableMenu.add(new Separator()); } { InsertHeaderFooterAction headerAction = new InsertHeaderFooterAction(JSFUIPlugin .getResourceString("ElementEdit.Submenu.InsertTableHeader"), elePart, true);//$NON-NLS-1$ tableMenu.add(headerAction); InsertHeaderFooterAction footerAction = new InsertHeaderFooterAction(JSFUIPlugin .getResourceString("ElementEdit.Submenu.InsertTableFooter"), elePart, false);//$NON-NLS-1$ tableMenu.add(footerAction); DeleteHeaderFooterAction delHeaderAction = new DeleteHeaderFooterAction(JSFUIPlugin .getResourceString("ElementEdit.Submenu.DeleteTableHeader"), elePart, true);//$NON-NLS-1$ tableMenu.add(delHeaderAction); DeleteHeaderFooterAction delFooterAction = new DeleteHeaderFooterAction(JSFUIPlugin .getResourceString("ElementEdit.Submenu.DeleteTableFooter"), elePart, false);//$NON-NLS-1$ tableMenu.add(delFooterAction); tableMenu.add(new Separator()); } { InsertHColumnHeaderFooterAction hColHeaderAction = new InsertHColumnHeaderFooterAction(JSFUIPlugin .getResourceString("ElementEdit.Submenu.InsertColumnHeader"),//$NON-NLS-1$ elePart, true); tableMenu.add(hColHeaderAction); InsertHColumnHeaderFooterAction hColFooterAction = new InsertHColumnHeaderFooterAction(JSFUIPlugin .getResourceString("ElementEdit.Submenu.InsertColumnFooter"),//$NON-NLS-1$ elePart, false); tableMenu.add(hColFooterAction); DeleteHColumnHeaderFooterAction delColHeader = new DeleteHColumnHeaderFooterAction(JSFUIPlugin .getResourceString("ElementEdit.Submenu.DeleteColumnHeader"),//$NON-NLS-1$ elePart, true); tableMenu.add(delColHeader); DeleteHColumnHeaderFooterAction delColFooter = new DeleteHColumnHeaderFooterAction(JSFUIPlugin .getResourceString("ElementEdit.Submenu.DeleteColumnFooter"),//$NON-NLS-1$ elePart, false); tableMenu.add(delColFooter); } } /* (non-Javadoc) * @see org.eclipse.jst.pagedesigner.elementedit.IElementEdit#createEditPolicies(org.eclipse.jst.pagedesigner.parts.ElementEditPart) */ public void createEditPolicies(ElementEditPart part) { part.installEditPolicy(EditPolicy.SELECTION_FEEDBACK_ROLE, new DataTableResizePolicy(part)); part.installEditPolicy(EditPolicy.PRIMARY_DRAG_ROLE, new MyDragMoveEditPolicy()); } static class DataTableResizePolicy extends ElementResizableEditPolicy { private static final String COLUMN_SELECT_IMAGE_FILE = "column_select.gif"; //$NON-NLS-1$ ElementEditPart _part; Cursor _columnSelectCursor; /** * @param part */ public DataTableResizePolicy(ElementEditPart part) { _part = part; } public void deactivate() { super.deactivate(); if (_columnSelectCursor != null && !_columnSelectCursor.isDisposed()) { _columnSelectCursor.dispose(); _columnSelectCursor = null; } } private Cursor getColumnSelectCursor() { if (_columnSelectCursor == null) { final Image cursorImage = JSFUIPlugin.getDefault().getImage(COLUMN_SELECT_IMAGE_FILE); _columnSelectCursor = new Cursor(null, cursorImage.getImageData(), 2, 5); } return _columnSelectCursor; } /* (non-Javadoc) * @see org.eclipse.gef.editpolicies.ResizableEditPolicy#getCommand(org.eclipse.gef.Request) */ public Command getCommand(Request request) { IHTMLGraphicalViewer viewer = (IHTMLGraphicalViewer) _part.getViewer(); Element dataTable = (Element) _part.getIDOMNode(); if (request instanceof TableResizeRequest) { return super.getCommand(request); } else if (request instanceof TableInsertRequest) { TableInsertRequest tableInsertRequest = (TableInsertRequest) request; if (tableInsertRequest.isRow()) { // don't support insert row. return null; } int index = tableInsertRequest.getIndex() + (tableInsertRequest.isBefore() ? 0 : 1); return new DataTableInsertColumnCommand(viewer, dataTable, index); } else if (request instanceof InsertHeaderFooterRequest) { InsertHeaderFooterRequest req = (InsertHeaderFooterRequest) request; boolean isHeader = req.isHeader(); return new DataTableInsertHeaderCommand(viewer, dataTable, isHeader); } else if (request instanceof DeleteHeaderFooterRequest) { DeleteHeaderFooterRequest req = (DeleteHeaderFooterRequest) request; boolean isHeader = req.isHeader(); return new DataTableDeleteHeaderCommand(viewer, dataTable, isHeader); } else if (request instanceof InsertHColumnHeaderFooterRequest) { InsertHColumnHeaderFooterRequest req = (InsertHColumnHeaderFooterRequest) request; boolean isHeader = req.isHeader(); return new DataTableInsertColumnHeaderCommand(viewer, dataTable, isHeader); } else if (request instanceof DeleteHColumnHeaderFooterRequest) { DeleteHColumnHeaderFooterRequest req = (DeleteHColumnHeaderFooterRequest) request; boolean isHeader = req.isHeader(); return new DataTableDeleteColumnHeaderCommand(viewer, dataTable, isHeader); } else if (request instanceof TableRowColumnDeleteRequest) { TableRowColumnDeleteRequest deleteReq = (TableRowColumnDeleteRequest) request; if (deleteReq.isRow()) { return null; } return new DataTableDeleteColumnCommand(viewer, dataTable, deleteReq.getIndex()); } return super.getCommand(request); } public Cursor getSelectionToolCursor(Point mouseLocation) { if (hitTestColumnSelection(mouseLocation)) { return getColumnSelectCursor(); } return null; } protected DragTracker getSelectionTracker(LocationRequest request) { final Point mouseLocator = request.getLocation(); if (hitTestColumnSelection(mouseLocator)) { ObjectModeDragTracker dragTracker = new ObjectModeDragTracker(getHost()) { protected boolean handleButtonDown(int button) { // only customize the case where we are in a column selection mode if (button == 1) { EditPart retarget = getRetargetSelectionEditPart(mouseLocator); if (retarget != null) { setSourceEditPart(retarget); } } // default return super.handleButtonDown(button); } }; dragTracker.setDefaultCursor(getSelectionToolCursor(mouseLocator)); return dragTracker; } return new ObjectModeDragTracker(getHost()); } public DragTracker getSelectionDragTracker(LocationRequest request) { return getSelectionTracker(request); } /** * @param mouseLocation * @return the edit part fo the given mouse location */ public EditPart getRetargetSelectionEditPart(Point mouseLocation) { if (hitTestColumnSelection(mouseLocation)) { GraphicalEditPart editPart = (GraphicalEditPart) getHost(); List children = editPart.getChildren(); for (Iterator it = children.iterator(); it.hasNext();) { GraphicalEditPart child = (GraphicalEditPart) it.next(); if (child instanceof NodeEditPart) { Node childNode = ((NodeEditPart)child).getDOMNode(); if (JSFDOMUtil.isHColumn(childNode)) { Point relativeMousePointer = mouseLocation.getCopy(); IFigure hostFigure = child.getFigure(); hostFigure.translateToRelative(relativeMousePointer); Rectangle hostBounds = hostFigure.getBounds(); if (relativeMousePointer.x >= hostBounds.x && relativeMousePointer.x < hostBounds.x+hostBounds.width) { return child; } } } } } // otherwise, don't retarget return null; } private boolean hitTestColumnSelection(Point mouseLocation) { final GraphicalEditPart part = (GraphicalEditPart) getHost(); final IFigure panelFigure = part.getFigure(); Point relativeLocation = mouseLocation.getCopy(); panelFigure.translateToRelative(relativeLocation); final int yoffsetAbs = Math.abs(panelFigure.getBounds().y - relativeLocation.y); if (yoffsetAbs <= 4) { return true; } return false; } } /** * @author cbateman * */ public static class MyDragMoveEditPolicy extends DragMoveEditPolicy { protected IPositionMediator createDropChildValidator( DropRequest r) { DropData dropData = createDropData(r); if (dropData!=null) { DnDPositionValidator validator = new DnDPositionValidator(new DropActionData( ActionData.COMPONENT_MOVE, dropData)); validator.addRule(new OnlyColumnsAndFacetsRule(validator.getActionData())); return validator; } return null; } private static class OnlyColumnsAndFacetsRule extends DefaultPositionRule { /** * @param actionData */ public OnlyColumnsAndFacetsRule(ActionData actionData) { super(actionData); } public boolean isEditable(Target target) { if (IJSFConstants.TAG_IDENTIFIER_DATA_TABLE.isSameTagType(target.getTagWrapper())) { return isDataDroppable(); } return true; } private boolean isDataDroppable() { ActionData actionData = getActionData(); if (actionData instanceof DropActionData) { DropActionData dropActionData = (DropActionData) actionData; TagIdentifier tagId = (TagIdentifier) dropActionData.getDropData().getTagIdentifiers().get(0); if (IJSFConstants.TAG_IDENTIFIER_FACET.isSameTagType(tagId) || IJSFConstants.TAG_IDENTIFIER_COLUMN.isSameTagType(tagId)) { return true; } } return false; } } } }