/* * (c) Copyright 2010-2011 AgileBirds * * This file is part of OpenFlexo. * * OpenFlexo is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * OpenFlexo is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>. * */ package org.openflexo.wkf.roleeditor; import java.awt.Color; import java.util.Enumeration; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import org.openflexo.fge.Drawing; import org.openflexo.fge.FGEUtils; import org.openflexo.fge.GraphicalRepresentation; import org.openflexo.fge.ShapeGraphicalRepresentation; import org.openflexo.fge.cp.ControlArea; import org.openflexo.fge.geom.FGEDimension; import org.openflexo.fge.geom.FGEGeometricObject.SimplifiedCardinalDirection; import org.openflexo.fge.geom.FGEPoint; import org.openflexo.fge.graphics.BackgroundStyle; import org.openflexo.fge.graphics.BackgroundStyle.BackgroundImage; import org.openflexo.fge.graphics.BackgroundStyle.BackgroundImage.ImageBackgroundType; import org.openflexo.fge.graphics.BackgroundStyle.ColorGradient.ColorGradientDirection; import org.openflexo.fge.graphics.DecorationPainter; import org.openflexo.fge.graphics.FGEShapeDecorationGraphics; import org.openflexo.fge.graphics.ForegroundStyle; import org.openflexo.fge.graphics.TextStyle; import org.openflexo.fge.shapes.Rectangle; import org.openflexo.fge.shapes.Shape.ShapeType; import org.openflexo.foundation.DataModification; import org.openflexo.foundation.FlexoObservable; import org.openflexo.foundation.GraphicalFlexoObserver; import org.openflexo.foundation.RepresentableFlexoModelObject; import org.openflexo.foundation.action.SetPropertyAction; import org.openflexo.foundation.wkf.Role; import org.openflexo.foundation.wkf.dm.ObjectLocationChanged; import org.openflexo.foundation.wkf.dm.ObjectSizeChanged; import org.openflexo.foundation.wkf.dm.RoleColorChange; import org.openflexo.foundation.wkf.dm.RoleNameChange; import org.openflexo.foundation.wkf.dm.WKFAttributeDataModification; import org.openflexo.icon.WKFIconLibrary; import org.openflexo.toolbox.ConcatenedList; public class RoleGR extends ShapeGraphicalRepresentation<Role> implements GraphicalFlexoObserver { private static final Logger logger = Logger.getLogger(RoleGR.class.getPackage().getName()); public static final int WIDTH = 100; public static final int HEIGHT = 40; private ForegroundStyle foreground; private BackgroundStyle background; private TextStyle textStyle; public RoleGR(Role aRole, Drawing<?> aDrawing) { super(ShapeType.RECTANGLE, aRole, aDrawing); // setText(getRole().getName()); setIsFloatingLabel(false); getShape().setIsRounded(true); setDimensionConstraints(DimensionConstraints.FREELY_RESIZABLE); updateStyles(); setBorder(new ShapeGraphicalRepresentation.ShapeBorder(25, 25, 25, 25)); setDecorationPainter(new RoleDecorationPainter(aRole)); setIsMultilineAllowed(true); setAdjustMinimalWidthToLabelWidth(true); setAdjustMinimalHeightToLabelHeight(true); addToMouseClickControls(new RoleEditorController.ShowContextualMenuControl()); addToMouseDragControls(new DrawRoleSpecializationControl()); aRole.addObserver(this); } @Override public double getWidth() { return getRole().getWidth(RepresentableFlexoModelObject.DEFAULT, 100); } @Override public void setWidthNoNotification(double width) { getRole().setWidth(width, RepresentableFlexoModelObject.DEFAULT); } @Override public double getHeight() { return getRole().getHeight(RepresentableFlexoModelObject.DEFAULT, 40); } @Override public void setHeightNoNotification(double height) { getRole().setHeight(height, RepresentableFlexoModelObject.DEFAULT); } @Override public RoleListRepresentation getDrawing() { return (RoleListRepresentation) super.getDrawing(); } @Override public void delete() { Role role = getRole(); super.delete(); role.deleteObserver(this); } private void updateStyles() { foreground = ForegroundStyle.makeStyle(getRoleColor()); foreground.setLineWidth(2); background = BackgroundStyle.makeColorGradientBackground(getRoleColor(), Color.WHITE, ColorGradientDirection.SOUTH_EAST_NORTH_WEST); textStyle = TextStyle.makeDefault(); textStyle.setColor(FGEUtils.chooseBestColor(getRoleColor(), Color.WHITE, Color.BLACK)); setForeground(foreground); setBackground(background); setTextStyle(textStyle); } /** * @return */ protected Color getRoleColor() { // See also org.openflexo.wkf.swleditor.gr.RoleContainerGR.updateColors() and // org.openflexo.components.browser.wkf.RoleElement.buildCustomIcon(Color) // org.openflexo.wkf.processeditor.gr.AbstractActivityNodeGR.getMainBgColor() if (getRole().getColor() != null) { return getRole().getColor(); } return Color.RED; } public class RoleDecorationPainter implements DecorationPainter, Cloneable { private Role role; protected ForegroundStyle decorationForeground; protected BackgroundImage decorationBackground; private boolean isSystemRole; @Override public RoleDecorationPainter clone() { return new RoleDecorationPainter(role); } public RoleDecorationPainter(Role aRole) { role = aRole; updateDecorationBackground(); decorationForeground = ForegroundStyle.makeStyle(getRoleColor()); decorationForeground.setLineWidth(2); } private void updateDecorationBackground() { if (role.getIsSystemRole()) { isSystemRole = true; decorationBackground = BackgroundStyle.makeImageBackground(WKFIconLibrary.SYSTEM_ROLE_ICON); } else { isSystemRole = false; decorationBackground = BackgroundStyle.makeImageBackground(WKFIconLibrary.ROLE_ICON); } decorationBackground.setImageBackgroundType(ImageBackgroundType.OPAQUE); decorationBackground.setImageBackgroundColor(Color.WHITE); decorationBackground.setDeltaX(6); decorationBackground.setDeltaY(-4); decorationBackground.setUseTransparency(true); decorationBackground.setTransparencyLevel(0.9f); } @Override public void paintDecoration(FGEShapeDecorationGraphics g) { if (!decorationForeground.getColor().equals(getRoleColor())) { decorationForeground.setColor(getRoleColor()); } if (role.getIsSystemRole() != isSystemRole) { updateDecorationBackground(); } g.useBackgroundStyle(decorationBackground); g.fillCircle(new FGEPoint(30, 20), new FGEDimension(22, 22)); g.useForegroundStyle(decorationForeground); g.drawCircle(new FGEPoint(30, 20), new FGEDimension(22, 22)); }; @Override public boolean paintBeforeShape() { return false; } } private boolean isUpdatingPosition = false; @Override public double getX() { if (!getRole().hasLocationForContext(RepresentableFlexoModelObject.DEFAULT)) { getRole().getX(RepresentableFlexoModelObject.DEFAULT, getDefaultX()); } return getRole().getX(RepresentableFlexoModelObject.DEFAULT); } @Override public void setXNoNotification(double posX) { isUpdatingPosition = true; getRole().setX(posX, RepresentableFlexoModelObject.DEFAULT); isUpdatingPosition = false; } @Override public double getY() { if (!getRole().hasLocationForContext(RepresentableFlexoModelObject.DEFAULT)) { getRole().getY(RepresentableFlexoModelObject.DEFAULT, getDefaultY()); } return getRole().getY(RepresentableFlexoModelObject.DEFAULT); } @Override public void setYNoNotification(double posY) { isUpdatingPosition = true; getRole().setY(posY, RepresentableFlexoModelObject.DEFAULT); isUpdatingPosition = false; } private int defaultX = -1; private int defaultY = -1; // Override to implement defaut automatic layout public double getDefaultX() { if (defaultX < 0) { doDefaultLayout(10, 10); } return defaultX; } // Override to implement defaut automatic layout public double getDefaultY() { if (defaultY < 0) { doDefaultLayout(10, 10); } return defaultY; } private void doDefaultLayout(int x, int y) { boolean ok = true; Enumeration<GraphicalRepresentation<?>> en = getDrawing().getAllGraphicalRepresentations(); while (en.hasMoreElements()) { GraphicalRepresentation<?> gr = en.nextElement(); if (gr instanceof RoleGR) { RoleGR rgr = (RoleGR) gr; if (rgr != this) { if (rgr.getRole().hasLocationForContext(RepresentableFlexoModelObject.DEFAULT)) { java.awt.Rectangle viewBounds = gr.getViewBounds(1.0); if (viewBounds.intersects(new java.awt.Rectangle(x, y, WIDTH, HEIGHT))) { ok = false; if (viewBounds.x + viewBounds.width + WIDTH > getDrawingGraphicalRepresentation().getWidth()) { // End of line, we go to the next one if (y + 10 + HEIGHT < getDrawingGraphicalRepresentation().getHeight()) { doDefaultLayout(10, y + 10 + HEIGHT); } else { if (logger.isLoggable(Level.WARNING)) { logger.warning("Could not find suitable location for role: " + getRole()); } defaultX = 10; defaultY = 10; } } else { doDefaultLayout(viewBounds.x + viewBounds.width + 10, y); } } } } } } if (ok) { defaultX = x; defaultY = y; } } private boolean isEditingLabel = false; private String editingText; // private Color textColor; @Override public void notifyLabelWillBeEdited() { editingText = getText(); // textColor = getTextStyle().getColor(); isEditingLabel = true; super.notifyLabelWillBeEdited(); } @Override public void notifyLabelHasBeenEdited() { isEditingLabel = false; setTextNoNotification(editingText); editingText = null; // textColor = null; super.notifyLabelHasBeenEdited(); } @Override public String getText() { if (isEditingLabel) { return editingText; } else { return getRole().getName(); } } @Override public void setTextNoNotification(String text) { if (isEditingLabel) { editingText = text; /*Role roleWithName = getRole().getRoleList().roleWithName(text); GPO: I abandon this possibility because notifications are not taken into account by textComponent during edition if (roleWithName!=null && roleWithName!=getRole()) { getTextStyle().setColor(Color.RED); } else { getTextStyle().setColor(textColor); }*/ return; } SetPropertyAction set = SetPropertyAction.actionType.makeNewAction(getRole(), null, getDrawing().getEditor()); set.setKey("name"); set.setValue(text); set.doAction(); /*try { getRole().setName(text); } catch (DuplicateRoleException e) { e.printStackTrace(); }*/ } public Role getRole() { return getDrawable(); } @Override public Rectangle getShape() { return (Rectangle) super.getShape(); } @Override public void update(FlexoObservable observable, DataModification dataModification) { if (observable == getRole()) { if (dataModification instanceof WKFAttributeDataModification) { if (((WKFAttributeDataModification) dataModification).getAttributeName().equals("posX") || ((WKFAttributeDataModification) dataModification).getAttributeName().equals("posY")) { if (!isUpdatingPosition) { notifyObjectMoved(); } } else if (((WKFAttributeDataModification) dataModification).getAttributeName().equals("roleSpecializations")) { if (getDrawing() instanceof RoleListRepresentation) { getDrawing().updateGraphicalObjectsHierarchy(); } // This might be not the case when used in palette !!! } else if ("isSystemRole".equals(((WKFAttributeDataModification) dataModification).getAttributeName())) { notifyShapeNeedsToBeRedrawn(); } else { notifyShapeNeedsToBeRedrawn(); } } else if (dataModification instanceof ObjectSizeChanged) { if (!isResizing()) { notifyObjectResized(); } } else if (dataModification instanceof ObjectLocationChanged) { if (!isUpdatingPosition) { notifyObjectMoved(); } } else if (dataModification instanceof RoleNameChange) { notifyAttributeChange(org.openflexo.fge.GraphicalRepresentation.Parameters.text); } else if (dataModification instanceof RoleColorChange) { updateStyles(); notifyShapeNeedsToBeRedrawn(); } } } private ConcatenedList<ControlArea<?>> controlAreas; @Override public List<? extends ControlArea<?>> getControlAreas() { if (controlAreas == null) { controlAreas = new ConcatenedList<ControlArea<?>>(); controlAreas.addElementList(super.getControlAreas()); controlAreas.addElement(new FloatingPalette(this, getDrawable().getRoleList(), SimplifiedCardinalDirection.EAST)); controlAreas.addElement(new FloatingPalette(this, getDrawable().getRoleList(), SimplifiedCardinalDirection.WEST)); controlAreas.addElement(new FloatingPalette(this, getDrawable().getRoleList(), SimplifiedCardinalDirection.NORTH)); controlAreas.addElement(new FloatingPalette(this, getDrawable().getRoleList(), SimplifiedCardinalDirection.SOUTH)); } return controlAreas; } }