/*
* Copyright (C) 2006-2016 DLR, Germany
*
* All rights reserved
*
* http://www.rcenvironment.de/
*/
package de.rcenvironment.core.gui.workflow.editor.properties;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Arrays;
import org.eclipse.gef.commands.Command;
import org.eclipse.jface.preference.ColorSelector;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Scale;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Spinner;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.forms.widgets.Section;
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;
import de.rcenvironment.core.component.workflow.model.api.WorkflowLabel;
import de.rcenvironment.core.component.workflow.model.api.WorkflowLabel.LabelPosition;
import de.rcenvironment.core.component.workflow.model.api.WorkflowLabel.TextAlignmentType;
import de.rcenvironment.core.gui.utils.incubator.NumericalTextConstraintListener;
import de.rcenvironment.core.gui.workflow.parts.WorkflowLabelPart;
import de.rcenvironment.core.utils.common.OSFamily;
/**
* Property Section for all WorkflowLabel.
*
* @author Sascha Zur
* @author Marc Stammerjohann
* @author Doreen Seider
* @author Hendrik Abbenhaus
*/
public class WorkflowLabelPropertySection extends WorkflowPropertySection implements WorkflowLabelCommand.Executor {
private static final int HORIZONTAL_SPACING = 20;
private static final int COLORSELECTOROFFSET_X = 50;
private static final int COLORSELECTOROFFSET_Y = 200;
private static final int ALPHA_TEXT_WIDTH = 25;
private static final String TABS = " ";
private static final int MAX_255 = 255;
private static final int MAX_100 = 100;
private static final double SCALE_TO_PERCENT_FACTOR = 2.55;
private static final String COLOR = "Color:";
private WorkflowLabel label;
private StyledText headerTextField;
private StyledText textfield;
private Button[] labelPositionButtons;
private Button[] headerAlignmentButtons;
private Button[] textAlignmentButtons;
private LabelPosition[] values;
private Label headerColorPreviewLabel;
private Label textColorPreviewLabel;
private Spinner headerSizeSpinner;
private Spinner textSizeSpinner;
private Label bgColorPreviewLabel;
private Scale bgAlphaScale;
private Text bgAlphaValueText;
private Button bgBorderButton;
private EditValueCommand editTextCommand;
private EditValueCommand editTransparencyCommand;
private final Updater updater = createUpdater();
private final Synchronizer synchronizer = createSynchronizer();
private final SynchronizerAdapter synchronizerAdapter = new SynchronizerAdapter();
@Override
public void setInput(final IWorkbenchPart part, final ISelection selection) {
final Object firstSelectionElement = ((IStructuredSelection) selection).getFirstElement();
final WorkflowLabelPart workflowLabelPart = (WorkflowLabelPart) firstSelectionElement;
final WorkflowLabel workflowLabel = (WorkflowLabel) workflowLabelPart.getModel();
if (getPart() == null || !getPart().equals(part)
|| label == null || !label.equals(workflowLabel)) {
super.setInput(part, selection);
setWorkflowLabelBase(workflowLabel);
updateLabelPositionSelection(label.getLabelPosition());
updateAlignmentButtonsSelection(headerAlignmentButtons, label.getHeaderAlignmentType());
updateAlignmentButtonsSelection(textAlignmentButtons, label.getTextAlignmentType());
if (headerTextField != null && !headerTextField.isDisposed()) {
headerTextField.setText(workflowLabel.getHeaderText());
headerTextField.setSelection(headerTextField.getText().length());
headerColorPreviewLabel.setBackground(createColor(label.getColorHeader()));
headerSizeSpinner.setSelection(label.getHeaderTextSize());
headerAlignmentButtons[label.getHeaderAlignmentType().ordinal()].setSelection(true);
}
if (textfield != null && !textfield.isDisposed()) {
textfield.setText(workflowLabel.getText());
textColorPreviewLabel.setBackground(createColor(label.getColorText()));
textSizeSpinner.setSelection(label.getTextSize());
textAlignmentButtons[label.getTextAlignmentType().ordinal()].setSelection(true);
bgColorPreviewLabel.setBackground(createColor(label.getColorBackground()));
bgAlphaScale.setSelection(label.getAlphaDisplay());
bgAlphaValueText.setText("" + ((int) Math.ceil((label.getAlphaDisplay() / SCALE_TO_PERCENT_FACTOR))));
bgBorderButton.setSelection(label.hasBorder());
}
}
}
private static Color createColor(int[] color) {
return new Color(Display.getCurrent(), color[0], color[1], color[2]);
}
private void setWorkflowLabelBase(final WorkflowLabel workflowLabel) {
this.label = workflowLabel;
initializeModelBindingBase();
}
protected final Updater getUpdater() {
return updater;
}
protected Updater createUpdater() {
return new DefaultUpdater();
}
protected Synchronizer createSynchronizer() {
return new DefaultSynchronizer();
}
@Override
public void dispose() {
tearDownModelBindingBase();
super.dispose();
}
private void initializeModelBindingBase() {
label.addPropertyChangeListener(synchronizerAdapter);
}
private void tearDownModelBindingBase() {
label.removePropertyChangeListener(synchronizerAdapter);
}
@Override
public void createControls(Composite parent, TabbedPropertySheetPage aTabbedPropertySheetPage) {
GridData mGridData = new GridData(GridData.FILL_BOTH);
mGridData.grabExcessHorizontalSpace = true;
mGridData.grabExcessVerticalSpace = true;
mGridData.horizontalAlignment = SWT.FILL;
parent.setLayoutData(mGridData);
parent.setLayout(new GridLayout(2, false));
createHeaderSection(aTabbedPropertySheetPage, parent);
createBackgroundSection(aTabbedPropertySheetPage, parent);
Composite composite = new Composite(parent, SWT.NONE);
GridData cData = new GridData();
cData.horizontalSpan = 2;
cData.grabExcessHorizontalSpace = false;
cData.grabExcessVerticalSpace = true;
cData.horizontalAlignment = SWT.FILL;
cData.verticalAlignment = SWT.FILL;
composite.setLayoutData(cData);
GridLayout mainLayout = new GridLayout(4, false);
mainLayout.marginTop = 0;
mainLayout.marginLeft = 0;
mainLayout.marginWidth = 0;
mainLayout.marginHeight = 0;
composite.setLayout(mainLayout);
createTextSection(aTabbedPropertySheetPage, composite);
createPositionSection(aTabbedPropertySheetPage, composite);
}
private void createHeaderSection(TabbedPropertySheetPage tabbedPropertySheetPage, Composite parent) {
final Section headerPropertiesSection = tabbedPropertySheetPage.getWidgetFactory().createSection(parent, Section.TITLE_BAR);
GridData hGridData = new GridData(GridData.FILL_BOTH);
hGridData.horizontalSpan = 1;
hGridData.grabExcessHorizontalSpace = true;
hGridData.grabExcessVerticalSpace = false;
// hGridData
headerPropertiesSection.setLayoutData(hGridData);
headerPropertiesSection.setLayout(new GridLayout(1, false));
headerPropertiesSection.setText("Header");
Composite headerPropertiesComposite = tabbedPropertySheetPage.getWidgetFactory().createComposite(headerPropertiesSection);
GridData hPGridData = new GridData(GridData.FILL | GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL);
hPGridData.horizontalSpan = 2;
headerPropertiesComposite.setLayout(new GridLayout(4, false));
headerPropertiesComposite.setLayoutData(hPGridData);
headerPropertiesSection.setClient(headerPropertiesComposite);
headerTextField = new StyledText(headerPropertiesComposite, SWT.SINGLE | SWT.BORDER);
GridData headerTextData = new GridData(GridData.GRAB_HORIZONTAL | GridData.FILL | GridData.FILL_HORIZONTAL);
headerTextField.setLayoutData(headerTextData);
headerTextField.addModifyListener(new ModifyListener() {
@Override
public void modifyText(ModifyEvent arg0) {
String oldValue = label.getHeaderText();
String newValue = headerTextField.getText();
if (!newValue.equals(oldValue)) {
int position = headerTextField.getCaretOffset();
if (editTextCommand == null) {
editTextCommand =
editProperty(new Value(Value.ValueType.HEADER_TEXT, oldValue),
new Value(Value.ValueType.HEADER_TEXT, newValue));
} else {
editTextCommand.setNewValue(new Value(Value.ValueType.HEADER_TEXT, newValue));
}
headerTextField.setCaretOffset(position);
}
}
});
headerTextField.addKeyListener(new TextKeyListener());
headerTextField.addFocusListener(new FocusListener() {
@Override
public void focusGained(FocusEvent arg0) {}
@Override
public void focusLost(FocusEvent arg0) {
editTextCommand = null;
}
});
Composite textColorSizePropertiesComposite = new Composite(headerPropertiesComposite, SWT.NONE);
GridLayout gridLayout = new GridLayout(2, false);
gridLayout.horizontalSpacing = HORIZONTAL_SPACING;
textColorSizePropertiesComposite.setLayout(gridLayout);
textColorSizePropertiesComposite.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE));
GridData g2 = new GridData();
g2.horizontalSpan = 1;
textColorSizePropertiesComposite.setLayoutData(g2);
Composite textColorComposite = new Composite(textColorSizePropertiesComposite, SWT.NONE);
textColorComposite.setLayout(new GridLayout(2, false));
textColorComposite.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE));
Label textColorLabel = new Label(textColorComposite, SWT.NONE);
textColorLabel.setText(COLOR);
textColorLabel.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE));
headerColorPreviewLabel = new Label(textColorComposite, SWT.BORDER);
headerColorPreviewLabel.setText(TABS);
headerColorPreviewLabel.addMouseListener(new ColorMouseListener(Value.ValueType.COLOR_HEADER));
Composite textSizeComposite = new Composite(textColorSizePropertiesComposite, SWT.NONE);
textSizeComposite.setLayout(new GridLayout(2, false));
textSizeComposite.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE));
Label textSizeLabel = new Label(textSizeComposite, SWT.NONE);
textSizeLabel.setText("Size:");
textSizeLabel.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE));
headerSizeSpinner = new Spinner(textSizeComposite, SWT.BORDER);
headerSizeSpinner.setMinimum(1);
final int maxFontSize = 99;
headerSizeSpinner.setMaximum(maxFontSize);
headerSizeSpinner.addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent event) {
int oldValue = label.getHeaderTextSize();
int newValue = headerSizeSpinner.getSelection();
if (newValue != oldValue) {
editProperty(new Value(Value.ValueType.HEADER_SIZE, oldValue), new Value(Value.ValueType.HEADER_SIZE, newValue));
}
}
@Override
public void widgetDefaultSelected(SelectionEvent event) {
widgetSelected(event);
}
});
headerAlignmentButtons = new Button[3];
addHeaderAlignmentGroup(headerPropertiesComposite);
}
private void createTextSection(TabbedPropertySheetPage tabbedPropertySheetPage, Composite parent) {
final Section textPropertiesSection = tabbedPropertySheetPage.getWidgetFactory().createSection(parent, Section.TITLE_BAR);
GridData tGridData = new GridData(GridData.FILL_BOTH);
tGridData.horizontalSpan = 3;
tGridData.grabExcessHorizontalSpace = true;
tGridData.grabExcessVerticalSpace = true;
textPropertiesSection.setLayoutData(tGridData);
textPropertiesSection.setLayout(new GridLayout(1, false));
textPropertiesSection.setText("Text");
Composite textPropertiesComposite = tabbedPropertySheetPage.getWidgetFactory().createComposite(textPropertiesSection, SWT.NONE);
GridData tPGridData = new GridData(GridData.FILL_BOTH);
tPGridData.horizontalSpan = 1;
tPGridData.grabExcessHorizontalSpace = true;
tPGridData.grabExcessVerticalSpace = true;
tPGridData.horizontalAlignment = GridData.FILL;
tPGridData.verticalAlignment = GridData.FILL;
textPropertiesComposite.setLayoutData(tPGridData);
textPropertiesComposite.setLayout(new GridLayout(3, false));
textPropertiesSection.setClient(textPropertiesComposite);
textfield = new StyledText(textPropertiesComposite, SWT.MULTI | SWT.BORDER | SWT.WRAP | SWT.V_SCROLL);
GridData textData = new GridData();
textData.grabExcessHorizontalSpace = true;
textData.grabExcessVerticalSpace = true;
textData.horizontalAlignment = GridData.FILL;
textData.verticalAlignment = GridData.FILL;
textData.minimumWidth = 1;
textData.widthHint = 1;
textData.heightHint = 1;
textData.minimumHeight = 1;
textfield.setLayoutData(textData);
textfield.addModifyListener(new ModifyListener() {
@Override
public void modifyText(ModifyEvent arg0) {
String oldValue = label.getText();
String newValue = textfield.getText();
if (!newValue.equals(oldValue)) {
int position = textfield.getCaretOffset();
if (editTextCommand == null) {
editTextCommand =
editProperty(new Value(Value.ValueType.TEXT, oldValue), new Value(Value.ValueType.TEXT, newValue));
} else {
editTextCommand.setNewValue(new Value(Value.ValueType.TEXT, newValue));
}
textfield.setCaretOffset(position);
}
}
});
textfield.addKeyListener(new TextKeyListener());
textfield.addFocusListener(new FocusListener() {
@Override
public void focusLost(FocusEvent arg0) {
editTextCommand = null;
}
@Override
public void focusGained(FocusEvent arg0) {}
});
Composite textColorSizePropertiesComposite = new Composite(textPropertiesComposite, SWT.NONE);
GridLayout gridLayout = new GridLayout(2, false);
gridLayout.horizontalSpacing = HORIZONTAL_SPACING;
textColorSizePropertiesComposite.setLayout(gridLayout);
textColorSizePropertiesComposite.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE));
GridData g2 = new GridData();
g2.horizontalSpan = 1;
g2.verticalAlignment = GridData.BEGINNING;
textColorSizePropertiesComposite.setLayoutData(g2);
Composite textColorComposite = new Composite(textColorSizePropertiesComposite, SWT.NONE);
textColorComposite.setLayout(new GridLayout(2, false));
textColorComposite.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE));
Label textColorLabel = new Label(textColorComposite, SWT.NONE);
textColorLabel.setText(COLOR);
textColorLabel.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE));
textColorPreviewLabel = new Label(textColorComposite, SWT.BORDER);
textColorPreviewLabel.setText(TABS);
textColorPreviewLabel.addMouseListener(new ColorMouseListener(Value.ValueType.COLOR_TEXT));
Composite textSizeComposite = new Composite(textColorSizePropertiesComposite, SWT.NONE);
textSizeComposite.setLayout(new GridLayout(2, false));
textSizeComposite.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE));
Label textSizeLabel = new Label(textSizeComposite, SWT.NONE);
textSizeLabel.setText("Size:");
textSizeLabel.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE));
textSizeSpinner = new Spinner(textSizeComposite, SWT.BORDER);
textSizeSpinner.setMinimum(1);
final int maxFontSize = 99;
textSizeSpinner.setMaximum(maxFontSize);
textSizeSpinner.addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent event) {
int oldValue = label.getTextSize();
int newValue = textSizeSpinner.getSelection();
if (newValue != oldValue) {
editProperty(new Value(Value.ValueType.TEXT_SIZE, oldValue), new Value(Value.ValueType.TEXT_SIZE, newValue));
}
}
@Override
public void widgetDefaultSelected(SelectionEvent event) {
widgetSelected(event);
}
});
textAlignmentButtons = new Button[3];
addTextAlignmentGroup(textPropertiesComposite);
}
private void createBackgroundSection(TabbedPropertySheetPage tabbedPropertySheetPage, Composite parent) {
final Section bgPropertiesSection = tabbedPropertySheetPage.getWidgetFactory().createSection(parent, Section.TITLE_BAR);
bgPropertiesSection.setText("Background");
GridData sGridData = new GridData();
sGridData.horizontalSpan = 1;
sGridData.horizontalAlignment = GridData.HORIZONTAL_ALIGN_END;
sGridData.verticalAlignment = GridData.HORIZONTAL_ALIGN_BEGINNING;
bgPropertiesSection.setLayoutData(sGridData);
Composite bgPropertiesComposite = tabbedPropertySheetPage.getWidgetFactory().createComposite(bgPropertiesSection);
GridLayout gridLayout = new GridLayout(3, false);
gridLayout.horizontalSpacing = HORIZONTAL_SPACING;
bgPropertiesComposite.setLayout(gridLayout);
bgPropertiesComposite.setLayoutData(
new GridData(GridData.FILL_BOTH | GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL | SWT.BORDER));
bgPropertiesSection.setClient(bgPropertiesComposite);
Composite bgColorComposite = new Composite(bgPropertiesComposite, SWT.NONE);
bgColorComposite.setLayout(new GridLayout(2, false));
bgColorComposite.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE));
Label bgColorLabel = new Label(bgColorComposite, SWT.NONE);
bgColorLabel.setText("Color:");
bgColorLabel.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE));
bgColorPreviewLabel = new Label(bgColorComposite, SWT.BORDER);
bgColorPreviewLabel.setText(TABS);
bgColorPreviewLabel.addMouseListener(new ColorMouseListener(Value.ValueType.COLOR_BACKGROUND));
Composite bgAlphaComposite = new Composite(bgPropertiesComposite, SWT.NONE);
bgAlphaComposite.setLayout(new GridLayout(3, false));
bgAlphaComposite.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE));
Label bgAlphaLabel = new Label(bgAlphaComposite, SWT.NONE);
bgAlphaLabel.setText("Transparency:");
bgAlphaLabel.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE));
bgAlphaScale = new Scale(bgAlphaComposite, SWT.HORIZONTAL);
bgAlphaScale.setMaximum(MAX_255);
bgAlphaScale.setMinimum(0);
bgAlphaScale.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE));
bgAlphaScale.addSelectionListener(new AplhaSelectionListener());
bgAlphaScale.addFocusListener(new FocusListener() {
@Override
public void focusLost(FocusEvent arg0) {
editTransparencyCommand = null;
}
@Override
public void focusGained(FocusEvent arg0) {}
});
bgAlphaValueText = new Text(bgAlphaComposite, SWT.NONE);
bgAlphaValueText.setEditable(false);
bgAlphaValueText.addVerifyListener(new NumericalTextConstraintListener(bgAlphaValueText,
NumericalTextConstraintListener.ONLY_INTEGER));
bgAlphaValueText.addModifyListener(new AlphaValueListener());
GridData alphaData = new GridData();
alphaData.widthHint = ALPHA_TEXT_WIDTH;
bgAlphaValueText.setLayoutData(alphaData);
bgAlphaValueText.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE));
bgBorderButton = new Button(bgPropertiesComposite, SWT.CHECK);
bgBorderButton.setText("Border");
bgBorderButton.addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent event) {
boolean oldValue = label.hasBorder();
boolean newValue = bgBorderButton.getSelection();
if (newValue != oldValue) {
editProperty(new Value(Value.ValueType.BORDER, oldValue), new Value(Value.ValueType.BORDER, newValue));
}
}
@Override
public void widgetDefaultSelected(SelectionEvent event) {
widgetSelected(event);
}
});
}
private void createPositionSection(TabbedPropertySheetPage tabbedPropertySheetPage, Composite parent) {
final Section positionSection = tabbedPropertySheetPage.getWidgetFactory().createSection(parent, Section.TITLE_BAR);
GridData positionGridData = new GridData(GridData.FILL_VERTICAL);
positionGridData.horizontalAlignment = GridData.END;
positionGridData.grabExcessHorizontalSpace = false;
positionGridData.grabExcessVerticalSpace = true;
positionSection.setLayoutData(positionGridData);
positionSection.setLayout(new FillLayout());
positionSection.setText("Text Position");
Composite positionPropertiesComposite = tabbedPropertySheetPage.getWidgetFactory().createComposite(positionSection);
positionPropertiesComposite.setLayout(new GridLayout(1, false));
positionSection.setClient(positionPropertiesComposite);
Group positionGroup = new Group(positionPropertiesComposite, SWT.SHADOW_IN);
GridLayout gridLayout = new GridLayout(3, true);
gridLayout.horizontalSpacing = 10;
gridLayout.verticalSpacing = 10;
positionGroup.setLayout(gridLayout);
GridData groupGridData = new GridData();
groupGridData.verticalAlignment = GridData.BEGINNING;
groupGridData.grabExcessHorizontalSpace = true;
positionGroup.setLayoutData(groupGridData);
int[] horizontalAlignment = { GridData.BEGINNING, GridData.CENTER, GridData.END };
int[] verticalAlignment = horizontalAlignment;
labelPositionButtons = new Button[9];
values = LabelPosition.values();
int buttonIndex = 0;
for (int j = 0; j < verticalAlignment.length; j++) {
for (int i = 0; i < horizontalAlignment.length; i++) {
labelPositionButtons[buttonIndex] = new Button(positionGroup, SWT.RADIO);
GridData gridData = new GridData(horizontalAlignment[i], verticalAlignment[j], true, true, 1, 1);
labelPositionButtons[buttonIndex].setLayoutData(gridData);
labelPositionButtons[buttonIndex].addSelectionListener(new PositionSelectionListener(values[buttonIndex]));
buttonIndex++;
}
}
}
private void addHeaderAlignmentGroup(Composite parent) {
Group alignmentGroup = new Group(parent, SWT.SHADOW_IN);
alignmentGroup.setText(Messages.textAlignment);
alignmentGroup.setLayout(new GridLayout(3, true));
Button leftAlignment = new Button(alignmentGroup, SWT.RADIO | SWT.LEFT);
leftAlignment.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, true, true, 1, 1));
leftAlignment.addSelectionListener(new TextAlignmentSelectionListener(Value.ValueType.HEADER_ALIGNMENT, TextAlignmentType.LEFT));
headerAlignmentButtons[0] = leftAlignment;
Button centerAlignment = new Button(alignmentGroup, SWT.RADIO | SWT.CENTER);
centerAlignment.setLayoutData(new GridData(SWT.CENTER, SWT.FILL, true, true, 1, 1));
centerAlignment.addSelectionListener(
new TextAlignmentSelectionListener(Value.ValueType.HEADER_ALIGNMENT, TextAlignmentType.CENTER));
headerAlignmentButtons[1] = centerAlignment;
Button rightAlignment = new Button(alignmentGroup, SWT.RADIO | SWT.RIGHT);
rightAlignment.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, true, 1, 1));
rightAlignment.addSelectionListener(new TextAlignmentSelectionListener(Value.ValueType.HEADER_ALIGNMENT, TextAlignmentType.RIGHT));
headerAlignmentButtons[2] = rightAlignment;
}
private void addTextAlignmentGroup(Composite parent) {
Group alignmentGroup = new Group(parent, SWT.SHADOW_IN);
GridData gridData = new GridData();
gridData.verticalAlignment = GridData.BEGINNING;
alignmentGroup.setText(Messages.textAlignment);
alignmentGroup.setLayoutData(gridData);
alignmentGroup.setLayout(new GridLayout(3, true));
Button leftAlignment = new Button(alignmentGroup, SWT.RADIO | SWT.LEFT);
leftAlignment.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, true, true, 1, 1));
leftAlignment.addSelectionListener(new TextAlignmentSelectionListener(Value.ValueType.TEXT_ALIGNMENT, TextAlignmentType.LEFT));
textAlignmentButtons[0] = leftAlignment;
Button centerAlignment = new Button(alignmentGroup, SWT.RADIO | SWT.CENTER);
centerAlignment.setLayoutData(new GridData(SWT.CENTER, SWT.FILL, true, true, 1, 1));
centerAlignment.addSelectionListener(new TextAlignmentSelectionListener(Value.ValueType.TEXT_ALIGNMENT, TextAlignmentType.CENTER));
textAlignmentButtons[1] = centerAlignment;
Button rightAlignment = new Button(alignmentGroup, SWT.RADIO | SWT.RIGHT);
rightAlignment.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, true, 1, 1));
rightAlignment.addSelectionListener(new TextAlignmentSelectionListener(Value.ValueType.TEXT_ALIGNMENT, TextAlignmentType.RIGHT));
textAlignmentButtons[2] = rightAlignment;
}
private void updateLabelPositionSelection(LabelPosition labelPosition) {
for (int i = 0; i < values.length; i++) {
if (values[i].equals(labelPosition)) {
labelPositionButtons[i].setSelection(true);
} else {
labelPositionButtons[i].setSelection(false);
}
}
}
private void updateAlignmentButtonsSelection(Button[] buttonList, TextAlignmentType textAlignmentType) {
if (buttonList == null) {
return;
}
switch (textAlignmentType) {
case LEFT:
buttonList[0].setSelection(true);
buttonList[1].setSelection(false);
buttonList[2].setSelection(false);
break;
case CENTER:
buttonList[0].setSelection(false);
buttonList[1].setSelection(true);
buttonList[2].setSelection(false);
break;
case RIGHT:
buttonList[0].setSelection(false);
buttonList[1].setSelection(false);
buttonList[2].setSelection(true);
break;
default:
break;
}
}
protected EditValueCommand editProperty(final Value oldValue, final Value newValue) {
final EditValueCommand command = new EditValueCommand(oldValue, newValue);
execute(command);
return command;
}
private void updateContent() {
Display.getCurrent().asyncExec(new Runnable() {
@Override
public void run() {
if (isAccessible(headerTextField)) {
int location = headerTextField.getCaretOffset(); // remember caret location because setting the text resets it
headerTextField.setText(label.getHeaderText());
headerTextField.setSelection(location);
}
if (isAccessible(textfield)) {
int location = textfield.getCaretOffset(); // remember caret location because setting the text resets it
textfield.setText(label.getText());
textfield.setSelection(location);
}
if (isAccessible(headerColorPreviewLabel)) {
headerColorPreviewLabel.setBackground(
new Color(null, label.getColorHeader()[0], label.getColorHeader()[1], label.getColorHeader()[2]));
}
if (isAccessible(textColorPreviewLabel)) {
// FIXME: resource leak: The color object is never disposed!
textColorPreviewLabel.setBackground(
new Color(null, label.getColorText()[0], label.getColorText()[1], label.getColorText()[2]));
}
if (isAccessible(bgColorPreviewLabel)) {
// FIXME: resource leak: The color object is never disposed!
bgColorPreviewLabel.setBackground(new Color(null, label.getColorBackground()[0], label.getColorBackground()[1], label
.getColorBackground()[2]));
}
if (isAccessible(bgAlphaScale)) {
bgAlphaScale.setSelection(label.getAlphaDisplay());
}
if (isAccessible(bgAlphaValueText)) {
bgAlphaValueText.setText("" + ((int) Math.ceil((label.getAlphaDisplay() / SCALE_TO_PERCENT_FACTOR))));
}
if (isAccessible(bgBorderButton)) {
bgBorderButton.setSelection(label.hasBorder());
}
if (isAccessible(labelPositionButtons)) {
updateLabelPositionSelection(label.getLabelPosition());
}
if (isAccessible(textAlignmentButtons)) {
updateAlignmentButtonsSelection(textAlignmentButtons, label.getTextAlignmentType());
}
if (isAccessible(headerAlignmentButtons)) {
updateAlignmentButtonsSelection(headerAlignmentButtons, label.getHeaderAlignmentType());
}
if (isAccessible(headerSizeSpinner)) {
headerSizeSpinner.setSelection(label.getHeaderTextSize());
}
if (isAccessible(textSizeSpinner)) {
textSizeSpinner.setSelection(label.getTextSize());
}
}
});
}
private boolean isAccessible(Control[] controls) {
boolean accessible = true;
for (Control c : Arrays.asList(controls)) {
accessible &= isAccessible(c);
}
return accessible;
}
private boolean isAccessible(Control c) {
return c != null && !c.isDisposed();
}
@Override
public void aboutToBeShown() {
super.aboutToBeShown();
updateContent();
}
/**
* Selection listener for selecting the alignment.
*
* @author Marc Stammerjohann
*/
private class PositionSelectionListener implements SelectionListener {
private LabelPosition type;
PositionSelectionListener(LabelPosition type) {
this.type = type;
}
@Override
public void widgetSelected(SelectionEvent event) {
LabelPosition oldValue = label.getLabelPosition();
Button selectedButton = (Button) event.getSource();
if (selectedButton.getSelection()) {
if (!type.equals(oldValue)) {
editProperty(new Value(Value.ValueType.LABEL_POSITION, oldValue), new Value(Value.ValueType.TEXT_ALIGNMENT, type));
}
if (OSFamily.isLinux()) {
// preventing focus frame around the empty button text
textfield.setFocus();
}
}
}
@Override
public void widgetDefaultSelected(SelectionEvent event) {}
}
/**
* Selection listener for alignment selection.
*
* @author Jascha Riedel
*/
private class TextAlignmentSelectionListener implements SelectionListener {
private final TextAlignmentType textAlignmentType;
private final Value.ValueType valueType;
TextAlignmentSelectionListener(Value.ValueType valueType, TextAlignmentType textAlignmentType) {
this.valueType = valueType;
this.textAlignmentType = textAlignmentType;
}
@Override
public void widgetDefaultSelected(SelectionEvent arg0) {}
@Override
public void widgetSelected(SelectionEvent arg0) {
TextAlignmentType oldValue;
if (valueType == Value.ValueType.HEADER_ALIGNMENT) {
oldValue = label.getHeaderAlignmentType();
} else if (valueType == Value.ValueType.TEXT_ALIGNMENT) {
oldValue = label.getTextAlignmentType();
} else {
oldValue = TextAlignmentType.LEFT;
}
if (((Button) arg0.getSource()).getSelection()) {
if (textAlignmentType != oldValue) {
editProperty(new Value(valueType, oldValue),
new Value(valueType, textAlignmentType));
}
if (OSFamily.isLinux()) {
// preventing focus frame around the empty button text
textfield.setFocus();
}
}
}
}
/**
* Selection listener for selecting the transparency.
*
* @author Marc Stammerjohann
*/
private class AplhaSelectionListener implements SelectionListener {
@Override
public void widgetSelected(SelectionEvent arg0) {
int oldValue = label.getAlphaDisplay();
int newValue = bgAlphaScale.getSelection();
if (newValue != oldValue) {
if (editTransparencyCommand == null) {
editTransparencyCommand =
editProperty(new Value(Value.ValueType.TRANSPARENCY, oldValue), new Value(Value.ValueType.TRANSPARENCY,
newValue));
} else {
editTransparencyCommand.setNewValue(new Value(Value.ValueType.TRANSPARENCY, newValue));
}
}
}
@Override
public void widgetDefaultSelected(SelectionEvent arg0) {
widgetSelected(arg0);
}
}
/**
* Listener for the alpha value text field.
*
* @author Sascha Zur
*/
private class AlphaValueListener implements ModifyListener {
@Override
public void modifyText(ModifyEvent arg0) {
String text = ((Text) arg0.getSource()).getText();
try {
int value = Integer.parseInt(text);
if (value > MAX_100) {
((Text) arg0.getSource()).setText("" + MAX_100);
} else if (value < 0) {
((Text) arg0.getSource()).setText("0");
} else {
bgAlphaScale.setSelection(((int) (SCALE_TO_PERCENT_FACTOR * value)));
}
} catch (NumberFormatException e) {
text = ""; // Should never happen
}
}
}
/**
* Mouse listener for selecting the color.
*
* @author Marc Stammerjohann
*/
private class ColorMouseListener implements MouseListener {
private Value.ValueType type;
ColorMouseListener(final Value.ValueType type) {
this.type = type;
}
@Override
public void mouseUp(MouseEvent event) { // Create own shell to place the color selector
// where desired.
int[] oldValue = null;
if (type.equals(Value.ValueType.COLOR_BACKGROUND)) {
oldValue = label.getColorBackground();
} else if (type.equals(Value.ValueType.COLOR_TEXT)) {
oldValue = label.getColorText();
} else if (type.equals(Value.ValueType.COLOR_HEADER)) {
oldValue = label.getColorHeader();
} else {
oldValue = new int[] { 0, 0, 0 };
}
int displayWidth = event.display.getBounds().width;
int displayHeight = event.display.getBounds().height;
Shell colorSelectorShell = new Shell(event.display);
colorSelectorShell.setLocation(displayWidth / 2 - COLORSELECTOROFFSET_X, displayHeight / 2 - COLORSELECTOROFFSET_Y);
ColorSelector cs = new ColorSelector(colorSelectorShell);
cs.setColorValue(new RGB(oldValue[0], oldValue[1], oldValue[2]));
cs.open();
int[] newValue = new int[] { cs.getColorValue().red, cs.getColorValue().green, cs.getColorValue().blue };
if (!Arrays.equals(newValue, oldValue)) {
editProperty(new Value(type, oldValue), new Value(type, newValue));
}
colorSelectorShell.dispose();
}
@Override
public void mouseDoubleClick(MouseEvent arg0) {}
@Override
public void mouseDown(MouseEvent arg0) {}
}
/**
* Key listener for the text field.
*
* @author Marc Stammerjohann
*/
private class TextKeyListener implements KeyListener {
@Override
public void keyPressed(KeyEvent event) {
if (event.stateMask == SWT.CTRL && event.keyCode == 'a') {
textfield.setSelection(0);
headerTextField.setSelection(0);
Object src = event.getSource();
if (src.equals(textfield)) {
textfield.selectAll();
} else if (src.equals(headerTextField)) {
headerTextField.selectAll();
}
}
}
@Override
public void keyReleased(KeyEvent arg0) {}
}
@Override
public void execute(WorkflowLabelCommand command) {
command.setCommandStack(getCommandStack());
command.setWorkflowLabel(label);
command.initialize();
if (command.canExecute()) {
getCommandStack().execute(new LabelCommandWrapper(command));
}
}
/**
* {@link WorkflowLabelCommand} to change the value of a property through editing.
*
* @author Marc Stammerjohann
*/
protected final class EditValueCommand extends AbstractWorkflowLabelCommand {
private final Value oldValue;
private Value newValue;
private EditValueCommand(final Value oldValue, Value newValue) {
this.oldValue = oldValue;
this.newValue = newValue;
}
public Value getOldValue() {
return oldValue;
}
public Value getNewValue() {
return newValue;
}
public void setNewValue(final Value newValue) {
this.newValue = newValue;
execute2();
}
@Override
protected void execute2() {
switch (newValue.getType()) {
case HEADER_TEXT:
label.setHeaderText(newValue.getTextValue());
break;
case TEXT:
label.setText(newValue.getTextValue());
break;
case COLOR_HEADER:
label.setColorHeader(newValue.getColorValues());
break;
case COLOR_TEXT:
label.setColorText(newValue.getColorValues());
break;
case COLOR_BACKGROUND:
label.setColorBackground(newValue.getColorValues());
break;
case TRANSPARENCY:
label.setAlpha(newValue.getTransparencyValue());
break;
case LABEL_POSITION:
label.setLabelPosition(newValue.getLabelPosition());
break;
case TEXT_ALIGNMENT:
label.setTextAlignmentType(newValue.getTextAlignmentType());
break;
case HEADER_ALIGNMENT:
label.setHeaderAlignmentType(newValue.getTextAlignmentType());
case BORDER:
label.setHasBorder(newValue.getHasBorder());
break;
case HEADER_SIZE:
label.setHeaderTextSize(newValue.getTextSize());
break;
case TEXT_SIZE:
label.setTextSize(newValue.getTextSize());
break;
default:
break;
}
label.firePropertChangeEvent();
label.firePropertyChange(WorkflowLabel.COMMAND_CHANGE, newValue);
}
@Override
protected void undo2() {
switch (oldValue.getType()) {
case HEADER_TEXT:
label.setHeaderText(oldValue.getTextValue());
break;
case TEXT:
label.setText(oldValue.getTextValue());
break;
case COLOR_HEADER:
label.setColorHeader(oldValue.getColorValues());
break;
case COLOR_TEXT:
label.setColorText(oldValue.getColorValues());
break;
case COLOR_BACKGROUND:
label.setColorBackground(oldValue.getColorValues());
break;
case TRANSPARENCY:
label.setAlpha(oldValue.getTransparencyValue());
break;
case LABEL_POSITION:
label.setLabelPosition(oldValue.getLabelPosition());
break;
case TEXT_ALIGNMENT:
label.setTextAlignmentType(oldValue.getTextAlignmentType());
break;
case HEADER_ALIGNMENT:
label.setHeaderAlignmentType(oldValue.getTextAlignmentType());
break;
case BORDER:
label.setHasBorder(oldValue.getHasBorder());
break;
case HEADER_SIZE:
label.setHeaderTextSize(oldValue.getTextSize());
break;
case TEXT_SIZE:
label.setTextSize(oldValue.getTextSize());
break;
default:
break;
}
label.firePropertChangeEvent();
label.firePropertyChange(WorkflowLabel.COMMAND_CHANGE, oldValue);
}
}
/**
* A wrapper class to wrap different data types to be used within the {@link EditValueCommand}.
*
* @author Marc Stammerjohann
* @author Jascha Riedel
*/
private static class Value {
private ValueType type;
private String textValue;
private int[] colorValues;
private int transparencyValue;
private LabelPosition labelPosition;
private TextAlignmentType textAlignmentType;
private boolean hasBorder;
private int textSize;
Value(final ValueType type, final String value) {
this.type = type;
if (type == ValueType.TEXT
|| type == ValueType.HEADER_TEXT) {
this.textValue = value;
}
}
Value(final ValueType type, final int[] colorValues) {
this.type = type;
if (type == ValueType.COLOR_BACKGROUND
|| type == ValueType.COLOR_TEXT
|| type == ValueType.COLOR_HEADER) {
this.colorValues = colorValues;
}
}
Value(final ValueType type, final int value) {
this.type = type;
if (type == ValueType.TEXT_SIZE || type == ValueType.HEADER_SIZE) {
this.textSize = value;
} else if (type == ValueType.TRANSPARENCY) {
this.transparencyValue = value;
}
}
Value(final ValueType type, LabelPosition labelPosition) {
this.type = ValueType.LABEL_POSITION;
this.labelPosition = labelPosition;
}
Value(final ValueType type, TextAlignmentType textAlignmentType) {
this.type = type;
this.textAlignmentType = textAlignmentType;
}
Value(final ValueType type, boolean border) {
this.type = type;
if (type == ValueType.BORDER) {
this.hasBorder = border;
}
}
public int[] getColorValues() {
return colorValues;
}
public String getTextValue() {
return textValue;
}
public int getTransparencyValue() {
return transparencyValue;
}
public LabelPosition getLabelPosition() {
return labelPosition;
}
public TextAlignmentType getTextAlignmentType() {
return textAlignmentType;
}
public boolean getHasBorder() {
return hasBorder;
}
public int getTextSize() {
return textSize;
}
public ValueType getType() {
return type;
}
/**
* Contains all editable properties.
*
* @author Marc Stammerjohann
*/
private enum ValueType {
HEADER_TEXT,
TEXT,
COLOR_HEADER,
COLOR_TEXT,
COLOR_BACKGROUND,
TRANSPARENCY,
LABEL_POSITION,
HEADER_ALIGNMENT,
TEXT_ALIGNMENT,
BORDER,
HEADER_SIZE,
TEXT_SIZE;
}
}
/**
* A wrapper class to wrap {@link WorkflowLabelCommand}s in GEF {@link Command}s.
*
* @author Marc Stammerjohann
*/
private static final class LabelCommandWrapper extends WorkflowPropertySection.CommandWrapper {
private WorkflowLabelCommand command;
LabelCommandWrapper(WorkflowLabelCommand command) {
super(command);
this.command = command;
}
}
/**
* Adapter to listen to events in the backing model and translate it to events in the {@link Synchronizer}.
*
* @author Christian Weiss
* @author Marc Stammerjohann
*/
private final class SynchronizerAdapter implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent event) {
final String propertyNameValue = event.getPropertyName();
if (propertyNameValue.equals(WorkflowLabel.COMMAND_CHANGE)) {
synchronizer.handlePropertyChange((Value) event.getNewValue());
}
}
}
/**
* Listener class responsible for keeping the GUI in sync with the model.
*
* <p>
* The <code>Synchronizer</code> gets registered at the model to listen to change events (properties & channels) and executes
* appropriate actions to reflect those changes in the GUI.
* </p>
*
* <p>
* The integration of a <code>Synchronizer</code> is as follows:
* <ul>
* <li>A {@link SynchronizerAdapter} gets registered to the backing model (a {@link WorkflowLabel}. This adapter filters events and
* converts the non-filtered to invocations of the {@link Synchronizer} instance created via
* {@link WorkflowLabelPropertySection#createSynchronizer()}.</li>
* <li>The {@link Synchronizer} receives those filtered events via its custom interface and reacts through updating the GUI
* appropriately. The default implementation {@link DefaultSynchronizer} forwards updates to the {@link Updater} instance created via
* {@link WorkflowLabelPropertySection#createUpdater()}.</li>
* </ul>
* </p>
*
* @author Christian Weiss
* @author Marc Stammerjohann
*/
public interface Synchronizer {
/**
* React on the change of a property.
*
* @param newValue the new value of the property
*/
void handlePropertyChange(final Value newValue);
}
/**
* Default implementation of a {@link Synchronizer}, forwarding all updates to the {@link Updater}.
*
* <p>
* It is adviced to derive from this class and call the super class implementation as the very first thing in overwritten methods.
* </p>
*
* @author Christian Weiss
* @author Marc Stammerjohann
*/
protected class DefaultSynchronizer implements Synchronizer {
@Override
public void handlePropertyChange(Value newValue) {
Control control = null;
switch (newValue.getType()) {
case HEADER_TEXT:
control = headerTextField;
break;
case TEXT:
control = textfield;
break;
case COLOR_HEADER:
control = headerColorPreviewLabel;
break;
case COLOR_TEXT:
control = textColorPreviewLabel;
break;
case COLOR_BACKGROUND:
control = bgColorPreviewLabel;
break;
case TRANSPARENCY:
getUpdater().updateControl(bgAlphaValueText, newValue);
control = bgAlphaScale;
break;
case BORDER:
control = bgBorderButton;
break;
case HEADER_SIZE:
control = headerSizeSpinner;
break;
case TEXT_SIZE:
control = textSizeSpinner;
break;
default:
break;
}
getUpdater().updateControl(control, newValue);
}
}
/**
* Interface for handlers updating the UI.
*
* @author Christian Weiss
* @author Marc Stammerjohann
*/
protected interface Updater {
/**
* Updates the gui elements.
*
* @param newValue the value to display
*/
void updateControl(final Control control, final Value newValue);
}
/**
* Default {@link Updater} implementation of the handler to update the UI.
*
* @author Christian Weiss
* @author Marc Stammerjohann
*/
protected class DefaultUpdater implements Updater {
@Override
public void updateControl(Control control, Value newValue) {
if (control != null && control.isDisposed()) {
return;
}
if (newValue != null) {
switch (newValue.getType()) {
case HEADER_TEXT:
if (control instanceof StyledText) {
final StyledText styledTextControl = (StyledText) control;
styledTextControl.setText(newValue.getTextValue());
styledTextControl.setSelection(newValue.getTextValue().length());
}
break;
case TEXT:
if (control instanceof StyledText) {
final StyledText sytledTextControl = (StyledText) control;
int offset = sytledTextControl.getCaretOffset();
int scrollbarSel = sytledTextControl.getTopIndex();
sytledTextControl.setText(newValue.getTextValue());
if (offset > 0 && offset < newValue.getTextValue().length() - 1) {
sytledTextControl.setSelection(offset);
sytledTextControl.setTopIndex(scrollbarSel);
} else {
sytledTextControl.setSelection(newValue.getTextValue().length());
}
}
break;
case COLOR_HEADER:
refreshColorLabels(control, newValue);
break;
case COLOR_TEXT:
refreshColorLabels(control, newValue);
break;
case COLOR_BACKGROUND:
refreshColorLabels(control, newValue);
break;
case TRANSPARENCY:
if (control instanceof Scale) {
Scale scaleControl = (Scale) control;
scaleControl.setSelection(newValue.getTransparencyValue());
} else if (control instanceof Text) {
Text textControl = (Text) control;
textControl.setText("" + ((int) Math.ceil((newValue.getTransparencyValue() / SCALE_TO_PERCENT_FACTOR))));
}
break;
case BORDER:
if (control instanceof Button) {
Button buttonControl = (Button) control;
buttonControl.setSelection(newValue.getHasBorder());
}
break;
case HEADER_SIZE:
if (control instanceof Spinner) {
Spinner spinner = (Spinner) control;
spinner.setSelection(newValue.getTextSize());
}
break;
case TEXT_SIZE:
if (control instanceof Spinner) {
Spinner spinner = (Spinner) control;
spinner.setSelection(newValue.getTextSize());
}
break;
case LABEL_POSITION:
if (!labelPositionButtons[0].isDisposed()) {
updateLabelPositionSelection(newValue.getLabelPosition());
}
break;
case HEADER_ALIGNMENT:
if (!headerAlignmentButtons[0].isDisposed()) {
updateAlignmentButtonsSelection(headerAlignmentButtons, newValue.getTextAlignmentType());
}
break;
case TEXT_ALIGNMENT:
if (!textAlignmentButtons[0].isDisposed()) {
updateAlignmentButtonsSelection(textAlignmentButtons, newValue.getTextAlignmentType());
}
break;
default:
break;
}
}
}
private void refreshColorLabels(Control control, Value newValue) {
if (control instanceof Label) {
final Label labelControl = (Label) control;
// FIXME: resource leak: The color object is never disposed!
labelControl.setBackground(new Color(null, newValue.getColorValues()[0], newValue.getColorValues()[1],
newValue.getColorValues()[2]));
}
}
}
}