0001: /*
0002: * Copyright 2001-2007 Geert Bevin <gbevin[remove] at uwyn dot com>
0003: * Distributed under the terms of either:
0004: * - the common development and distribution license (CDDL), v1.0; or
0005: * - the GNU Lesser General Public License, v2.1 or later
0006: * $Id: Element.java 3634 2007-01-08 21:42:24Z gbevin $
0007: */
0008: package com.uwyn.rife.gui.old;
0009:
0010: import java.awt.*;
0011: import java.awt.event.MouseEvent;
0012: import java.awt.event.MouseListener;
0013: import java.awt.event.MouseMotionListener;
0014: import java.awt.font.LineMetrics;
0015: import java.awt.geom.*;
0016: import java.awt.image.BufferedImage;
0017: import java.util.ArrayList;
0018:
0019: import javax.swing.JComponent;
0020: import javax.swing.JMenu;
0021: import javax.swing.JMenuItem;
0022: import javax.swing.JPopupMenu;
0023:
0024: import com.uwyn.rife.config.Config;
0025: import com.uwyn.rife.gui.Rife;
0026: import com.uwyn.rife.swing.JDialogSystemError;
0027: import com.uwyn.rife.tools.ExceptionUtils;
0028: import com.uwyn.rife.tools.Localization;
0029:
0030: public class Element extends JComponent implements MouseListener,
0031: MouseMotionListener {
0032: private boolean mSelected = false;
0033:
0034: private Color mTitleBackgroundColor = new Color(220, 220, 220);
0035: private StructurePanel mStructurePanel = null;
0036: private ElementStyle mElementStyleOrig = null;
0037: private ElementStyle mElementStyleScaled = null;
0038:
0039: private ArrayList<ElementListener> mElementListeners = null;
0040: private ArrayList<ElementProperty> mElementProperties = null;
0041:
0042: private float mXOrig = -1f;
0043: private float mYOrig = -1f;
0044: private float mWidthOrig = -1f;
0045: private float mHeightOrig = -1f;
0046: private float mBodyXOffsetOrig = -1f;
0047: private float mBodyYOffsetOrig = -1f;
0048: private Area mBoundingOrig = null;
0049: private Area mBodyAreaOutsideOrig = null;
0050: private Area mBodyAreaInsideOrig = null;
0051: private GeneralPath mUsedParameterLinesOrig = null;
0052: private Area mTitleRectangleOutsideOrig = null;
0053: private Area mTitleRectangleInsideOrig = null;
0054:
0055: private float mScaleFactor = 1f;
0056:
0057: private float mXScaled = -1f;
0058: private float mYScaled = -1f;
0059: private float mWidthScaled = -1f;
0060: private float mHeightScaled = -1f;
0061: private Area mBoundingScaled = null;
0062: private Area mBodyAreaOutsideScaled = null;
0063: private Area mBodyAreaInsideScaled = null;
0064: private GeneralPath mUsedParameterLinesScaled = null;
0065: private Area mTitleRectangleOutsideScaled = null;
0066: private Area mTitleRectangleInsideScaled = null;
0067:
0068: private boolean mDragActive = false;
0069: private Point mDragStartPoint = null;
0070: private BufferedImage mDragBufferedImage = null;
0071:
0072: private boolean mIsTransparent = false;
0073:
0074: public Element(StructurePanel structurePanel,
0075: ElementStyle styleOrig, ElementStyle styleScaled) {
0076: this (structurePanel, "", styleOrig, styleScaled);
0077: }
0078:
0079: public Element(StructurePanel structurePanel, String title,
0080: ElementStyle styleOrig, ElementStyle styleScaled) {
0081: super ();
0082:
0083: mStructurePanel = structurePanel;
0084: mElementStyleOrig = styleOrig;
0085: mElementStyleScaled = styleScaled;
0086:
0087: mElementListeners = new ArrayList<ElementListener>();
0088: mElementProperties = new ArrayList<ElementProperty>();
0089: addProperty(ElementPropertyTitle.class, title);
0090:
0091: setOpaque(false);
0092: setLayout(null);
0093: }
0094:
0095: public StructurePanel getStructurePanel() {
0096: return mStructurePanel;
0097: }
0098:
0099: public int getWidth() {
0100: if (mWidthScaled == -1) {
0101: createPrecalculatedAreas();
0102: }
0103: return (int) mWidthScaled;
0104: }
0105:
0106: public int getHeight() {
0107: if (mHeightScaled == -1) {
0108: createPrecalculatedAreas();
0109: }
0110: return (int) mHeightScaled;
0111: }
0112:
0113: public Area getBoundingAreaOrig() {
0114: return mBoundingOrig;
0115: }
0116:
0117: public Area getBoundingAreaScaled() {
0118: return mBoundingScaled;
0119: }
0120:
0121: public Area getTitleRectangleOutside() {
0122: return mTitleRectangleOutsideScaled;
0123: }
0124:
0125: public Area getTitleRectangleInside() {
0126: return mTitleRectangleInsideScaled;
0127: }
0128:
0129: public void setLocation(Point p) {
0130: setLocation(p.x, p.y);
0131: }
0132:
0133: public void setLocation(int x, int y) {
0134: setBounds(x, y, getWidth(), getHeight());
0135: }
0136:
0137: public void setBounds(Rectangle r) {
0138: setBounds(r.x, r.x, r.width, r.height);
0139: }
0140:
0141: public void setBounds(int x, int y, int width, int height) {
0142: mXOrig = x / mScaleFactor;
0143: mYOrig = y / mScaleFactor;
0144: if (Config.getRepInstance().getBool("GRID_SNAP")) {
0145: int grid_size = Config.getRepInstance().getInt("GRID_SIZE");
0146: mXOrig = mXOrig - ((mXOrig + mBodyXOffsetOrig) % grid_size);
0147: mYOrig = mYOrig - ((mYOrig + mBodyYOffsetOrig) % grid_size);
0148: }
0149: mXScaled = mXOrig * mScaleFactor;
0150: mYScaled = mYOrig * mScaleFactor;
0151: super .setBounds((int) mXScaled, (int) mYScaled, width, height);
0152: }
0153:
0154: public int getX() {
0155: return (int) mXScaled;
0156: }
0157:
0158: public int getY() {
0159: return (int) mYScaled;
0160: }
0161:
0162: public Rectangle getBounds(Rectangle rv) {
0163: if (rv == null) {
0164: rv = new Rectangle();
0165: }
0166:
0167: rv.x = getX();
0168: rv.y = getY();
0169: rv.width = getWidth();
0170: rv.height = getHeight();
0171:
0172: return rv;
0173: }
0174:
0175: public void setElementColor(Color bodyColor) {
0176: mTitleBackgroundColor = bodyColor;
0177: repaint();
0178: }
0179:
0180: public void selectElement() {
0181: if (!mSelected) {
0182: mSelected = true;
0183: }
0184: }
0185:
0186: public void deselectElement() {
0187: if (mSelected) {
0188: mSelected = false;
0189: }
0190: }
0191:
0192: public boolean isSelected() {
0193: return mSelected;
0194: }
0195:
0196: public ElementStyle getElementStyleScaled() {
0197: return mElementStyleScaled;
0198: }
0199:
0200: protected void resetPrecalculatedAreas() {
0201: mWidthOrig = -1f;
0202: mHeightOrig = -1f;
0203: mBodyXOffsetOrig = -1f;
0204: mBodyYOffsetOrig = -1f;
0205: mBoundingOrig = null;
0206: mBodyAreaOutsideOrig = null;
0207: mBodyAreaInsideOrig = null;
0208: mUsedParameterLinesOrig = null;
0209:
0210: mWidthScaled = -1f;
0211: mHeightScaled = -1f;
0212: mBoundingScaled = null;
0213: mBodyAreaOutsideScaled = null;
0214: mBodyAreaInsideScaled = null;
0215: mUsedParameterLinesScaled = null;
0216: }
0217:
0218: ElementProperty createProperty(Class propertyClass, String name) {
0219: ElementProperty property = null;
0220: try {
0221: property = (ElementProperty) propertyClass.getConstructor(
0222: new Class[] { Element.class, String.class })
0223: .newInstance(new Object[] { this , name });
0224: } catch (Throwable e) {
0225: JDialogSystemError dialog = new JDialogSystemError(
0226: Rife.getMainFrame(),
0227: "Element.createProperty() : Error while creating an element property with name '"
0228: + name
0229: + "' and class '"
0230: + propertyClass.getName()
0231: + "': "
0232: + ExceptionUtils.getExceptionStackTrace(e));
0233: dialog.setVisible(true);
0234: Rife.quit();
0235: }
0236:
0237: return property;
0238: }
0239:
0240: ElementProperty getProperty(Class propertyClass, String name) {
0241: int index = mElementProperties.indexOf(createProperty(
0242: propertyClass, name));
0243: if (index == -1) {
0244: return null;
0245: } else {
0246: return mElementProperties.get(index);
0247: }
0248: }
0249:
0250: ElementProperty addProperty(Class propertyClass, String name) {
0251: ElementProperty property = createProperty(propertyClass, name);
0252:
0253: if (property != null) {
0254: if (!mElementProperties.contains(property)) {
0255: mElementProperties.add(property);
0256: resetPrecalculatedAreas();
0257: return property;
0258: }
0259: }
0260:
0261: return null;
0262: }
0263:
0264: boolean removeProperty(ElementProperty property) {
0265: if (mElementProperties.remove(property)) {
0266: resetPrecalculatedAreas();
0267: return true;
0268: } else {
0269: return false;
0270: }
0271: }
0272:
0273: boolean renameProperty(ElementProperty property, String newName) {
0274: if (mElementProperties.contains(property)) {
0275: if (property.isValidName(newName)) {
0276: property.setName(newName);
0277: resetPrecalculatedAreas();
0278: return true;
0279: } else {
0280: return false;
0281: }
0282: }
0283:
0284: return false;
0285: }
0286:
0287: ElementPropertyExit addExit(String name) {
0288: return (ElementPropertyExit) addProperty(
0289: ElementPropertyExit.class, name);
0290: }
0291:
0292: ElementPropertyParameterConsumed addConsumedParameter(String name) {
0293: return (ElementPropertyParameterConsumed) addProperty(
0294: ElementPropertyParameterConsumed.class, name);
0295: }
0296:
0297: ElementPropertyParameterUsed addUsedParameter(String name) {
0298: return (ElementPropertyParameterUsed) addProperty(
0299: ElementPropertyParameterUsed.class, name);
0300: }
0301:
0302: ElementPropertyParameterAdded addAddedParameter(String name) {
0303: return (ElementPropertyParameterAdded) addProperty(
0304: ElementPropertyParameterAdded.class, name);
0305: }
0306:
0307: ElementProperty getTitle() {
0308: return getProperties(ElementPropertyTitle.class).get(0);
0309: }
0310:
0311: ArrayList<ElementProperty> getExits() {
0312: return getProperties(ElementPropertyExit.class);
0313: }
0314:
0315: ArrayList<ElementProperty> getConsumedParameters() {
0316: return getProperties(ElementPropertyParameterConsumed.class);
0317: }
0318:
0319: ArrayList<ElementProperty> getUsedParameters() {
0320: return getProperties(ElementPropertyParameterUsed.class);
0321: }
0322:
0323: ArrayList<ElementProperty> getAddedParameters() {
0324: return getProperties(ElementPropertyParameterAdded.class);
0325: }
0326:
0327: ArrayList<ElementProperty> getProperties(Class propertyClass) {
0328: ArrayList<ElementProperty> result = new ArrayList<ElementProperty>();
0329:
0330: for (ElementProperty property : mElementProperties) {
0331: if (propertyClass.isInstance(property)) {
0332: result.add(property);
0333: }
0334: }
0335: return result;
0336: }
0337:
0338: int countExits() {
0339: return countProperties(ElementPropertyExit.class);
0340: }
0341:
0342: int countConsumedParameters() {
0343: return countProperties(ElementPropertyParameterConsumed.class);
0344: }
0345:
0346: int countUsedParameters() {
0347: return countProperties(ElementPropertyParameterUsed.class);
0348: }
0349:
0350: int countAddedParameters() {
0351: return countProperties(ElementPropertyParameterAdded.class);
0352: }
0353:
0354: private int countProperties(Class propertyClass) {
0355: int result = 0;
0356:
0357: for (ElementProperty property : mElementProperties) {
0358: if (propertyClass.isInstance(property)) {
0359: result++;
0360: }
0361: }
0362: return result;
0363: }
0364:
0365: public Dimension getMinimumSize() {
0366: return new Dimension((int) mWidthScaled, (int) mHeightScaled);
0367: }
0368:
0369: public Dimension getPreferredSize() {
0370: return getMinimumSize();
0371: }
0372:
0373: public Dimension getMaximumSize() {
0374: return getMinimumSize();
0375: }
0376:
0377: public boolean contains(int x, int y) {
0378: if (mBoundingScaled != null && x >= 0 && y >= 0
0379: && x < mWidthScaled && y < mHeightScaled
0380: && mBoundingScaled.contains(x, y)) {
0381: return true;
0382: } else {
0383: return false;
0384: }
0385: }
0386:
0387: public synchronized void scalePrecalculatedAreas(float multiplier) {
0388: mScaleFactor *= multiplier;
0389:
0390: mXScaled = mXOrig * mScaleFactor;
0391: mYScaled = mYOrig * mScaleFactor;
0392: mWidthScaled = mWidthOrig * mScaleFactor;
0393: mHeightScaled = mHeightOrig * mScaleFactor;
0394:
0395: AffineTransform scale_transform = AffineTransform
0396: .getScaleInstance(mScaleFactor, mScaleFactor);
0397: mBoundingScaled = mBoundingOrig
0398: .createTransformedArea(scale_transform);
0399: mBodyAreaOutsideScaled = mBodyAreaOutsideOrig
0400: .createTransformedArea(scale_transform);
0401: mBodyAreaInsideScaled = mBodyAreaInsideOrig
0402: .createTransformedArea(scale_transform);
0403: mTitleRectangleOutsideScaled = mTitleRectangleOutsideOrig
0404: .createTransformedArea(scale_transform);
0405: mTitleRectangleInsideScaled = mTitleRectangleInsideOrig
0406: .createTransformedArea(scale_transform);
0407: mUsedParameterLinesScaled = (GeneralPath) mUsedParameterLinesOrig
0408: .clone();
0409: mUsedParameterLinesScaled.transform(scale_transform);
0410:
0411: for (ElementProperty property : mElementProperties) {
0412: property.scale(multiplier);
0413: }
0414:
0415: super .setBounds((int) mXScaled, (int) mYScaled,
0416: (int) mWidthScaled, (int) mHeightScaled);
0417: }
0418:
0419: private synchronized void createPrecalculatedAreas() {
0420: int grid_size = Config.getRepInstance().getInt("GRID_SIZE");
0421: LineMetrics line_metrics = null;
0422: Rectangle2D string_bounds = null;
0423: Rectangle2D name_bounds = null;
0424: Area hotspot = null;
0425:
0426: //
0427: // calculate parameters dimensions
0428: //
0429: line_metrics = mElementStyleOrig.mParamFont.getLineMetrics("M",
0430: mElementStyleOrig.mFontRenderContext);
0431: float parameter_text_width = (float) (mElementStyleOrig.mParamFont
0432: .getStringBounds("M",
0433: mElementStyleOrig.mFontRenderContext)
0434: .getHeight());
0435: float parameter_text_middle = line_metrics.getDescent()
0436: - line_metrics.getStrikethroughOffset();
0437:
0438: // calculate the parameter rectangle width, this is the distance that one parameter needs to draw its components
0439: // and to be aligned to the grid
0440: float parameter_rectangle_width_minimum = parameter_text_width
0441: + (mElementStyleOrig.mParamMarginWidth * 2)
0442: + mElementStyleOrig.mParamLineWidth;
0443: float parameter_rectangle_width_unit = grid_size * 2;
0444: float parameter_rectangle_width = parameter_rectangle_width_unit;
0445: if (parameter_rectangle_width_minimum > parameter_rectangle_width_unit) {
0446: parameter_rectangle_width = (float) (Math
0447: .ceil(parameter_rectangle_width_minimum
0448: / parameter_rectangle_width_unit) * parameter_rectangle_width_unit);
0449: }
0450:
0451: // calculate to FINAL WIDTH of the complete consumed parameters rectangle
0452: float consumed_parameters_rectangle_width = 0;
0453: float number_of_consumed_parameters = countConsumedParameters();
0454: if (number_of_consumed_parameters > 0) {
0455: consumed_parameters_rectangle_width = (number_of_consumed_parameters * parameter_rectangle_width)
0456: + ((number_of_consumed_parameters + 1) * (parameter_rectangle_width / 2));
0457: }
0458:
0459: // calculate to FINAL WIDTH of the complete used parameters rectangle
0460: float used_parameters_rectangle_width = 0;
0461: float number_of_used_parameters = countUsedParameters();
0462: if (number_of_used_parameters > 0) {
0463: used_parameters_rectangle_width = (number_of_used_parameters * parameter_rectangle_width)
0464: + ((number_of_used_parameters + 1) * (parameter_rectangle_width / 2));
0465:
0466: if (number_of_consumed_parameters == 0) {
0467: used_parameters_rectangle_width += mElementStyleOrig.mElementBorderWidth;
0468: }
0469: }
0470:
0471: // calculate to FINAL WIDTH of the complete added parameters rectangle
0472: float added_parameters_rectangle_width = 0;
0473: float number_of_added_parameters = countAddedParameters();
0474: if (number_of_added_parameters > 0) {
0475: added_parameters_rectangle_width = number_of_added_parameters
0476: * parameter_rectangle_width
0477: + number_of_added_parameters
0478: * (parameter_rectangle_width / 2);
0479: }
0480:
0481: //
0482: // calculate title dimensions
0483: //
0484: line_metrics = mElementStyleOrig.mTitleFont.getLineMetrics("M",
0485: mElementStyleOrig.mFontRenderContext);
0486: Rectangle2D name_text_bounds = mElementStyleOrig.mTitleFont
0487: .getStringBounds(getTitle().getName(),
0488: mElementStyleOrig.mFontRenderContext);
0489: float title_text_height = (float) (name_text_bounds.getHeight());
0490: float title_text_width = (float) (name_text_bounds.getWidth());
0491:
0492: // calculate the MINIMAL WIDTH of the TITLE RECTANGLE so that it contains at least the title text
0493: float name_rectangle_width = title_text_width
0494: + mElementStyleOrig.mElementBorderWidth * 2
0495: + mElementStyleOrig.mTitleMarginWidth * 2;
0496: // snap it to grid units
0497: name_rectangle_width = (float) (Math.ceil(name_rectangle_width
0498: / grid_size) * grid_size);
0499: // calculate the FINAL HEIGHT of the TITLE RECTANGLE
0500: float name_rectangle_height = title_text_height
0501: + mElementStyleOrig.mElementBorderWidth * 2
0502: + mElementStyleOrig.mTitleMarginHeight * 2;
0503: // snap it to grid units
0504: name_rectangle_height = (float) (Math
0505: .ceil(name_rectangle_height / grid_size) * grid_size);
0506:
0507: // calculate the temporary width of the complete element rectangle and take space for the right edge
0508: float element_rectangle_width = consumed_parameters_rectangle_width
0509: + used_parameters_rectangle_width
0510: + parameter_rectangle_width
0511: + name_rectangle_width
0512: + mElementStyleOrig.mElementBorderWidth;
0513:
0514: // calculate the FINAL X OFFSET to start the TITLE BOX immediatly right of the used parameters rectangle
0515: float name_rectangle_x_offset = element_rectangle_width
0516: - name_rectangle_width;
0517:
0518: //
0519: // make sure that the element is wide enough to contain all the parameters and exit widths
0520: //
0521:
0522: // calculate the maximum width of all the exit texts
0523: float exits_width = 0;
0524: float exit_string_width = 0;
0525:
0526: for (ElementProperty exit : getExits()) {
0527: exit_string_width = (float) (mElementStyleOrig.mExitFont
0528: .getStringBounds(exit.getName(),
0529: mElementStyleOrig.mFontRenderContext)
0530: .getWidth());
0531: if (exit_string_width > exits_width) {
0532: exits_width = exit_string_width;
0533: }
0534: }
0535:
0536: // calculate the minimal body rectangle width to known what size has to be at least available to display all the items
0537: // inside the body (consumed parameter texts, used parameter texts and lines, added parameters texts, exit texts)
0538: float minimal_body_rectangle_width = consumed_parameters_rectangle_width
0539: + used_parameters_rectangle_width
0540: + added_parameters_rectangle_width
0541: + parameter_rectangle_width
0542: + mElementStyleOrig.mExitMarginWidth
0543: + exits_width
0544: + mElementStyleOrig.mExitMarginWidth;
0545: // snap yhe minimal body rectangle width to grid units and take space for the right edge
0546: minimal_body_rectangle_width = (float) (Math
0547: .ceil(minimal_body_rectangle_width / grid_size) * grid_size)
0548: + mElementStyleOrig.mElementBorderWidth;
0549:
0550: if (element_rectangle_width < minimal_body_rectangle_width) {
0551: // calculate the FINAL WIDTH of the ELEMENT RECTANGLE
0552: element_rectangle_width = minimal_body_rectangle_width;
0553: // calculate the FINAL WIDTH of the TITLE RECTANGLE so that it's wide enough to fill all the space
0554: // right of the used parameters rectangle
0555: name_rectangle_width = element_rectangle_width
0556: - (consumed_parameters_rectangle_width
0557: + used_parameters_rectangle_width
0558: + parameter_rectangle_width + mElementStyleOrig.mElementBorderWidth);
0559: }
0560:
0561: //
0562: // calculate body dimensions
0563: //
0564: line_metrics = mElementStyleOrig.mExitFont.getLineMetrics("M",
0565: mElementStyleOrig.mFontRenderContext);
0566: float exit_text_height = (float) (mElementStyleOrig.mExitFont
0567: .getStringBounds("M",
0568: mElementStyleOrig.mFontRenderContext)
0569: .getHeight());
0570: // calculate the exit rectangle height, this is the distance that one exit needs to draw its text and rectangle
0571: float exit_rectangle_height = exit_text_height
0572: + (mElementStyleOrig.mElementBorderWidth * 2)
0573: + (mElementStyleOrig.mExitMarginHeight * 2);
0574: // snap it to grid units
0575: exit_rectangle_height = (float) (Math
0576: .ceil(exit_rectangle_height / grid_size) * grid_size);
0577: // calculate the width of the exit rectangle
0578: float exit_rectangle_width = grid_size * 4
0579: + mElementStyleOrig.mElementBorderWidth;
0580: // calculate the vertical offset from one exit to the next one
0581: float exit_rectangle_y_interval = exit_rectangle_height
0582: + (exit_rectangle_height / 2);
0583: // take space for the bottom edge
0584: exit_rectangle_height += mElementStyleOrig.mElementBorderWidth;
0585:
0586: // calculate the MINIMUM HEIGHT of the BODY RECTANGLE
0587: float body_rectangle_height = name_rectangle_height * 2;
0588: // calculate the FINAL WIDTH of the BODY RECTANGLE
0589: float body_rectangle_width = element_rectangle_width;
0590: // calculate the temporary height of the body rectangle, this is large enough to display the title and all the exits
0591: float number_of_exits = countExits();
0592: if (number_of_exits > 0) {
0593: body_rectangle_height = name_rectangle_height
0594: + number_of_exits * exit_rectangle_y_interval
0595: + exit_rectangle_y_interval / 3;
0596: }
0597:
0598: //
0599: // make sure that the body is high enough to contain all the parameters in height
0600: //
0601:
0602: // calculate the maximum height of all the consumed parameter texts
0603: float parameters_height = 0;
0604: float parameter_string_width = 0;
0605:
0606: for (ElementProperty parameter : getConsumedParameters()) {
0607: parameter_string_width = (float) (mElementStyleOrig.mParamFont
0608: .getStringBounds(parameter.getName(),
0609: mElementStyleOrig.mFontRenderContext)
0610: .getWidth());
0611: if (parameter_string_width > parameters_height) {
0612: parameters_height = parameter_string_width;
0613: }
0614: }
0615: // calculate the minimal body rectangle height that is required to correctly display the longest consumed parameter
0616: float minimal_body_rectangle_height_for_parameters = mElementStyleOrig.mParamLineLength
0617: + mElementStyleOrig.mParamMarginHeight
0618: + parameters_height
0619: + (mElementStyleOrig.mElementBorderWidth * 2);
0620: // calculate the height of the body rectangle and make it at least as big as the previously calculated minimal body height
0621: if (body_rectangle_height < minimal_body_rectangle_height_for_parameters) {
0622: body_rectangle_height = minimal_body_rectangle_height_for_parameters;
0623: }
0624:
0625: // calculate the maximum height of all the used parameter texts
0626: parameters_height = 0;
0627: parameter_string_width = 0;
0628:
0629: for (ElementProperty parameter : getUsedParameters()) {
0630: parameter_string_width = (float) (mElementStyleOrig.mParamFont
0631: .getStringBounds(parameter.getName(),
0632: mElementStyleOrig.mFontRenderContext)
0633: .getWidth());
0634: if (parameter_string_width > parameters_height) {
0635: parameters_height = parameter_string_width;
0636: }
0637: }
0638: // calculate the minimal body rectangle height that is required to correctly display the longest used parameter
0639: minimal_body_rectangle_height_for_parameters = mElementStyleOrig.mParamLineLength
0640: + mElementStyleOrig.mParamMarginHeight
0641: + parameters_height
0642: + (mElementStyleOrig.mElementBorderWidth * 2);
0643: // calculate the height of the body rectangle and make it at least as big as the previously calculated minimal body height
0644: if (body_rectangle_height < minimal_body_rectangle_height_for_parameters) {
0645: body_rectangle_height = minimal_body_rectangle_height_for_parameters;
0646: }
0647:
0648: // calculate the maximum height of all the added parameter texts
0649: parameters_height = 0;
0650:
0651: for (ElementProperty parameter : getAddedParameters()) {
0652: parameter_string_width = (float) (mElementStyleOrig.mParamFont
0653: .getStringBounds(parameter.getName(),
0654: mElementStyleOrig.mFontRenderContext)
0655: .getWidth());
0656: if (parameter_string_width > parameters_height) {
0657: parameters_height = parameter_string_width;
0658: }
0659: }
0660: // calculate the minimal body rectangle height that is required to correctly display the longest added parameter
0661: minimal_body_rectangle_height_for_parameters = name_rectangle_height
0662: + (mElementStyleOrig.mParamLineLength / 2)
0663: + parameters_height
0664: + mElementStyleOrig.mParamMarginHeight
0665: + (mElementStyleOrig.mElementBorderWidth * 2);
0666: // calculate the height of the body rectangle and make it at least as big as the previously calculated minimal body height
0667: if (body_rectangle_height < minimal_body_rectangle_height_for_parameters) {
0668: body_rectangle_height = minimal_body_rectangle_height_for_parameters;
0669: }
0670: // snap the height of the body to grid units and take space for the bottom edge
0671: body_rectangle_height = (float) (Math
0672: .ceil(body_rectangle_height / grid_size) * grid_size)
0673: + mElementStyleOrig.mElementBorderWidth;
0674:
0675: //
0676: // calculate the width and height of the buffered image
0677: //
0678: mBodyXOffsetOrig = 0;
0679: mBodyYOffsetOrig = 0;
0680: // calculate the required vertical offset that is needed for the optional top parameter handles (consumed and used)
0681: if (number_of_consumed_parameters > 0
0682: || number_of_used_parameters > 0) {
0683: mBodyYOffsetOrig += mElementStyleOrig.mParamLineLength / 2;
0684: }
0685: // calculate the body width, taking into account the existance of exits
0686: if (number_of_exits > 0) {
0687: mWidthOrig = element_rectangle_width + exit_rectangle_width
0688: + 1;
0689: } else {
0690: mWidthOrig = element_rectangle_width + 1;
0691: }
0692: // calculate the body height, taking into account the space taken by optional parameter handles
0693: if (number_of_consumed_parameters > 0
0694: || number_of_used_parameters > 0
0695: || number_of_added_parameters > 0) {
0696: mHeightOrig = body_rectangle_height
0697: + mElementStyleOrig.mParamLineLength + 1;
0698: } else {
0699: mHeightOrig = body_rectangle_height + 1;
0700: }
0701:
0702: //
0703: // precalculate the body shape
0704: //
0705:
0706: // create the body area, including the outside stroke
0707: Area body_area_outside = new Area(new Rectangle2D.Float(
0708: mBodyXOffsetOrig, mBodyYOffsetOrig,
0709: body_rectangle_width, body_rectangle_height));
0710: // create the body area, excluding the outside stroke
0711: Area body_area_inside = new Area(new Rectangle2D.Float(
0712: mBodyXOffsetOrig
0713: + mElementStyleOrig.mElementBorderWidth,
0714: mBodyYOffsetOrig
0715: + mElementStyleOrig.mElementBorderWidth,
0716: body_rectangle_width
0717: - mElementStyleOrig.mElementBorderWidth * 2,
0718: body_rectangle_height
0719: - mElementStyleOrig.mElementBorderWidth * 2));
0720: // if there are exits, add them to the body shape
0721: if (number_of_exits > 0) {
0722: // create the base exit shape, including the outside stroke
0723: Area exit_area_outside = new Area(new Rectangle2D.Float(
0724: mBodyXOffsetOrig + element_rectangle_width
0725: - mElementStyleOrig.mElementBorderWidth,
0726: mBodyYOffsetOrig + name_rectangle_height
0727: + exit_rectangle_y_interval / 3,
0728: exit_rectangle_width, exit_rectangle_height));
0729: // create the base exit shape, excluding the outside stroke
0730: Area exit_area_inside = new Area(
0731: new Rectangle2D.Float(
0732: mBodyXOffsetOrig
0733: + element_rectangle_width
0734: - mElementStyleOrig.mElementBorderWidth,
0735: mBodyYOffsetOrig
0736: + name_rectangle_height
0737: + exit_rectangle_y_interval
0738: / 3
0739: + mElementStyleOrig.mElementBorderWidth,
0740: exit_rectangle_width
0741: - mElementStyleOrig.mElementBorderWidth,
0742: exit_rectangle_height
0743: - mElementStyleOrig.mElementBorderWidth
0744: * 2));
0745: // create the transformation that will translate the previous exit shape to make it suit for the next one
0746: AffineTransform next_exit_transform = AffineTransform
0747: .getTranslateInstance(0, exit_rectangle_y_interval);
0748: // process each exit, add its shapes to the body shapes and transform the exit shapes for the optional next exit
0749:
0750: Rectangle2D exit_area_outside_bounds = null;
0751: float hotspot_width = exits_width
0752: + mElementStyleOrig.mExitMarginWidth * 2;
0753: if (hotspot_width < exit_rectangle_width) {
0754: hotspot_width = exit_rectangle_width;
0755: }
0756: float hotspot_x = mWidthOrig
0757: - mElementStyleOrig.mElementBorderWidth * 2
0758: - hotspot_width;
0759: for (ElementProperty exit : getExits()) {
0760: body_area_outside.add(exit_area_outside);
0761: body_area_inside.add(exit_area_inside);
0762: exit_area_outside_bounds = exit_area_outside
0763: .getBounds2D();
0764: exit.setHotSpot(new Rectangle2D.Float(hotspot_x,
0765: (float) exit_area_outside_bounds.getY(),
0766: hotspot_width, (float) exit_area_outside_bounds
0767: .getHeight()));
0768: exit_area_outside = exit_area_outside
0769: .createTransformedArea(next_exit_transform);
0770: exit_area_inside = exit_area_inside
0771: .createTransformedArea(next_exit_transform);
0772: }
0773: }
0774:
0775: // create the bounding area by stroking the body area
0776: mBoundingOrig = new Area((new BasicStroke(1))
0777: .createStrokedShape(body_area_outside));
0778: mBoundingOrig.add(body_area_outside);
0779:
0780: // store the body areas and create the outside shape so that it only contains what is needed to draw the stroke
0781: mBodyAreaInsideOrig = body_area_inside;
0782: mBodyAreaOutsideOrig = (Area) body_area_outside.clone();
0783: mBodyAreaOutsideOrig.subtract(mBodyAreaInsideOrig);
0784:
0785: //
0786: // precalculate exit name texts
0787: //
0788: if (number_of_exits > 0) {
0789: // calculate the base location for the first exit text
0790: float base_exit_text_x_offset = mBodyXOffsetOrig
0791: + element_rectangle_width + exit_rectangle_width
0792: - mElementStyleOrig.mExitMarginWidth * 2
0793: - mElementStyleOrig.mElementBorderWidth;
0794: float base_exit_text_y_offset = mBodyYOffsetOrig
0795: + name_rectangle_height + exit_rectangle_y_interval
0796: / 3 + mElementStyleOrig.mElementBorderWidth
0797: + mElementStyleOrig.mExitMarginHeight
0798: + exit_text_height;
0799: // iterate over all the exit texts
0800: for (ElementProperty exit : getExits()) {
0801: // store each exit text with it's precalculated location in a dedicated glyph vector
0802: string_bounds = mElementStyleOrig.mExitFont
0803: .getStringBounds(exit.getName(),
0804: mElementStyleOrig.mFontRenderContext);
0805: exit
0806: .setNameBounds(new Rectangle2D.Float(
0807: (float) (base_exit_text_x_offset - string_bounds
0808: .getWidth()),
0809: (float) (base_exit_text_y_offset - string_bounds
0810: .getHeight()),
0811: (float) string_bounds.getWidth(),
0812: (float) string_bounds.getHeight()));
0813:
0814: // move the vertical position downwards
0815: base_exit_text_y_offset += exit_rectangle_y_interval;
0816: }
0817: }
0818:
0819: //
0820: // precalculate title shape
0821: //
0822: mTitleRectangleOutsideOrig = new Area(new Rectangle2D.Float(
0823: mBodyXOffsetOrig + name_rectangle_x_offset,
0824: mBodyYOffsetOrig, name_rectangle_width,
0825: name_rectangle_height));
0826: mTitleRectangleInsideOrig = new Area(new Rectangle2D.Float(
0827: mBodyXOffsetOrig + name_rectangle_x_offset
0828: + mElementStyleOrig.mElementBorderWidth,
0829: mBodyYOffsetOrig
0830: + mElementStyleOrig.mElementBorderWidth,
0831: name_rectangle_width
0832: - mElementStyleOrig.mElementBorderWidth * 2,
0833: name_rectangle_height
0834: - mElementStyleOrig.mElementBorderWidth * 2));
0835: mBodyAreaOutsideOrig.add(mTitleRectangleOutsideOrig);
0836: mBodyAreaOutsideOrig.subtract(mTitleRectangleInsideOrig);
0837: mBodyAreaInsideOrig.subtract(mTitleRectangleOutsideOrig);
0838:
0839: //
0840: // precalculate consumed parameters and texts
0841: //
0842:
0843: // set the initial horizontal offset for the drawing of the parameter handles, this is both used by all parameters
0844: float parameter_x_cursor = mBodyXOffsetOrig
0845: + (parameter_rectangle_width / 2);
0846: if (number_of_consumed_parameters > 0) {
0847: // move the initial parameter line offset to the position for consumed parameters
0848: parameter_x_cursor += parameter_rectangle_width;
0849: // calculate the vertical start and end positions of the top parameter handles
0850: float consumed_parameter_handle_top_y1 = mBodyYOffsetOrig
0851: - (mElementStyleOrig.mParamLineLength / 2);
0852: float consumed_parameter_handle_top_y2 = mBodyYOffsetOrig
0853: + (mElementStyleOrig.mParamLineLength / 2);
0854: // create the first parameter handle area
0855: Area consumed_parameter_handle_top_area = new Area(
0856: new Rectangle2D.Float(parameter_x_cursor
0857: - (mElementStyleOrig.mParamLineWidth / 2),
0858: consumed_parameter_handle_top_y1,
0859: mElementStyleOrig.mParamLineWidth,
0860: mElementStyleOrig.mParamLineLength));
0861:
0862: // calculate the horizontal interval between the parameters and create the transform object to perform the translation
0863: float consumed_parameter_x_interval = parameter_rectangle_width
0864: + (parameter_rectangle_width / 2);
0865: AffineTransform next_consumed_parameter_transform = AffineTransform
0866: .getTranslateInstance(
0867: consumed_parameter_x_interval, 0);
0868:
0869: // process all the consumed parameters
0870: for (ElementProperty parameter : getConsumedParameters()) {
0871: // add the consumed parameter handle to the body area and bounding area
0872: mBodyAreaOutsideOrig
0873: .add(consumed_parameter_handle_top_area);
0874: mBoundingOrig.add(consumed_parameter_handle_top_area);
0875:
0876: // add the consumed parameter texts together with their locations as glyph vectors to the collection of parameter glyph vectors
0877: string_bounds = mElementStyleOrig.mParamFont
0878: .getStringBounds(parameter.getName(),
0879: mElementStyleOrig.mFontRenderContext);
0880: name_bounds = new Rectangle2D.Float(
0881: (float) (parameter_x_cursor
0882: + parameter_text_middle - string_bounds
0883: .getHeight()),
0884: consumed_parameter_handle_top_y2
0885: + mElementStyleOrig.mParamMarginHeight,
0886: (float) string_bounds.getHeight(),
0887: (float) string_bounds.getWidth());
0888: parameter.setNameBounds(name_bounds);
0889: hotspot = new Area(new Rectangle2D.Float(
0890: (float) name_bounds.getX(),
0891: consumed_parameter_handle_top_y1,
0892: (float) name_bounds.getWidth(),
0893: (float) (name_bounds.getY() + name_bounds
0894: .getHeight())));
0895: hotspot.intersect(mBoundingOrig);
0896: parameter.setHotSpot(hotspot);
0897:
0898: // update the horizontal offset and translate the parameter handle area
0899: parameter_x_cursor += consumed_parameter_x_interval;
0900: consumed_parameter_handle_top_area = consumed_parameter_handle_top_area
0901: .createTransformedArea(next_consumed_parameter_transform);
0902: }
0903: } else {
0904: // adapt the initial horizontal offset in case there are no consumed parameters to make the used parameters appear
0905: // on the correct location
0906: parameter_x_cursor += parameter_rectangle_width / 2;
0907: }
0908:
0909: //
0910: // precalculate used parameters lines and texts
0911: //
0912: mUsedParameterLinesOrig = new GeneralPath();
0913: if (number_of_used_parameters > 0) {
0914: // move the initial parameter line offset to the position for used parameters
0915: parameter_x_cursor += parameter_rectangle_width / 2;
0916: // calculate the vertical start and end positions of the top and bottom parameter handles
0917: float used_parameter_handle_top_y1 = mBodyYOffsetOrig
0918: - (mElementStyleOrig.mParamLineLength / 2);
0919: float used_parameter_handle_top_y2 = mBodyYOffsetOrig
0920: + (mElementStyleOrig.mParamLineLength / 2);
0921: float used_parameter_handle_bottom_y1 = used_parameter_handle_top_y1
0922: + body_rectangle_height;
0923: float used_parameter_handle_bottom_y2 = used_parameter_handle_top_y2
0924: + body_rectangle_height;
0925: // create the first parameter top and bottom handle areas with their connection line
0926: Area used_parameter_handle_top_area = new Area(
0927: new Rectangle2D.Float(parameter_x_cursor
0928: - (mElementStyleOrig.mParamLineWidth / 2),
0929: used_parameter_handle_top_y1,
0930: mElementStyleOrig.mParamLineWidth,
0931: mElementStyleOrig.mParamLineLength));
0932: Area used_parameter_handle_bottom_area = new Area(
0933: new Rectangle2D.Float(parameter_x_cursor
0934: - (mElementStyleOrig.mParamLineWidth / 2),
0935: used_parameter_handle_bottom_y1,
0936: mElementStyleOrig.mParamLineWidth,
0937: mElementStyleOrig.mParamLineLength));
0938: Line2D used_parameter_handle_connect = new Line2D.Float(
0939: parameter_x_cursor, used_parameter_handle_top_y2,
0940: parameter_x_cursor, used_parameter_handle_bottom_y1);
0941:
0942: // calculate the horizontal interval between the parameters and create the transform object to perform the translation
0943: float used_parameter_x_interval = parameter_rectangle_width
0944: + (parameter_rectangle_width / 2);
0945: AffineTransform next_used_parameter_transform = AffineTransform
0946: .getTranslateInstance(used_parameter_x_interval, 0);
0947:
0948: // process all the used parameters
0949: for (ElementProperty parameter : getUsedParameters()) {
0950: // add the used parameter top and bottom handles to the body area and bounding area
0951: mBodyAreaOutsideOrig
0952: .add(used_parameter_handle_top_area);
0953: mBodyAreaOutsideOrig
0954: .add(used_parameter_handle_bottom_area);
0955: mBoundingOrig.add(used_parameter_handle_top_area);
0956: mBoundingOrig.add(used_parameter_handle_bottom_area);
0957:
0958: // add the connection line between handles to the collection of used parameter connection lines
0959: mUsedParameterLinesOrig.moveTo(parameter_x_cursor,
0960: used_parameter_handle_top_y2);
0961: mUsedParameterLinesOrig.lineTo(parameter_x_cursor,
0962: used_parameter_handle_bottom_y1);
0963:
0964: // add the used parameter texts together with their locations as glyph vectors to the collection of parameter glyph vectors
0965: string_bounds = mElementStyleOrig.mParamFont
0966: .getStringBounds(parameter.getName(),
0967: mElementStyleOrig.mFontRenderContext);
0968: name_bounds = new Rectangle2D.Float(
0969: (float) (parameter_x_cursor
0970: - mElementStyleOrig.mParamMarginWidth - string_bounds
0971: .getHeight()),
0972: used_parameter_handle_top_y2
0973: + mElementStyleOrig.mParamMarginHeight,
0974: (float) string_bounds.getHeight(),
0975: (float) string_bounds.getWidth());
0976: parameter.setNameBounds(name_bounds);
0977: hotspot = new Area(
0978: new Rectangle2D.Float(
0979: (float) name_bounds.getX(),
0980: used_parameter_handle_top_y1,
0981: (float) (parameter_x_cursor
0982: + mElementStyleOrig.mParamLineWidth - name_bounds
0983: .getX()),
0984: used_parameter_handle_bottom_y2
0985: - used_parameter_handle_top_y1));
0986: hotspot.intersect(mBoundingOrig);
0987: parameter.setHotSpot(hotspot);
0988:
0989: // update the horizontal offset and translate the parameter top and bottom handle areas and their connection line
0990: parameter_x_cursor += used_parameter_x_interval;
0991: used_parameter_handle_top_area = used_parameter_handle_top_area
0992: .createTransformedArea(next_used_parameter_transform);
0993: used_parameter_handle_bottom_area = used_parameter_handle_bottom_area
0994: .createTransformedArea(next_used_parameter_transform);
0995: used_parameter_handle_connect.setLine(
0996: parameter_x_cursor,
0997: used_parameter_handle_top_y2,
0998: parameter_x_cursor,
0999: used_parameter_handle_bottom_y1);
1000: }
1001: }
1002:
1003: //
1004: // precalculate added parameters lines and texts
1005: //
1006: if (number_of_added_parameters > 0) {
1007: // move the initial parameter line offset to the position for added parameters
1008: parameter_x_cursor += parameter_rectangle_width / 2;
1009: // calculate the vertical start and end positions of the bottom parameter handles
1010: float added_parameter_line_y1 = mBodyYOffsetOrig
1011: + body_rectangle_height
1012: - (mElementStyleOrig.mParamLineLength / 2);
1013: float added_parameter_line_y2 = mBodyYOffsetOrig
1014: + body_rectangle_height
1015: + (mElementStyleOrig.mParamLineLength / 2);
1016: // create the first parameter handle area
1017: Area added_parameter_line_area = new Area(
1018: new Rectangle2D.Float(parameter_x_cursor
1019: - (mElementStyleOrig.mParamLineWidth / 2),
1020: added_parameter_line_y1,
1021: mElementStyleOrig.mParamLineWidth,
1022: mElementStyleOrig.mParamLineLength));
1023:
1024: // calculate the horizontal interval between the parameters and create the transform object to perform the translation
1025: float added_parameter_x_interval = parameter_rectangle_width
1026: + (parameter_rectangle_width / 2);
1027: AffineTransform next_added_parameter_transform = AffineTransform
1028: .getTranslateInstance(added_parameter_x_interval, 0);
1029:
1030: // process all the added parameters
1031: for (ElementProperty parameter : getAddedParameters()) {
1032: // add the added parameter handle to the body area and bounding area
1033: mBodyAreaOutsideOrig.add(added_parameter_line_area);
1034: mBoundingOrig.add(added_parameter_line_area);
1035:
1036: // add the added parameter texts together with their locations as glyph vectors to the collection of parameter glyph vectors
1037: string_bounds = mElementStyleOrig.mParamFont
1038: .getStringBounds(parameter.getName(),
1039: mElementStyleOrig.mFontRenderContext);
1040: name_bounds = new Rectangle2D.Float(
1041: (float) (parameter_x_cursor
1042: + parameter_text_middle - string_bounds
1043: .getHeight()),
1044: (float) (added_parameter_line_y1
1045: - mElementStyleOrig.mParamMarginHeight - string_bounds
1046: .getWidth()), (float) string_bounds
1047: .getHeight(), (float) string_bounds
1048: .getWidth());
1049: parameter.setNameBounds(name_bounds);
1050: hotspot = new Area(new Rectangle2D.Float(
1051: (float) name_bounds.getX(), (float) name_bounds
1052: .getY(),
1053: (float) name_bounds.getWidth(),
1054: (float) (added_parameter_line_y2 - name_bounds
1055: .getY())));
1056: hotspot.intersect(mBoundingOrig);
1057: parameter.setHotSpot(hotspot);
1058:
1059: // update the horizontal offset and translate the parameter handle area
1060: parameter_x_cursor += added_parameter_x_interval;
1061: added_parameter_line_area = added_parameter_line_area
1062: .createTransformedArea(next_added_parameter_transform);
1063: }
1064: }
1065:
1066: //
1067: // precalculate name text
1068: //
1069: ElementProperty title = getTitle();
1070: title.setNameBounds(new Rectangle2D.Float(mBodyXOffsetOrig
1071: + name_rectangle_x_offset
1072: + (name_rectangle_width - title_text_width) / 2,
1073: mBodyYOffsetOrig + mElementStyleOrig.mTitleMarginHeight
1074: + mElementStyleOrig.mElementBorderWidth,
1075: title_text_width, title_text_height));
1076: title.setHotSpot(mTitleRectangleOutsideOrig);
1077:
1078: //
1079: // create the scaled version, keeping the current scale factor
1080: //
1081: scalePrecalculatedAreas(1);
1082: }
1083:
1084: public void drawElement(Graphics2D g2d) {
1085: Rectangle clip = g2d.getClipBounds();
1086:
1087: if (mBoundingScaled == null) {
1088: createPrecalculatedAreas();
1089: }
1090:
1091: if (clip == null || mBoundingScaled.intersects(clip)) {
1092: boolean drag_outline = Config.getRepInstance().getBool(
1093: "DRAG_OUTLINE");
1094: boolean scrolling_fast = Config.getRepInstance().getBool(
1095: "SCROLLING_FAST");
1096: boolean scrolling_outline = Config.getRepInstance()
1097: .getBool("SCROLLING_OUTLINE");
1098: boolean scroll_active = ((StructurePanel) getParent())
1099: .isScrollActive();
1100:
1101: if ((!mDragActive && !scroll_active)
1102: || (mDragActive && !drag_outline)
1103: || (scroll_active && !scrolling_outline)) {
1104: if (!mSelected) {
1105: g2d
1106: .setColor(mElementStyleScaled.mBodyBackgroundColor);
1107: } else {
1108: g2d
1109: .setColor(mElementStyleScaled.mBodyBackgroundColorSelected);
1110: }
1111: g2d.fill(mBodyAreaInsideScaled);
1112: }
1113: g2d.setColor(mElementStyleScaled.mElementBorderColor);
1114: g2d.fill(mBodyAreaOutsideScaled);
1115:
1116: if ((!mDragActive && !scroll_active)
1117: || (mDragActive && !drag_outline)
1118: || (scroll_active && !scrolling_outline)) {
1119: if (!scrolling_fast || !scroll_active) {
1120: g2d
1121: .setColor(mElementStyleScaled.mElementBorderColor);
1122: g2d
1123: .setStroke(mElementStyleScaled.mParamLineDashedStroke);
1124: g2d.draw(mUsedParameterLinesScaled);
1125: }
1126: if (clip == null
1127: || mTitleRectangleInsideScaled.intersects(clip)) {
1128: g2d.setColor(mTitleBackgroundColor);
1129: g2d.fill(mTitleRectangleInsideScaled);
1130: }
1131: getTitle().draw(g2d);
1132: if (!scrolling_fast || !scroll_active) {
1133: for (ElementProperty property : mElementProperties) {
1134: if (!(property instanceof ElementPropertyTitle)) {
1135: property.draw(g2d);
1136: }
1137: }
1138: }
1139:
1140: mStructurePanel.drawHighlightedProperty(this , g2d);
1141: }
1142: }
1143: }
1144:
1145: public void paintComponent(Graphics g) {
1146: super .paintComponent(g);
1147:
1148: Graphics2D g2d = (Graphics2D) g;
1149:
1150: if (mDragBufferedImage == null) {
1151: g2d = (Graphics2D) g2d.create();
1152: ElementStyle.setRenderingHints(g2d, mScaleFactor);
1153: drawElement(g2d);
1154: } else {
1155: if (mIsTransparent) {
1156: g2d.setComposite(AlphaComposite.getInstance(
1157: AlphaComposite.SRC_OVER, 0.5f));
1158: }
1159:
1160: g2d.drawImage(mDragBufferedImage, null, 0, 0);
1161: }
1162: }
1163:
1164: public BufferedImage getDragBufferedImage() {
1165: return mDragBufferedImage;
1166: }
1167:
1168: public void addElementListener(ElementListener listener) {
1169: mElementListeners.add(listener);
1170: }
1171:
1172: public void removeElementListener(ElementListener listener) {
1173: mElementListeners.remove(listener);
1174: }
1175:
1176: protected void fireElementRepositioned() {
1177: for (ElementListener listener : mElementListeners) {
1178: listener.elementRepositioned(this );
1179: }
1180: }
1181:
1182: protected void fireElementRaised() {
1183: for (ElementListener listener : mElementListeners) {
1184: listener.elementRaised(this );
1185: }
1186: }
1187:
1188: protected void fireElementSelected(int modifiers) {
1189: for (ElementListener listener : mElementListeners) {
1190: listener.elementSelected(this , modifiers);
1191: }
1192: }
1193:
1194: protected void fireElementDeselected(int modifiers) {
1195: for (ElementListener listener : mElementListeners) {
1196: listener.elementDeselected(this , modifiers);
1197: }
1198: }
1199:
1200: protected void fireElementDragged(int x, int y) {
1201: for (ElementListener listener : mElementListeners) {
1202: listener.elementDragged(this , x, y);
1203: }
1204: }
1205:
1206: protected void fireElementDragStart(Point dragStartPoint) {
1207: for (ElementListener listener : mElementListeners) {
1208: listener.elementDragStart(this , dragStartPoint);
1209: }
1210: }
1211:
1212: protected void fireElementDragEnd() {
1213: for (ElementListener listener : mElementListeners) {
1214: listener.elementDragEnd();
1215: }
1216: }
1217:
1218: protected void fireElementPropertyHighlighted(
1219: ElementProperty property) {
1220: for (ElementListener listener : mElementListeners) {
1221: listener.elementPropertyHighlighted(property);
1222: }
1223: }
1224:
1225: protected void repositionElementDuringDrag(int offsetX, int offsetY) {
1226: setLocation(offsetX + getX(), offsetY + getY());
1227: }
1228:
1229: protected void startDrag() {
1230: mDragActive = true;
1231: mDragBufferedImage = new BufferedImage((int) mWidthScaled,
1232: (int) mHeightScaled, BufferedImage.TYPE_INT_ARGB);
1233: Graphics2D g2d = mDragBufferedImage.createGraphics();
1234: ElementStyle.setRenderingHints(g2d, mScaleFactor);
1235: drawElement(g2d);
1236: fireElementRaised();
1237: if (Config.getRepInstance().getBool("DRAG_TRANSPARENT")) {
1238: mIsTransparent = true;
1239: }
1240: }
1241:
1242: protected void endDrag() {
1243: mDragBufferedImage = null;
1244: mDragActive = false;
1245: if (Config.getRepInstance().getBool("DRAG_TRANSPARENT")) {
1246: mIsTransparent = false;
1247: }
1248: fireElementRepositioned();
1249: }
1250:
1251: private ElementProperty locateElementProperty(Point location) {
1252: Shape hotspot = null;
1253: for (ElementProperty property : mElementProperties) {
1254: hotspot = property.getHotSpot();
1255: if (hotspot.contains(location)) {
1256: return property;
1257: }
1258: }
1259:
1260: return null;
1261: }
1262:
1263: private void triggerPopup(Point location) {
1264: fireElementRaised();
1265: ElementProperty property = locateElementProperty(location);
1266: if (property != null) {
1267: property.showPopupMenu(location);
1268: } else {
1269: JPopupMenu popup = new JPopupMenu();
1270: DynamicMenuBuilder menu_builder = new DynamicMenuBuilder();
1271: JMenu menu_add = menu_builder
1272: .addMenu(
1273: popup,
1274: Localization
1275: .getString("rife.element.popupmenu.add"),
1276: Localization
1277: .getChar("rife.element.popupmenu.add.mnemonic"));
1278: menu_builder
1279: .addMenuItem(
1280: menu_add,
1281: Localization
1282: .getString("rife.element.popupmenu.add.exit"),
1283: new AddExit(location),
1284: Localization
1285: .getChar("rife.element.popupmenu.add.exit.mnemonic"));
1286: menu_builder
1287: .addMenuItem(
1288: menu_add,
1289: Localization
1290: .getString("rife.element.popupmenu.add.consumedparameter"),
1291: new AddConsumedParameter(location),
1292: Localization
1293: .getChar("rife.element.popupmenu.add.consumedparameter.mnemonic"));
1294: menu_builder
1295: .addMenuItem(
1296: menu_add,
1297: Localization
1298: .getString("rife.element.popupmenu.add.usedparameter"),
1299: new AddUsedParameter(location),
1300: Localization
1301: .getChar("rife.element.popupmenu.add.usedparameter.mnemonic"));
1302: menu_builder
1303: .addMenuItem(
1304: menu_add,
1305: Localization
1306: .getString("rife.element.popupmenu.add.addedparameter"),
1307: new AddAddedParameter(location),
1308: Localization
1309: .getChar("rife.element.popupmenu.add.addedparameter.mnemonic"));
1310: menu_builder
1311: .addMenuItem(
1312: popup,
1313: Localization
1314: .getString("rife.element.popupmenu.delete"),
1315: new Delete(),
1316: Localization
1317: .getChar("rife.element.popupmenu.delete.mnemonic"));
1318:
1319: popup.show(this , location.x, location.y);
1320: popup.addPopupMenuListener(getStructurePanel());
1321: }
1322: }
1323:
1324: protected class AddExit implements DynamicMenuAction {
1325: private Point mClickedPoint = null;
1326:
1327: public AddExit(Point clickedPoint) {
1328: mClickedPoint = clickedPoint;
1329: }
1330:
1331: public void execute(JMenuItem menuItem) {
1332: ElementPropertyExit exit = addExit("");
1333: createPrecalculatedAreas();
1334: getStructurePanel()
1335: .editElementProperty(exit, mClickedPoint);
1336: }
1337: }
1338:
1339: protected class AddConsumedParameter implements DynamicMenuAction {
1340: private Point mClickedPoint = null;
1341:
1342: public AddConsumedParameter(Point clickedPoint) {
1343: mClickedPoint = clickedPoint;
1344: }
1345:
1346: public void execute(JMenuItem menuItem) {
1347: ElementPropertyParameterConsumed parameter = addConsumedParameter("");
1348: createPrecalculatedAreas();
1349: getStructurePanel().editElementProperty(parameter,
1350: mClickedPoint);
1351: }
1352: }
1353:
1354: protected class AddUsedParameter implements DynamicMenuAction {
1355: private Point mClickedPoint = null;
1356:
1357: public AddUsedParameter(Point clickedPoint) {
1358: mClickedPoint = clickedPoint;
1359: }
1360:
1361: public void execute(JMenuItem menuItem) {
1362: ElementPropertyParameterUsed parameter = addUsedParameter("");
1363: createPrecalculatedAreas();
1364: getStructurePanel().editElementProperty(parameter,
1365: mClickedPoint);
1366: }
1367: }
1368:
1369: protected class AddAddedParameter implements DynamicMenuAction {
1370: private Point mClickedPoint = null;
1371:
1372: public AddAddedParameter(Point clickedPoint) {
1373: mClickedPoint = clickedPoint;
1374: }
1375:
1376: public void execute(JMenuItem menuItem) {
1377: ElementPropertyParameterAdded parameter = addAddedParameter("");
1378: createPrecalculatedAreas();
1379: getStructurePanel().editElementProperty(parameter,
1380: mClickedPoint);
1381: }
1382: }
1383:
1384: protected class Delete implements DynamicMenuAction {
1385: public void execute(JMenuItem menuItem) {
1386: JComponent parent = (JComponent) Element.this .getParent();
1387: if (parent instanceof StructurePanel) {
1388: ((StructurePanel) parent).removeElement(Element.this );
1389: }
1390: }
1391: }
1392:
1393: private void updateHighlightedProperty(Point location) {
1394: ElementProperty property = locateElementProperty(location);
1395: fireElementPropertyHighlighted(property);
1396: }
1397:
1398: public void mouseClicked(MouseEvent e) {
1399: if ((e.getModifiers() & MouseEvent.BUTTON1_MASK) != 0) {
1400: if (e.getClickCount() == 2) {
1401: ElementProperty property = locateElementProperty(e
1402: .getPoint());
1403: if (property != null) {
1404: getStructurePanel().editElementProperty(property,
1405: e.getPoint());
1406: }
1407: }
1408: }
1409: }
1410:
1411: public void mousePressed(MouseEvent e) {
1412: getStructurePanel().removeElementPropertyEditor();
1413:
1414: if (e.isPopupTrigger()) {
1415: triggerPopup(e.getPoint());
1416: } else if ((e.getModifiers() & MouseEvent.BUTTON1_MASK) != 0) {
1417: mDragStartPoint = e.getPoint();
1418: if (!mSelected) {
1419: fireElementSelected(e.getModifiers());
1420: } else {
1421: fireElementDeselected(e.getModifiers());
1422: }
1423: }
1424: }
1425:
1426: public void mouseReleased(MouseEvent e) {
1427: if (e.isPopupTrigger()) {
1428: triggerPopup(e.getPoint());
1429: } else if ((e.getModifiers() & MouseEvent.BUTTON1_MASK) != 0) {
1430: mDragStartPoint = null;
1431: if (mDragActive) {
1432: fireElementDragEnd();
1433: }
1434: }
1435: }
1436:
1437: public void mouseEntered(MouseEvent e) {
1438: updateHighlightedProperty(e.getPoint());
1439: }
1440:
1441: public void mouseExited(MouseEvent e) {
1442: if (!mStructurePanel.isDragActive()
1443: && !mStructurePanel.isElementPropertyBeingEdited()
1444: && !mStructurePanel.isPopupMenuActive()) {
1445: updateHighlightedProperty(new Point(-1, -1));
1446: }
1447: if (mDragActive) {
1448: fireElementDragged(e.getPoint().x, e.getPoint().y);
1449: }
1450: }
1451:
1452: public void mouseDragged(MouseEvent e) {
1453: if (e.getComponent() == this ) {
1454: if ((e.getModifiers() & MouseEvent.BUTTON1_MASK) != 0) {
1455: if (mSelected) {
1456: if (!mDragActive) {
1457: fireElementDragStart(mDragStartPoint);
1458: } else {
1459: fireElementDragged(e.getPoint().x,
1460: e.getPoint().y);
1461: }
1462: }
1463: }
1464: }
1465: }
1466:
1467: public void mouseMoved(MouseEvent e) {
1468: updateHighlightedProperty(e.getPoint());
1469: }
1470: }
|