/*
* Copyright (C) 2006-2016 DLR, Germany
*
* All rights reserved
*
* http://www.rcenvironment.de/
*/
package de.rcenvironment.core.gui.workflow.parts;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.draw2d.ChopboxAnchor;
import org.eclipse.draw2d.ConnectionAnchor;
import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.GridData;
import org.eclipse.draw2d.GridLayout;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.Label;
import org.eclipse.draw2d.LineBorder;
import org.eclipse.draw2d.PositionConstants;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.draw2d.text.FlowPage;
import org.eclipse.draw2d.text.ParagraphTextLayout;
import org.eclipse.draw2d.text.TextFlow;
import org.eclipse.gef.CompoundSnapToHelper;
import org.eclipse.gef.ConnectionEditPart;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.NodeEditPart;
import org.eclipse.gef.Request;
import org.eclipse.gef.RequestConstants;
import org.eclipse.gef.SnapToGeometry;
import org.eclipse.gef.SnapToGrid;
import org.eclipse.gef.SnapToHelper;
import org.eclipse.gef.editparts.AbstractGraphicalEditPart;
import org.eclipse.gef.editpolicies.SnapFeedbackPolicy;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.views.properties.IPropertySource;
import de.rcenvironment.core.component.model.spi.PropertiesChangeSupport;
import de.rcenvironment.core.component.workflow.model.api.WorkflowLabel;
import de.rcenvironment.core.gui.workflow.editor.properties.LabelPropertySource;
/**
* GUI element of the {@link WorkflowLabel}.
*
* @author Sascha Zur
* @author Marc Stammerjohann
* @author Doreen Seider
* @author Jascha Riedel
*/
public class WorkflowLabelPart extends AbstractGraphicalEditPart implements PropertyChangeListener, NodeEditPart {
private static final int MINUS_ONE = -1;
private static final int TWELVE = 12;
private Font headerFont = null;
private Font mainFont = null;
private Color headerTextColor = null;
private Color mainTextColor = null;
private Color labelColor = null;
private TransparentLabel containerLabel;
private IFigure textContainer;
private FlowPage headerFlowPage;
private FlowPage mainFlowPage;
private int currentHeaderTextSize = MINUS_ONE;
private int currentMainTextSize = MINUS_ONE;
@Override
public ConnectionAnchor getSourceConnectionAnchor(ConnectionEditPart connection) {
return new ChopboxAnchor(getFigure());
}
@Override
public ConnectionAnchor getSourceConnectionAnchor(Request request) {
return new ChopboxAnchor(getFigure());
}
@Override
public ConnectionAnchor getTargetConnectionAnchor(ConnectionEditPart connection) {
return new ChopboxAnchor(getFigure());
}
@Override
public ConnectionAnchor getTargetConnectionAnchor(Request request) {
return new ChopboxAnchor(getFigure());
}
@Override
public void performRequest(Request req) {
if (req.getType().equals(RequestConstants.REQ_OPEN)) {
try {
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().showView("org.eclipse.ui.views.PropertySheet");
} catch (PartInitException e) {
throw new RuntimeException(e);
}
}
}
@Override
protected void createEditPolicies() {
installEditPolicy("Snap Feedback", new SnapFeedbackPolicy());
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
String prop = evt.getPropertyName();
if (WorkflowLabel.PROPERTY_CHANGE.equals(prop)) {
refreshVisuals();
}
}
@Override
protected IFigure createFigure() {
containerLabel = new TransparentLabel((WorkflowLabel) getModel());
GridLayout gridLayout = new GridLayout();
gridLayout.verticalSpacing = 10;
gridLayout.numColumns = 1;
containerLabel.setLayoutManager(gridLayout);
textContainer = new Figure();
textContainer.setLayoutManager(new GridLayout(1, false) {
@Override
public void layout(IFigure container) {
super.layout(container);
int availableWidth = container.getClientArea().width - horizontalSpacing * (numColumns - 1)
- marginWidth * 2;
if (container.getClientArea().width + TWELVE + 1 >= containerLabel.getClientArea().width) {
Dimension d = mainFlowPage.getPreferredSize(SWT.DEFAULT, SWT.DEFAULT);
if (d.width < textContainer.getClientArea().width - horizontalSpacing * (numColumns - 1)
- marginWidth * 2) {
((GridData) getConstraint(mainFlowPage)).widthHint = SWT.DEFAULT;
} else {
((GridData) getConstraint(mainFlowPage)).widthHint = availableWidth;
}
if (textContainer.getChildren().contains(headerFlowPage)) {
Dimension dd = headerFlowPage.getPreferredSize(SWT.DEFAULT, SWT.DEFAULT);
if (dd.width < textContainer.getClientArea().width - horizontalSpacing * (numColumns - 1)
- marginWidth * 2) {
((GridData) getConstraint(headerFlowPage)).widthHint = SWT.DEFAULT;
} else {
((GridData) getConstraint(headerFlowPage)).widthHint = availableWidth;
}
}
} else {
((GridData) getConstraint(mainFlowPage)).widthHint = SWT.DEFAULT;
((GridData) getConstraint(headerFlowPage)).widthHint = SWT.DEFAULT;
}
}
});
GridData textContainerGD = new GridData();
textContainerGD.grabExcessHorizontalSpace = true;
textContainerGD.grabExcessVerticalSpace = true;
textContainerGD.horizontalAlignment = GridData.CENTER;
textContainerGD.verticalAlignment = GridData.CENTER;
containerLabel.add(textContainer, textContainerGD);
mainFlowPage = new FlowPage();
TextFlow mainText = new TextFlow();
mainText.setLayoutManager(new ParagraphTextLayout(mainText, ParagraphTextLayout.WORD_WRAP_SOFT));
mainFlowPage.add(mainText);
headerFlowPage = new FlowPage();
TextFlow headerText = new TextFlow();
headerText.setLayoutManager(new ParagraphTextLayout(headerText, ParagraphTextLayout.WORD_WRAP_SOFT));
headerFlowPage.add(headerText);
GridData gridDataHeader = new GridData();
GridData gridDataMain = new GridData();
gridDataMain.grabExcessHorizontalSpace = false;
gridDataMain.grabExcessVerticalSpace = false;
gridDataMain.horizontalAlignment = SWT.FILL;
textContainer.add(headerFlowPage, gridDataHeader, 0);
textContainer.add(mainFlowPage, gridDataMain, 1);
refreshSettings((WorkflowLabel) getModel());
return containerLabel;
}
@Override
protected void refreshVisuals() {
WorkflowLabel label = (WorkflowLabel) getModel();
Point loc = new Point(label.getX(), label.getY());
containerLabel.setLocation(loc);
((GraphicalEditPart) getParent()).setLayoutConstraint(this, containerLabel,
new Rectangle(loc, new Dimension(label.getWidth(), label.getHeight())));
refreshSettings(label);
figure.repaint();
// This is a dirty fix to layout the flowpages correctly.
refreshSettings(label);
figure.repaint();
refreshSettings(label);
figure.repaint();
}
protected void refreshSettings(WorkflowLabel label) {
refreshContainerLabel(label);
textContainer.revalidate();
refreshMainText(label, (TextFlow) mainFlowPage.getChildren().get(0));
refreshHeaderText(label, (TextFlow) headerFlowPage.getChildren().get(0));
refreshPositionOfText(label);
textAlignHeaderPage(label);
textAlignMainPage(label);
textContainer.getUpdateManager().performUpdate();
}
protected void refreshContainerLabel(WorkflowLabel label) {
if (labelColor == null) {
labelColor = new Color(null, label.getColorBackground()[0], label.getColorBackground()[1], label.getColorBackground()[2]);
} else {
if ((labelColor.getRed() != label.getColorBackground()[0])
|| (labelColor.getGreen() != label.getColorBackground()[1])
|| (labelColor.getBlue() != label.getColorBackground()[2])) {
labelColor.dispose();
labelColor = new Color(null, label.getColorBackground()[0], label.getColorBackground()[1], label.getColorBackground()[2]);
}
}
containerLabel.setBackgroundColor(labelColor);
if (label.hasBorder()) {
containerLabel.setBorder(new LineBorder());
} else {
containerLabel.setBorder(null);
}
}
private void refreshPositionOfText(WorkflowLabel label) {
GridData textContainerGD = (GridData) containerLabel.getLayoutManager().getConstraint(textContainer);
// Position of text in Label
switch (label.getLabelPosition()) {
case TOPLEFT:
textContainerGD.verticalAlignment = GridData.BEGINNING;
textContainerGD.horizontalAlignment = GridData.BEGINNING;
break;
case TOPCENTER:
textContainerGD.verticalAlignment = GridData.BEGINNING;
textContainerGD.horizontalAlignment = GridData.CENTER;
break;
case TOPRIGHT:
textContainerGD.verticalAlignment = GridData.BEGINNING;
textContainerGD.horizontalAlignment = GridData.END;
break;
case CENTERLEFT:
textContainerGD.verticalAlignment = GridData.CENTER;
textContainerGD.horizontalAlignment = GridData.BEGINNING;
break;
case CENTER:
textContainerGD.verticalAlignment = GridData.CENTER;
textContainerGD.horizontalAlignment = GridData.CENTER;
break;
case CENTERRIGHT:
textContainerGD.verticalAlignment = GridData.CENTER;
textContainerGD.horizontalAlignment = GridData.END;
break;
case BOTTOMLEFT:
textContainerGD.verticalAlignment = GridData.END;
textContainerGD.horizontalAlignment = GridData.BEGINNING;
break;
case BOTTOMCENTER:
textContainerGD.verticalAlignment = GridData.END;
textContainerGD.horizontalAlignment = GridData.CENTER;
break;
case BOTTOMRIGHT:
textContainerGD.verticalAlignment = GridData.END;
textContainerGD.horizontalAlignment = GridData.END;
break;
default:
textContainerGD.verticalAlignment = GridData.BEGINNING;
textContainerGD.horizontalAlignment = GridData.BEGINNING;
break;
}
}
private void textAlignHeaderPage(WorkflowLabel label) {
switch (label.getHeaderAlignmentType()) {
case LEFT:
headerFlowPage.setHorizontalAligment(PositionConstants.LEFT);
((GridData) textContainer.getLayoutManager().getConstraint(headerFlowPage)).horizontalAlignment = GridData.BEGINNING;
break;
case CENTER:
headerFlowPage.setHorizontalAligment(PositionConstants.CENTER);
((GridData) textContainer.getLayoutManager().getConstraint(headerFlowPage)).horizontalAlignment = GridData.CENTER;
break;
case RIGHT:
headerFlowPage.setHorizontalAligment(PositionConstants.RIGHT);
((GridData) textContainer.getLayoutManager().getConstraint(headerFlowPage)).horizontalAlignment = GridData.END;
break;
default:
headerFlowPage.setHorizontalAligment(PositionConstants.LEFT);
((GridData) textContainer.getLayoutManager().getConstraint(headerFlowPage)).horizontalAlignment = GridData.BEGINNING;
break;
}
}
private void textAlignMainPage(WorkflowLabel label) {
switch (label.getTextAlignmentType()) {
case LEFT:
mainFlowPage.setHorizontalAligment(PositionConstants.LEFT);
break;
case CENTER:
mainFlowPage.setHorizontalAligment(PositionConstants.CENTER);
break;
case RIGHT:
mainFlowPage.setHorizontalAligment(PositionConstants.RIGHT);
break;
default:
mainFlowPage.setHorizontalAligment(PositionConstants.LEFT);
break;
}
}
protected void refreshHeaderText(WorkflowLabel label, TextFlow textFlow) {
if (label.getHeaderText().isEmpty()
&& textContainer.getChildren().contains(headerFlowPage)) {
textContainer.remove(headerFlowPage);
return;
} else if (label.getHeaderText().isEmpty()) {
return;
} else {
if (!textContainer.getChildren().contains(headerFlowPage)) {
textContainer.add(headerFlowPage, 0);
}
}
textFlow.setText(label.getHeaderText());
if (label.getHeaderTextSize() != currentHeaderTextSize
&& textFlow.getFont() != null && textFlow.getFont().getFontData().length > 0) {
FontData[] fD = textFlow.getFont().getFontData();
int size = label.getHeaderTextSize();
fD[0].setHeight(size);
currentHeaderTextSize = size;
if (headerFont != null) {
headerFont.dispose();
}
headerFont = new Font(Display.getDefault(), fD[0]);
textFlow.setFont(headerFont);
}
if (headerTextColor == null) {
headerTextColor = new Color(null, label.getColorHeader()[0], label.getColorHeader()[1], label.getColorHeader()[2]);
} else {
if ((headerTextColor.getRed() != label.getColorHeader()[0])
|| (headerTextColor.getGreen() != label.getColorHeader()[1])
|| (headerTextColor.getBlue() != label.getColorHeader()[2])) {
headerTextColor.dispose();
headerTextColor = new Color(null, label.getColorHeader()[0], label.getColorHeader()[1], label.getColorHeader()[2]);
}
}
textFlow.setForegroundColor(headerTextColor);
}
protected void refreshMainText(WorkflowLabel label, TextFlow textFlow) {
textFlow.setText(label.getText());
if (label.getTextSize() != currentMainTextSize
&& textFlow.getFont() != null && textFlow.getFont().getFontData().length > 0) {
FontData[] fD = textFlow.getFont().getFontData();
int size = label.getTextSize();
fD[0].setHeight(size);
currentMainTextSize = size;
if (mainFont != null) {
mainFont.dispose();
}
mainFont = new Font(Display.getDefault(), fD[0]);
textFlow.setFont(mainFont);
}
if (mainTextColor == null) {
mainTextColor = new Color(null, label.getColorText()[0], label.getColorText()[1], label.getColorText()[2]);
} else {
if ((mainTextColor.getRed() != label.getColorText()[0])
|| (mainTextColor.getGreen() != label.getColorText()[1])
|| (mainTextColor.getBlue() != label.getColorText()[2])) {
mainTextColor.dispose();
mainTextColor = new Color(null, label.getColorText()[0], label.getColorText()[1], label.getColorText()[2]);
}
}
textFlow.setForegroundColor(mainTextColor);
textFlow.revalidate();
}
/**
* A label that can be transparent.
*
* @author Sascha Zur
*/
protected class TransparentLabel extends Label {
private static final int ROUNDED_RECTANGLE_SIZE = 10;
private final WorkflowLabel label;
public TransparentLabel(WorkflowLabel label) {
super();
this.label = label;
}
@Override
protected void paintFigure(Graphics graphics) {
int oldAlpha = graphics.getAlpha();
int[] colorBackground = ((WorkflowLabel) getModel()).getColorBackground();
//FIXME: resource leak: The color object is never disposed!
graphics.setBackgroundColor(new Color(null, colorBackground[0], colorBackground[1], colorBackground[2]));
graphics.setAlpha(label.getAlpha());
graphics.fillRoundRectangle(getBounds(), ROUNDED_RECTANGLE_SIZE, ROUNDED_RECTANGLE_SIZE);
graphics.setAlpha(oldAlpha);
}
}
@Override
public void activate() {
super.activate();
((PropertiesChangeSupport) getModel()).addPropertyChangeListener(this);
}
@Override
public void deactivate() {
super.deactivate();
((PropertiesChangeSupport) getModel()).removePropertyChangeListener(this);
if (mainFont != null) {
mainFont.dispose();
}
if (headerFont != null) {
headerFont.dispose();
}
}
@Override
public Object getAdapter(@SuppressWarnings("rawtypes") Class type) {
if (type == IPropertySource.class) {
return new LabelPropertySource(getViewer().getEditDomain().getCommandStack(), (WorkflowLabel) getModel());
}
if (type == SnapToHelper.class) {
List<SnapToHelper> helpers = new ArrayList<SnapToHelper>();
if (Boolean.TRUE.equals(getViewer().getProperty(SnapToGeometry.PROPERTY_SNAP_ENABLED))) {
helpers.add(new SnapToGeometry(this));
}
if (Boolean.TRUE.equals(getViewer().getProperty(SnapToGrid.PROPERTY_GRID_ENABLED))) {
helpers.add(new SnapToGrid(this));
}
if (helpers.size() == 0) {
return null;
} else {
return new CompoundSnapToHelper(helpers.toArray(new SnapToHelper[0]));
}
}
return super.getAdapter(type);
}
}