/* * Copyright (c) 2006 Stiftung Deutsches Elektronen-Synchroton, * Member of the Helmholtz Association, (DESY), HAMBURG, GERMANY. * * THIS SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "../AS IS" BASIS. * WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR PARTICULAR PURPOSE AND * NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * THE USE OR OTHER DEALINGS IN THE SOFTWARE. SHOULD THE SOFTWARE PROVE DEFECTIVE * IN ANY RESPECT, THE USER ASSUMES THE COST OF ANY NECESSARY SERVICING, REPAIR OR * CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. * NO USE OF ANY SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. * DESY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, * OR MODIFICATIONS. * THE FULL LICENSE SPECIFYING FOR THE SOFTWARE THE REDISTRIBUTION, MODIFICATION, * USAGE AND OTHER RIGHTS AND OBLIGATIONS IS INCLUDED WITH THE DISTRIBUTION OF THIS * PROJECT IN THE FILE LICENSE.HTML. IF THE LICENSE IS NOT INCLUDED YOU MAY FIND A COPY * AT HTTP://WWW.DESY.DE/LEGAL/LICENSE.HTM */ package org.csstudio.sds.components.ui.internal.editparts; import java.util.List; import org.csstudio.sds.components.model.ActionButtonModel; import org.csstudio.sds.components.ui.internal.figures.RefreshableActionButtonFigure; import org.csstudio.sds.model.AbstractWidgetModel; import org.csstudio.sds.model.properties.actions.AbstractWidgetActionModel; import org.csstudio.sds.ui.editparts.ExecutionMode; import org.csstudio.sds.ui.editparts.IWidgetPropertyChangeHandler; import org.csstudio.sds.ui.widgetactionhandler.WidgetActionHandlerService; import org.csstudio.ui.util.CustomMediaFactory; import org.eclipse.draw2d.ButtonModel; import org.eclipse.draw2d.ChangeEvent; import org.eclipse.draw2d.ChangeListener; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.gef.Request; import org.eclipse.gef.RequestConstants; import org.eclipse.jface.viewers.CellEditor; import org.eclipse.jface.viewers.TextCellEditor; import org.eclipse.swt.SWT; import org.eclipse.swt.events.KeyAdapter; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Text; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * EditPart controller for the ActioButton widget. The controller mediates * between {@link ActionButtonModel} and {@link RefreshableActionButtonFigure}. * * @author Sven Wende * */ public final class ActionButtonEditPart extends AbstractTextTypeWidgetEditPart { private static final Logger LOG = LoggerFactory.getLogger(ActionButtonEditPart.class); /** * The actual figure will be surrounded with a small frame that can be used * to drag the figure around (even if the cell editor is activated). */ private static final int FRAME_WIDTH = 1; /** * The input field will be slightly brighter than the actual figure so it * can be easily recognized. */ private static final int INPUT_FIELD_BRIGHTNESS = 10; /** * {@inheritDoc} */ @Override protected IFigure doCreateFigure() { final ActionButtonModel model = (ActionButtonModel) getWidgetModel(); final RefreshableActionButtonFigure buttonFigure = new RefreshableActionButtonFigure(); buttonFigure.setTextValue(determineLabel(null)); buttonFigure.setFont(getModelFont(ActionButtonModel.PROP_FONT)); buttonFigure.setTextAlignment(model.getTextAlignment()); buttonFigure.setEnabled(getExecutionMode().equals(ExecutionMode.RUN_MODE) && model.isAccesible()); buttonFigure.setStyle(model.isToggleButton()); buttonFigure.setSelected(model.isPressed()); return buttonFigure; } /** * Returns the Figure of this EditPart. * * @return RefreshableActionButtonFigure The RefreshableActionButtonFigure * of this EditPart */ protected RefreshableActionButtonFigure getCastedFigure() { return (RefreshableActionButtonFigure) getFigure(); } /** * Returns the casted model. This is just for convenience. * * @return the casted {@link ActionButtonModel} */ @Override protected ActionButtonModel getCastedModel() { return (ActionButtonModel) getModel(); } /** * {@inheritDoc} */ @Override public void performRequest(final Request req) { final Object type = req.getType(); // entering a value is only allowed in run mode and when the widget is // enabled if (type != null && (type.equals(RequestConstants.REQ_OPEN) || type .equals(RequestConstants.REQ_DIRECT_EDIT))) { if (getExecutionMode() == ExecutionMode.RUN_MODE && getCastedModel().isAccesible()) { super.performRequest(req); } else if (getExecutionMode() == ExecutionMode.EDIT_MODE) { performEditTextValue(); } } } /** * Configures a listener for performing a {@link AbstractWidgetActionModel}. * * @param figure * The figure of the widget */ private void configureButtonListener(final RefreshableActionButtonFigure buttonFigure) { buttonFigure.addChangeListener(new ChangeListener() { @Override public void handleStateChanged(final ChangeEvent event) { final String propertyName = event.getPropertyName(); LOG.debug("ChangeEvent received, event.property=" + propertyName); // If the display is not in run mode or the button is not armed, // don't do anything. if (getExecutionMode() != ExecutionMode.RUN_MODE || !buttonFigure.getModel().isArmed()) { return; } // If the button is a toggle button, the property that changes // when the toggle state changes is SELECTED_PROPERTY. For a // standard button, the PRESSED_PROPERTY is used, which reflects // mouse down/up events. The action index is then selected based // on whether the button is selected/deselected, or // pressed/released, respectively. // // Note: we must use the same change listener because whether a // button is a toggle button can change dynamically. int actionIndex = -1; final ActionButtonModel widget = (ActionButtonModel) getWidgetModel(); if (widget.isToggleButton()) { if (ButtonModel.SELECTED_PROPERTY.equals(propertyName)) { widget.setPropertyValue(ActionButtonModel.PROP_TOGGLE_STATE, buttonFigure.isSelected()); if (buttonFigure.isSelected()) { actionIndex = widget.getChoosenPressedActionIndex(); LOG.debug("toggle=true, selected=true => using pressed action index: " + actionIndex); } else { actionIndex = widget.getChoosenReleasedActionIndex(); LOG.debug("toggle=true, selected=false => using released action index: " + actionIndex); } } } else { if (ButtonModel.PRESSED_PROPERTY.equals(propertyName)) { if (buttonFigure.getModel().isPressed()) { actionIndex = widget.getChoosenPressedActionIndex(); LOG.debug("toggle=false, pressed=true => using pressed action index: " + actionIndex); } else { actionIndex = widget.getChoosenReleasedActionIndex(); LOG.debug("toggle=false, pressed=false => using released action index: " + actionIndex); } } } final List<AbstractWidgetActionModel> actions = widget.getActionData().getWidgetActions(); // If an action should be used and there is only a single // action, use that action. if (actionIndex >= 0 && actions.size() == 1) { actionIndex = 0; } if (actionIndex >= 0 && actionIndex < actions.size()) { final AbstractWidgetActionModel action = actions.get(actionIndex); // The actual action can now be run asynchronously, because // all required data has been retrieved from the model. Display.getCurrent().asyncExec(new Runnable() { @Override public void run() { LOG.debug("Performing widget action: " + action); WidgetActionHandlerService.getInstance().performAction(widget, action); } }); } } }); } /** * {@inheritDoc} */ @Override protected void registerPropertyChangeHandlers() { super.registerPropertyChangeHandlers(); // final RefreshableActionButtonFigure buttonFigure = getCastedFigure(); this.configureButtonListener(buttonFigure); // label final IWidgetPropertyChangeHandler labelHandler = new IWidgetPropertyChangeHandler() { @Override public boolean handleChange(final Object oldValue, final Object newValue, final IFigure refreshableFigure) { final RefreshableActionButtonFigure rabFigure = getCastedFigure(); rabFigure.setTextValue(determineLabel(null)); return true; } }; setPropertyChangeHandler(ActionButtonModel.PROP_LABEL, labelHandler); // font setPropertyChangeHandler(ActionButtonModel.PROP_FONT, new FontChangeHandler<RefreshableActionButtonFigure>() { @Override protected void doHandle(final RefreshableActionButtonFigure rabFigure, final Font font) { rabFigure.setFont(font); } }); // text alignment final IWidgetPropertyChangeHandler alignmentHandler = new IWidgetPropertyChangeHandler() { @Override public boolean handleChange(final Object oldValue, final Object newValue, final IFigure refreshableFigure) { final RefreshableActionButtonFigure rabFigure = (RefreshableActionButtonFigure) refreshableFigure; rabFigure.setTextAlignment((Integer) newValue); return true; } }; setPropertyChangeHandler(ActionButtonModel.PROP_TEXT_ALIGNMENT, alignmentHandler); // button style final IWidgetPropertyChangeHandler buttonStyleHandler = new IWidgetPropertyChangeHandler() { @Override public boolean handleChange(final Object oldValue, final Object newValue, final IFigure refreshableFigure) { final RefreshableActionButtonFigure rabFigure = (RefreshableActionButtonFigure) refreshableFigure; rabFigure.setStyle((Boolean) newValue); rabFigure.setSelected((Boolean) newValue && getCastedModel().isPressed()); return true; } }; setPropertyChangeHandler(ActionButtonModel.PROP_TOGGLE_BUTTON, buttonStyleHandler); // button toggle state final IWidgetPropertyChangeHandler toggleButtonPressedHandler = new IWidgetPropertyChangeHandler() { @Override public boolean handleChange(final Object oldValue, final Object newValue, final IFigure refreshableFigure) { final RefreshableActionButtonFigure rabFigure = (RefreshableActionButtonFigure) refreshableFigure; rabFigure.setSelected(getCastedModel().isToggleButton() && (Boolean) newValue); return true; } }; setPropertyChangeHandler(ActionButtonModel.PROP_TOGGLE_STATE, toggleButtonPressedHandler); } /** * {@inheritDoc} */ @Override protected boolean forceDisabledInEditMode() { return true; } private void performEditTextValue() { final CellEditor cellEditor = createCellEditor2(); locateCellEditor(cellEditor); cellEditor.activate(); cellEditor.setFocus(); } private CellEditor createCellEditor2() { final CellEditor result = new TextCellEditor((Composite) getViewer().getControl()); // init cell editor... String currentValue = "N/A"; //$NON-NLS-1$ currentValue = getWidgetModel().getStringProperty(ActionButtonModel.PROP_LABEL); result.setValue(currentValue); final Text text = (Text) result.getControl(); // input text text.addKeyListener(new KeyAdapter() { @Override public void keyPressed(final KeyEvent e) { if (e.keyCode == SWT.CR || e.keyCode == SWT.KEYPAD_CR) { getWidgetModel().setPropertyValue(ActionButtonModel.PROP_LABEL, text.getText()); result.deactivate(); result.dispose(); } else if (e.keyCode == SWT.ESC) { result.deactivate(); result.dispose(); } } }); text.setForeground(getModelColor(AbstractWidgetModel.PROP_COLOR_FOREGROUND)); text.setFont(getModelFont(ActionButtonModel.PROP_FONT)); // calculate background color final RGB backgroundRgb = getModelColor(AbstractWidgetModel.PROP_COLOR_BACKGROUND).getRGB(); final int red = Math.min(backgroundRgb.red + INPUT_FIELD_BRIGHTNESS, 255); final int green = Math.min(backgroundRgb.green + INPUT_FIELD_BRIGHTNESS, 255); final int blue = Math.min(backgroundRgb.blue + INPUT_FIELD_BRIGHTNESS, 255); final Color backgroundColor = CustomMediaFactory.getInstance() .getColor(new RGB(red, green, blue)); text.setBackground(backgroundColor); text.selectAll(); return result; } /** * Locate the given cell editor . * * @param cellEditor * A cell editor. */ private void locateCellEditor(final CellEditor cellEditor) { final Rectangle rect = ActionButtonEditPart.this.figure.getBounds().getCopy(); rect.x = rect.x + FRAME_WIDTH; rect.y = rect.y + FRAME_WIDTH; rect.height = rect.height - FRAME_WIDTH * 1; rect.width = rect.width - FRAME_WIDTH * 1; getFigure().translateToAbsolute(rect); cellEditor.getControl().setBounds(rect.x, rect.y, rect.width, rect.height); cellEditor.getControl().setLayoutData(new GridData(SWT.CENTER)); cellEditor.getControl().setVisible(true); } }