/** * Copyright (c) 2006, 2007 Borland Software Corporation 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: * Borland Software Corporation - initial API and implementation */ package org.eclipse.gmf.graphdef.editor.edit.parts; import java.util.List; import org.eclipse.draw2d.Graphics; import org.eclipse.draw2d.GridData; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.LayoutManager; import org.eclipse.draw2d.ToolbarLayout; import org.eclipse.draw2d.geometry.PointList; 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.Request; import org.eclipse.gef.EditPartViewer.Conditional; import org.eclipse.gef.editpolicies.LayoutEditPolicy; import org.eclipse.gef.requests.ChangeBoundsRequest; import org.eclipse.gmf.gmfgraph.Alignment; import org.eclipse.gmf.gmfgraph.BasicFont; import org.eclipse.gmf.gmfgraph.BorderLayout; import org.eclipse.gmf.gmfgraph.BorderLayoutData; import org.eclipse.gmf.gmfgraph.Color; import org.eclipse.gmf.gmfgraph.ConstantColor; import org.eclipse.gmf.gmfgraph.Dimension; import org.eclipse.gmf.gmfgraph.FlowLayout; import org.eclipse.gmf.gmfgraph.Font; import org.eclipse.gmf.gmfgraph.GMFGraphPackage; import org.eclipse.gmf.gmfgraph.GridLayout; import org.eclipse.gmf.gmfgraph.GridLayoutData; import org.eclipse.gmf.gmfgraph.Layout; import org.eclipse.gmf.gmfgraph.LayoutData; import org.eclipse.gmf.gmfgraph.LineKind; import org.eclipse.gmf.gmfgraph.Point; import org.eclipse.gmf.gmfgraph.RGBColor; import org.eclipse.gmf.gmfgraph.RealFigure; import org.eclipse.gmf.gmfgraph.StackLayout; import org.eclipse.gmf.gmfgraph.XYLayout; import org.eclipse.gmf.gmfgraph.XYLayoutData; import org.eclipse.gmf.graphdef.editor.edit.policies.BorderLayoutEditPolicy; import org.eclipse.gmf.graphdef.editor.edit.policies.FigureContainerXYLayoutEditPolicy; import org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart; import org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeNodeEditPart; import org.eclipse.gmf.runtime.diagram.ui.l10n.DiagramColorRegistry; import org.eclipse.gmf.runtime.diagram.ui.requests.RequestConstants; import org.eclipse.gmf.runtime.diagram.ui.tools.DragEditPartsTrackerEx; import org.eclipse.gmf.runtime.notation.View; import org.eclipse.jface.resource.FontDescriptor; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.FontData; import org.eclipse.swt.graphics.RGB; public abstract class AbstractFigureEditPart extends ShapeNodeEditPart { private static Integer getGridDataAlignment(Alignment alignment) { switch (alignment.getValue()) { case Alignment.BEGINNING: return GridData.BEGINNING; case Alignment.END: return GridData.END; case Alignment.CENTER: return GridData.CENTER; case Alignment.FILL: return GridData.FILL; } return null; } private static int getFlowLayoutAllignment(Alignment alignment, boolean isToolbar) { switch (alignment.getValue()) { case Alignment.BEGINNING: return isToolbar ? ToolbarLayout.ALIGN_TOPLEFT : org.eclipse.draw2d.FlowLayout.ALIGN_LEFTTOP; case Alignment.END: return isToolbar ? ToolbarLayout.ALIGN_BOTTOMRIGHT : org.eclipse.draw2d.FlowLayout.ALIGN_RIGHTBOTTOM; } return isToolbar ? ToolbarLayout.ALIGN_CENTER : org.eclipse.draw2d.FlowLayout.ALIGN_CENTER; } protected static int getLineStyle(LineKind lineKind) { switch (lineKind.getValue()) { case LineKind.LINE_DASH: { return Graphics.LINE_DASH; } case LineKind.LINE_DOT: { return Graphics.LINE_DOT; } case LineKind.LINE_DASHDOT: { return Graphics.LINE_DASHDOT; } case LineKind.LINE_DASHDOTDOT: { return Graphics.LINE_DASHDOTDOT; } case LineKind.LINE_CUSTOM: { return Graphics.LINE_CUSTOM; } default: { return Graphics.LINE_SOLID; } } } protected static org.eclipse.swt.graphics.Color getColor(Color modelColor) { if (modelColor instanceof ConstantColor) { ConstantColor constantColor = (ConstantColor) modelColor; switch (constantColor.getValue()) { case BLACK_LITERAL: return org.eclipse.draw2d.ColorConstants.black; case BLUE_LITERAL: return org.eclipse.draw2d.ColorConstants.blue; case CYAN_LITERAL: return org.eclipse.draw2d.ColorConstants.cyan; case DARK_BLUE_LITERAL: return org.eclipse.draw2d.ColorConstants.darkBlue; case DARK_GRAY_LITERAL: return org.eclipse.draw2d.ColorConstants.darkGray; case DARK_GREEN_LITERAL: return org.eclipse.draw2d.ColorConstants.darkGreen; case GRAY_LITERAL: return org.eclipse.draw2d.ColorConstants.gray; case GREEN_LITERAL: return org.eclipse.draw2d.ColorConstants.green; case LIGHT_BLUE_LITERAL: return org.eclipse.draw2d.ColorConstants.lightBlue; case LIGHT_GRAY_LITERAL: return org.eclipse.draw2d.ColorConstants.lightGray; case LIGHT_GREEN_LITERAL: return org.eclipse.draw2d.ColorConstants.lightGreen; case ORANGE_LITERAL: return org.eclipse.draw2d.ColorConstants.orange; case RED_LITERAL: return org.eclipse.draw2d.ColorConstants.red; case WHITE_LITERAL: return org.eclipse.draw2d.ColorConstants.white; case YELLOW_LITERAL: return org.eclipse.draw2d.ColorConstants.yellow; } } else if (modelColor instanceof RGBColor) { RGBColor rgbColor = (RGBColor) modelColor; return DiagramColorRegistry.getInstance().getColor(new RGB(rgbColor.getRed(), rgbColor.getGreen(), rgbColor.getBlue())); } return null; } private static boolean isAppropriateLayoutEditPolicy(Layout layout, EditPolicy editPolicy) { if (layout instanceof BorderLayout) { return editPolicy instanceof BorderLayoutEditPolicy; } else { return editPolicy instanceof FigureContainerXYLayoutEditPolicy; } } private FontData myCachedFontData; private boolean myDragAllowed = true; public AbstractFigureEditPart(View view) { super(view); } private Object getLayoutConstraint() { RealFigure realFigure = getRealFigure(); if (realFigure == null || realFigure.getLayoutData() == null) { return null; } LayoutData layoutData = realFigure.getLayoutData(); switch (layoutData.eClass().getClassifierID()) { case GMFGraphPackage.BORDER_LAYOUT_DATA: { BorderLayoutData borderLayoutData = (BorderLayoutData) layoutData; if (borderLayoutData.getAlignment() != null) { switch (borderLayoutData.getAlignment().getValue()) { case Alignment.CENTER: case Alignment.FILL: { return org.eclipse.draw2d.BorderLayout.CENTER; } case Alignment.BEGINNING: { return borderLayoutData.isVertical() ? org.eclipse.draw2d.BorderLayout.TOP : org.eclipse.draw2d.BorderLayout.LEFT; } case Alignment.END: { return borderLayoutData.isVertical() ? org.eclipse.draw2d.BorderLayout.BOTTOM : org.eclipse.draw2d.BorderLayout.RIGHT; } } } break; } case GMFGraphPackage.CUSTOM_LAYOUT_DATA: { // TODO: implement custom layout break; } case GMFGraphPackage.GRID_LAYOUT_DATA: { GridLayoutData gridLayoutData = (GridLayoutData) layoutData; GridData result = new GridData(); result.grabExcessHorizontalSpace = gridLayoutData.isGrabExcessHorizontalSpace(); result.grabExcessVerticalSpace = gridLayoutData.isGrabExcessVerticalSpace(); Integer alignment = getGridDataAlignment(gridLayoutData.getHorizontalAlignment()); if (alignment != null) { result.horizontalAlignment = alignment; } alignment = getGridDataAlignment(gridLayoutData.getVerticalAlignment()); if (alignment != null) { result.verticalAlignment = alignment; } result.verticalSpan = gridLayoutData.getVerticalSpan(); result.horizontalSpan = gridLayoutData.getHorizontalSpan(); result.horizontalIndent = getMapMode().DPtoLP(gridLayoutData.getHorizontalIndent()); if (gridLayoutData.getSizeHint() != null) { result.widthHint = getMapMode().DPtoLP(gridLayoutData.getSizeHint().getDx()); result.heightHint = getMapMode().DPtoLP(gridLayoutData.getSizeHint().getDy()); } else { result.widthHint = SWT.DEFAULT; result.heightHint = SWT.DEFAULT; } return result; } case GMFGraphPackage.XY_LAYOUT_DATA: { final XYLayoutData xyLayoutData = (XYLayoutData) layoutData; Rectangle result = new Rectangle(); if (xyLayoutData.getTopLeft() != null && xyLayoutData.getSize() != null) { result.setLocation(getMapMode().DPtoLP(xyLayoutData.getTopLeft().getX()), getMapMode().DPtoLP(xyLayoutData.getTopLeft().getY())); result.setSize(getMapMode().DPtoLP(xyLayoutData.getSize().getDx()), getMapMode().DPtoLP(xyLayoutData.getSize().getDy())); } return result; } } return null; } protected void addChildVisual(EditPart childEditPart, int index) { IFigure child = ((GraphicalEditPart) childEditPart).getFigure(); Object layoutConstraint = null; if (childEditPart instanceof AbstractFigureEditPart) { layoutConstraint = ((AbstractFigureEditPart) childEditPart).getLayoutConstraint(); } else if (childEditPart instanceof AbstractPointEditPart) { layoutConstraint = ((AbstractPointEditPart) childEditPart).getLayoutConstraint(); } LayoutManager layoutManager = getContentPane().getLayoutManager(); if (layoutManager instanceof org.eclipse.draw2d.BorderLayout) { if (org.eclipse.draw2d.BorderLayout.BOTTOM != layoutConstraint && org.eclipse.draw2d.BorderLayout.CENTER != layoutConstraint && org.eclipse.draw2d.BorderLayout.LEFT != layoutConstraint && org.eclipse.draw2d.BorderLayout.RIGHT != layoutConstraint && org.eclipse.draw2d.BorderLayout.TOP != layoutConstraint) { // TODO: put figure into special pain with unconstrained // elements instead layoutConstraint = null; } } else if (layoutManager instanceof GridLayout) { if (false == layoutConstraint instanceof GridData) { layoutConstraint = null; } } else if (layoutManager instanceof org.eclipse.draw2d.XYLayout) { if (false == layoutConstraint instanceof Rectangle) { // TODO: put figure into special pain with unconstrained // elements instead layoutConstraint = null; } } getContentPane().add(child, layoutConstraint, index); } protected LayoutManager getLayoutManager(Layout layout) { if (layout instanceof BorderLayout) { BorderLayout borderLayout = (BorderLayout) layout; org.eclipse.draw2d.BorderLayout layoutManager = new org.eclipse.draw2d.BorderLayout(); if (borderLayout.getSpacing() != null) { layoutManager.setHorizontalSpacing(getMapMode().DPtoLP(borderLayout.getSpacing().getDx())); layoutManager.setVerticalSpacing(getMapMode().DPtoLP(borderLayout.getSpacing().getDy())); } return layoutManager; } if (layout instanceof FlowLayout) { FlowLayout flowLayout = (FlowLayout) layout; if (flowLayout.isForceSingleLine()) { ToolbarLayout layoutManager = new ToolbarLayout(); layoutManager.setStretchMinorAxis(flowLayout.isMatchMinorSize()); layoutManager.setMinorAlignment(getFlowLayoutAllignment(flowLayout.getMinorAlignment(), flowLayout.isForceSingleLine())); layoutManager.setSpacing(flowLayout.getMajorSpacing()); layoutManager.setVertical(flowLayout.isVertical()); return layoutManager; } else { org.eclipse.draw2d.FlowLayout layoutManager = new org.eclipse.draw2d.FlowLayout(); layoutManager.setStretchMinorAxis(flowLayout.isMatchMinorSize()); layoutManager.setMinorAlignment(getFlowLayoutAllignment(flowLayout.getMinorAlignment(), flowLayout.isForceSingleLine())); layoutManager.setMajorAlignment(getFlowLayoutAllignment(flowLayout.getMajorAlignment(), flowLayout.isForceSingleLine())); layoutManager.setMajorSpacing(flowLayout.getMajorSpacing()); layoutManager.setMinorSpacing(flowLayout.getMinorSpacing()); layoutManager.setHorizontal(!flowLayout.isVertical()); return layoutManager; } } if (layout instanceof GridLayout) { GridLayout gridLayout = (GridLayout) layout; org.eclipse.draw2d.GridLayout layoutManager = new org.eclipse.draw2d.GridLayout(); layoutManager.numColumns = gridLayout.getNumColumns(); layoutManager.makeColumnsEqualWidth = gridLayout.isEqualWidth(); if (gridLayout.getMargins() != null) { layoutManager.marginWidth = getMapMode().DPtoLP(gridLayout.getMargins().getDx()); layoutManager.marginHeight = getMapMode().DPtoLP(gridLayout.getMargins().getDy()); } else { int defaultMargin = 5; layoutManager.marginWidth = getMapMode().DPtoLP(defaultMargin); layoutManager.marginHeight = getMapMode().DPtoLP(defaultMargin); } if (gridLayout.getSpacing() != null) { layoutManager.horizontalSpacing = getMapMode().DPtoLP(gridLayout.getSpacing().getDx()); layoutManager.verticalSpacing = getMapMode().DPtoLP(gridLayout.getSpacing().getDy()); } else { int defaultSpacing = 5; layoutManager.horizontalSpacing = getMapMode().DPtoLP(defaultSpacing); layoutManager.verticalSpacing = getMapMode().DPtoLP(defaultSpacing); } return layoutManager; } if (layout instanceof StackLayout) { return new org.eclipse.draw2d.StackLayout(); } if (layout instanceof XYLayout) { return new org.eclipse.draw2d.XYLayout(); } return null; } protected org.eclipse.draw2d.geometry.Dimension getCornerDimensions(int width, int height) { return new org.eclipse.draw2d.geometry.Dimension(getMapMode().DPtoLP(width), getMapMode().DPtoLP(height)); } protected PointList getPointList(List<Point> template) { PointList result = new PointList(); for (Point point : template) { result.addPoint(new org.eclipse.draw2d.geometry.Point(getMapMode().DPtoLP(point.getX()), getMapMode().DPtoLP(point.getY()))); } return result; } protected org.eclipse.draw2d.geometry.Dimension getDraw2dDimension(Dimension dimension) { return new org.eclipse.draw2d.geometry.Dimension(getMapMode().DPtoLP(dimension.getDx()), getMapMode().DPtoLP(dimension.getDy())); } protected org.eclipse.draw2d.geometry.Point getDraw2DPoint(Point point) { return new org.eclipse.draw2d.geometry.Point(getMapMode().DPtoLP(point.getX()), getMapMode().DPtoLP(point.getY())); } protected void refreshLayoutData() { if (!hasParentFigure()) { return; } Object layoutConstraint = getLayoutConstraint(); if (layoutConstraint != null) { getFigure().getParent().setConstraint(getFigure(), layoutConstraint); } /* * It is important to call handleMajorSemanticChange() here because in * case of any changes in LayoutConstraints current EditPart can * visually replace any other existing (sibling) EditParts, so we have * to re-layout parent Figure. */ if (getParent() instanceof AbstractFigureEditPart) { ((AbstractFigureEditPart) getParent()).handleMajorSemanticChange(); } } /** * Parent figure == null if this method was called from setFigure() one. */ private boolean hasParentFigure() { return getFigure().getParent() != null; } protected void refreshLayoutManager() { if (isActive() && !isAppropriateLayoutEditPolicy(getRealFigure().getLayout(), getEditPolicy(EditPolicy.LAYOUT_ROLE))) { installEditPolicy(EditPolicy.LAYOUT_ROLE, createLayoutEditPolicy()); } if (!hasParentFigure()) { return; } handleMajorSemanticChange(); } // Will be generated by GMF for all subclasses protected abstract LayoutEditPolicy createLayoutEditPolicy(); public RealFigure getRealFigure() { View view = getNotationView(); if (view != null && view.getElement() instanceof RealFigure) { return (RealFigure) view.getElement(); } return null; } /** * Using this custom implementation instead of calling super.setFont() * because we have to support unsetting font operation (setFont(null)). * * TODO: getNodeFigure used here instead of getPrimaryShape() - better use * getPrimaryShape(). */ protected void refreshFont() { Font modelFont = getRealFigure().getFont(); if (modelFont instanceof BasicFont) { BasicFont basicFont = (BasicFont) modelFont; int fontStyle = SWT.NONE; switch (basicFont.getStyle()) { case BOLD_LITERAL: fontStyle = SWT.BOLD; break; case ITALIC_LITERAL: fontStyle = SWT.ITALIC; break; } if (basicFont.getFaceName() == null) { return; } FontData fontData = new FontData(basicFont.getFaceName(), basicFont.getHeight(), fontStyle); if (myCachedFontData != null && myCachedFontData.equals(fontData)) { return; } org.eclipse.swt.graphics.Font font = getResourceManager().createFont(FontDescriptor.createFrom(fontData)); getNodeFigure().setFont(font); getNodeFigure().repaint(); if (myCachedFontData != null) { getResourceManager().destroyFont(FontDescriptor.createFrom(myCachedFontData)); } } else { getNodeFigure().setFont(null); getNodeFigure().repaint(); } } @Override public DragTracker getDragTracker(Request request) { if (myDragAllowed) { return new DragEditPartsTrackerEx(this) { @Override protected Conditional getTargetingConditional() { return new TargetingConditional((ChangeBoundsRequest) getTargetRequest(), getSourceEditPart()); } }; } return null; } public void setDragAllowed(boolean dragAllowed) { myDragAllowed = dragAllowed; } private static class TargetingConditional implements Conditional { ChangeBoundsRequest myRequest; private EditPart mySourceEditPart; public TargetingConditional(ChangeBoundsRequest targetRequest, EditPart sourceEditpart) { mySourceEditPart = sourceEditpart; myRequest = new ChangeBoundsRequest(RequestConstants.REQ_CLONE); myRequest.setLocation(targetRequest.getLocation().getCopy()); myRequest.setMoveDelta(targetRequest.getMoveDelta().getCopy()); myRequest.setSizeDelta(targetRequest.getSizeDelta().getCopy()); myRequest.setResizeDirection(targetRequest.getResizeDirection()); } public boolean evaluate(EditPart editPart) { myRequest.setType(getRequestType(editPart)); return editPart.getTargetEditPart(myRequest) != null; } private Object getRequestType(EditPart editPart) { return isMove(editPart) ? RequestConstants.REQ_MOVE : RequestConstants.REQ_DROP; } private boolean isMove(EditPart editPart) { EditPart part = mySourceEditPart; while (part != editPart && part != null) { if (part.getParent() == editPart && part.getSelected() != EditPart.SELECTED_NONE) { return true; } part = part.getParent(); } return false; } } }