| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.hop.ui.core.widget; |
| |
| import static org.apache.hop.core.Condition.Function.NOT_NULL; |
| import static org.apache.hop.core.Condition.Function.NULL; |
| import static org.apache.hop.core.Condition.Operator.AND; |
| import static org.apache.hop.core.Condition.Operator.NONE; |
| import static org.apache.hop.core.Condition.Operator.lookupType; |
| |
| import java.util.ArrayList; |
| import org.apache.hop.core.Condition; |
| import org.apache.hop.core.Const; |
| import org.apache.hop.core.exception.HopValueException; |
| import org.apache.hop.core.exception.HopXmlException; |
| import org.apache.hop.core.row.IRowMeta; |
| import org.apache.hop.core.row.IValueMeta; |
| import org.apache.hop.core.row.ValueMetaAndData; |
| import org.apache.hop.core.row.value.ValueMetaFactory; |
| import org.apache.hop.core.row.value.ValueMetaString; |
| import org.apache.hop.core.xml.XmlHandler; |
| import org.apache.hop.i18n.BaseMessages; |
| import org.apache.hop.ui.core.dialog.EnterSelectionDialog; |
| import org.apache.hop.ui.core.dialog.EnterValueDialog; |
| import org.apache.hop.ui.core.dialog.ErrorDialog; |
| import org.apache.hop.ui.core.gui.GuiResource; |
| import org.apache.hop.ui.util.EnvironmentUtils; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.events.ModifyEvent; |
| import org.eclipse.swt.events.ModifyListener; |
| import org.eclipse.swt.events.MouseEvent; |
| import org.eclipse.swt.events.MouseMoveListener; |
| import org.eclipse.swt.events.SelectionAdapter; |
| import org.eclipse.swt.events.SelectionEvent; |
| import org.eclipse.swt.graphics.Color; |
| import org.eclipse.swt.graphics.Font; |
| import org.eclipse.swt.graphics.GC; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.swt.graphics.Point; |
| import org.eclipse.swt.graphics.Rectangle; |
| import org.eclipse.swt.widgets.Canvas; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Event; |
| import org.eclipse.swt.widgets.Menu; |
| import org.eclipse.swt.widgets.MenuItem; |
| import org.eclipse.swt.widgets.ScrollBar; |
| import org.eclipse.swt.widgets.Shell; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Node; |
| |
| /** Widget that allows you to edit a Condition in a graphical way. */ |
| public class ConditionEditor extends Canvas implements MouseMoveListener { |
| private static final Class<?> PKG = ConditionEditor.class; // For Translator |
| |
| private static final int X_PADDING = 18; |
| private static final String STRING_NOT = BaseMessages.getString(PKG, "ConditionEditor.StringNot"); |
| private static final String STRING_UP = BaseMessages.getString(PKG, "ConditionEditor.StringUp"); |
| |
| private static final int AREA_NONE = 0; |
| private static final int AREA_BACKGROUND = 1; |
| private static final int AREA_NOT = 2; |
| private static final int AREA_CONDITION = 3; |
| private static final int AREA_SUBCONDITION = 4; |
| private static final int AREA_OPERATOR = 5; |
| private static final int AREA_UP = 6; |
| private static final int AREA_LEFT = 7; |
| private static final int AREA_FUNCTION = 8; |
| private static final int AREA_RIGHT_VALUE = 9; |
| private static final int AREA_RIGHT_EXACT = 10; |
| private static final int AREA_ICON_ADD = 11; |
| |
| protected Canvas widget; |
| private Shell shell; |
| private Display display; |
| private Condition activeCondition; |
| private Color bg; |
| private Color white; |
| private Color black; |
| private Color red; |
| private Color green; |
| private Color blue; |
| private Color gray; |
| private Font fixed; |
| |
| private Image imageAdd; |
| |
| private Rectangle sizeNot; |
| private Rectangle sizeWidget; |
| private Rectangle sizeAndNot; |
| private Rectangle sizeUp; |
| private Rectangle sizeLeft; |
| private Rectangle sizeFn; |
| private Rectangle sizeRightval; |
| private Rectangle sizeRightex; |
| private Rectangle[] sizeCond; |
| private Rectangle[] sizeOper; |
| private Rectangle sizeAdd; |
| private Rectangle maxdrawn; |
| |
| private int hoverCondition; |
| private int hoverOperator; |
| private boolean hoverNot; |
| private boolean hoverUp; |
| private boolean hoverLeft; |
| private boolean hoverFn; |
| private boolean hoverRightval; |
| private boolean hoverRightex; |
| |
| private int previousArea; |
| private int previousAreaNr; |
| |
| private ArrayList<Condition> parents; |
| private IRowMeta fields; |
| |
| private int maxFieldLength; |
| |
| private ScrollBar sbVertical; |
| private ScrollBar sbHorizontal; |
| private int offsetx; |
| private int offsety; |
| |
| private ArrayList<ModifyListener> modListeners; |
| |
| private String messageString; |
| private Menu mPop; |
| |
| public ConditionEditor(Composite composite, int arg1, Condition co, IRowMeta inputFields) { |
| super(composite, arg1 | SWT.NO_BACKGROUND | SWT.V_SCROLL | SWT.H_SCROLL); |
| |
| widget = this; |
| |
| this.activeCondition = co; |
| this.fields = inputFields; |
| |
| imageAdd = GuiResource.getInstance().getImage("ui/images/add.svg"); |
| |
| modListeners = new ArrayList<>(); |
| |
| sbVertical = getVerticalBar(); |
| sbHorizontal = getHorizontalBar(); |
| offsetx = 0; |
| offsety = 0; |
| maxdrawn = null; |
| |
| sizeNot = null; |
| sizeWidget = null; |
| sizeCond = null; |
| |
| previousArea = -1; |
| previousAreaNr = -1; |
| |
| parents = new ArrayList<>(); // Remember parent in drill-down... |
| |
| hoverCondition = -1; |
| hoverOperator = -1; |
| hoverNot = false; |
| hoverUp = false; |
| hoverLeft = false; |
| hoverFn = false; |
| hoverRightval = false; |
| hoverRightex = false; |
| |
| /* |
| * Determine the maximum field length... |
| */ |
| getMaxFieldLength(); |
| |
| shell = composite.getShell(); |
| display = shell.getDisplay(); |
| |
| bg = GuiResource.getInstance().getColorBackground(); |
| fixed = GuiResource.getInstance().getFontFixed(); |
| |
| white = GuiResource.getInstance().getColorWhite(); |
| black = GuiResource.getInstance().getColorBlack(); |
| red = GuiResource.getInstance().getColorRed(); |
| green = GuiResource.getInstance().getColorGreen(); |
| blue = GuiResource.getInstance().getColorBlue(); |
| gray = GuiResource.getInstance().getColorDarkGray(); |
| |
| widget.addPaintListener( |
| pe -> { |
| Rectangle r = widget.getBounds(); |
| if (r.width > 0 && r.height > 0) { |
| repaint(pe.gc, r.width, r.height); |
| } |
| }); |
| |
| if (!EnvironmentUtils.getInstance().isWeb()) { |
| widget.addMouseMoveListener(this); |
| } |
| |
| widget.addListener( |
| SWT.MouseDown, |
| e -> { |
| try { |
| Point screen = new Point(e.x, e.y); |
| int area = getAreaCode(screen); |
| |
| if (e.button == 1) { // Left click on widget... |
| |
| switch (area) { |
| case AREA_NOT: |
| activeCondition.negate(); |
| setModified(); |
| widget.redraw(); |
| break; |
| case AREA_OPERATOR: |
| int operator = getNrOperator(screen); |
| EnterSelectionDialog esd = |
| new EnterSelectionDialog( |
| shell, |
| Condition.getRealOperators(), |
| BaseMessages.getString(PKG, "ConditionEditor.Operator.Label"), |
| BaseMessages.getString(PKG, "ConditionEditor.SelectOperator.Label")); |
| esd.setAvoidQuickSearch(); |
| Condition selcond = activeCondition.getCondition(operator); |
| String def = selcond.getOperatorDesc(); |
| int defnr = esd.getSelectionNr(Const.trim(def)); |
| String selection = esd.open(defnr); |
| if (selection != null) { |
| int opnr = Condition.getOperator(selection); |
| activeCondition.getCondition(operator).setOperator(lookupType(opnr)); |
| setModified(); |
| } |
| widget.redraw(); |
| break; |
| case AREA_SUBCONDITION: |
| int nr = getNrSubcondition(screen); |
| editCondition(nr); |
| setMessageString( |
| BaseMessages.getString( |
| PKG, "ConditionEditor.GoUpOneLevel.Label", "" + getLevel())); |
| redraw(); |
| break; |
| case AREA_UP: |
| // Go to the parent condition... |
| goUp(); |
| break; |
| case AREA_FUNCTION: |
| if (activeCondition.isAtomic()) { |
| esd = |
| new EnterSelectionDialog( |
| shell, |
| Condition.functions, |
| BaseMessages.getString(PKG, "ConditionEditor.Functions.Label"), |
| BaseMessages.getString(PKG, "ConditionEditor.SelectFunction.Label")); |
| esd.setAvoidQuickSearch(); |
| def = activeCondition.getFunctionDesc(); |
| defnr = esd.getSelectionNr(def); |
| selection = esd.open(defnr); |
| if (selection != null) { |
| int fnnr = Condition.getFunction(selection); |
| activeCondition.setFunction(Condition.Function.lookupType(fnnr)); |
| |
| if (activeCondition.getFunction() == NOT_NULL |
| || activeCondition.getFunction() == NULL) { |
| activeCondition.setRightValueName(null); |
| activeCondition.setRightValue(null); |
| } |
| |
| setModified(); |
| } |
| widget.redraw(); |
| } |
| break; |
| case AREA_LEFT: |
| if (activeCondition.isAtomic() && fields != null) { |
| esd = |
| new EnterSelectionDialog( |
| shell, |
| fields.getFieldNamesAndTypes(maxFieldLength), |
| BaseMessages.getString(PKG, "ConditionEditor.Fields"), |
| BaseMessages.getString(PKG, "ConditionEditor.SelectAField")); |
| esd.setAvoidQuickSearch(); |
| def = activeCondition.getLeftValueName(); |
| defnr = esd.getSelectionNr(def); |
| selection = esd.open(defnr); |
| if (selection != null) { |
| IValueMeta v = fields.getValueMeta(esd.getSelectionNr()); |
| activeCondition.setLeftValueName(v.getName()); |
| setModified(); |
| } |
| widget.redraw(); |
| } |
| break; |
| case AREA_RIGHT_VALUE: |
| if (activeCondition.isAtomic() && fields != null) { |
| esd = |
| new EnterSelectionDialog( |
| shell, |
| fields.getFieldNamesAndTypes(maxFieldLength), |
| BaseMessages.getString(PKG, "ConditionEditor.Fields"), |
| BaseMessages.getString(PKG, "ConditionEditor.SelectAField")); |
| esd.setAvoidQuickSearch(); |
| def = activeCondition.getLeftValueName(); |
| defnr = esd.getSelectionNr(def); |
| selection = esd.open(defnr); |
| if (selection != null) { |
| IValueMeta v = fields.getValueMeta(esd.getSelectionNr()); |
| activeCondition.setRightValueName(v.getName()); |
| activeCondition.setRightValue(null); |
| setModified(); |
| } |
| widget.redraw(); |
| } |
| break; |
| case AREA_RIGHT_EXACT: |
| if (activeCondition.isAtomic()) { |
| Condition.CValue v = activeCondition.getRightValue(); |
| if (v == null) { |
| IValueMeta leftval = |
| fields != null |
| ? fields.searchValueMeta(activeCondition.getLeftValueName()) |
| : null; |
| if (leftval != null) { |
| try { |
| v = |
| new Condition.CValue( |
| new ValueMetaAndData( |
| ValueMetaFactory.createValueMeta( |
| "constant", leftval.getType()), |
| null)); |
| } catch (Exception exception) { |
| new ErrorDialog( |
| shell, "Error", "Error creating value meta object", exception); |
| } |
| } else { |
| v = |
| new Condition.CValue( |
| new ValueMetaAndData(new ValueMetaString("constant"), null)); |
| } |
| } |
| EnterValueDialog evd = |
| new EnterValueDialog( |
| shell, SWT.NONE, v.createValueMeta(), v.createValueData()); |
| evd.setModalDialog( |
| true); // To keep the condition editor from being closed with a value dialog |
| // still |
| // open. |
| ValueMetaAndData newval = evd.open(); |
| if (newval != null) { |
| activeCondition.setRightValueName(null); |
| activeCondition.setRightValue(new Condition.CValue(newval)); |
| setModified(); |
| } |
| widget.redraw(); |
| } |
| break; |
| case AREA_ICON_ADD: |
| addCondition(); |
| break; |
| |
| default: |
| break; |
| } |
| } |
| } catch (Exception ex) { |
| new ErrorDialog(shell, "Error", "Error editing condition", ex); |
| } |
| }); |
| |
| // |
| // set the pop-up menu |
| // |
| widget.addMenuDetectListener( |
| e -> { |
| Point screen = new Point(e.x, e.y); |
| Point widgetScreen = widget.toDisplay(1, 1); |
| Point wRel = new Point(screen.x - widgetScreen.x, screen.y - widgetScreen.y); |
| int area = getAreaCode(wRel); |
| setMenu(area, wRel); |
| }); |
| |
| sbVertical.addListener( |
| SWT.Selection, |
| e -> { |
| offsety = -sbVertical.getSelection(); |
| widget.redraw(); |
| }); |
| |
| sbHorizontal.addListener( |
| SWT.Selection, |
| e -> { |
| offsetx = -sbHorizontal.getSelection(); |
| widget.redraw(); |
| }); |
| |
| widget.addListener( |
| SWT.Resize, |
| e -> { |
| sizeWidget = widget.getBounds(); |
| setBars(); |
| }); |
| } |
| |
| private void getMaxFieldLength() { |
| maxFieldLength = 5; |
| if (fields != null) { |
| for (int i = 0; i < fields.size(); i++) { |
| IValueMeta value = fields.getValueMeta(i); |
| if (value != null && value.getName() != null) { |
| int len = fields.getValueMeta(i).getName().length(); |
| if (len > maxFieldLength) { |
| maxFieldLength = len; |
| } |
| } |
| } |
| } |
| } |
| |
| public int getLevel() { |
| return parents.size(); |
| } |
| |
| public void goUp() { |
| if (!parents.isEmpty()) { |
| int last = parents.size() - 1; |
| activeCondition = parents.get(last); |
| parents.remove(last); |
| |
| redraw(); |
| } |
| if (getLevel() > 0) { |
| setMessageString( |
| BaseMessages.getString(PKG, "ConditionEditor.GoUpOneLevel.Label", "" + getLevel())); |
| } else { |
| setMessageString(BaseMessages.getString(PKG, "ConditionEditor.EditSubCondition")); |
| } |
| } |
| |
| private void setMenu(int area, Point screen) { |
| final int conditionIndex = getNrSubcondition(screen); |
| if (mPop != null && !mPop.isDisposed()) { |
| mPop.dispose(); |
| } |
| |
| switch (area) { |
| case AREA_NOT: |
| mPop = new Menu(widget); |
| MenuItem miNegate = new MenuItem(mPop, SWT.PUSH); |
| miNegate.setText(BaseMessages.getString(PKG, "ConditionEditor.NegateCondition")); |
| miNegate.addListener( |
| SWT.Selection, |
| e -> { |
| activeCondition.negate(); |
| widget.redraw(); |
| setModified(); |
| }); |
| setMenu(mPop); |
| break; |
| case AREA_BACKGROUND: |
| case AREA_ICON_ADD: |
| mPop = new Menu(widget); |
| MenuItem miAdd = new MenuItem(mPop, SWT.PUSH); |
| miAdd.setText(BaseMessages.getString(PKG, "ConditionEditor.AddCondition.Label")); |
| miAdd.addListener( |
| SWT.Selection, |
| e -> { |
| try { |
| addCondition(); |
| } catch (Exception ex) { |
| new ErrorDialog(shell, "Error", "Error adding condition", ex); |
| } |
| }); |
| setMenu(mPop); |
| break; |
| case AREA_SUBCONDITION: |
| mPop = new Menu(widget); |
| MenuItem miEdit = new MenuItem(mPop, SWT.PUSH); |
| miEdit.setText(BaseMessages.getString(PKG, "ConditionEditor.EditCondition.Label")); |
| miEdit.addListener( |
| SWT.Selection, |
| e -> { |
| editCondition(conditionIndex); |
| setModified(); |
| widget.redraw(); |
| }); |
| MenuItem miDel = new MenuItem(mPop, SWT.PUSH); |
| miDel.setText(BaseMessages.getString(PKG, "ConditionEditor.DeleteCondition.Label")); |
| miDel.addListener( |
| SWT.Selection, |
| e -> { |
| removeCondition(conditionIndex); |
| setModified(); |
| widget.redraw(); |
| }); |
| // Add a sub-condition in the subcondition... (move down) |
| final Condition sub = activeCondition.getCondition(conditionIndex); |
| if (sub.getLeftValueName() != null) { |
| miAdd = new MenuItem(mPop, SWT.PUSH); |
| miAdd.setText(BaseMessages.getString(PKG, "ConditionEditor.AddSubCondition.Label")); |
| miAdd.addListener( |
| SWT.Selection, |
| e -> { |
| try { |
| Condition c = new Condition(); |
| c.setOperator(AND); |
| sub.addCondition(c); |
| setModified(); |
| widget.redraw(); |
| } catch (Exception ex) { |
| new ErrorDialog(shell, "Error", "Error adding sub-condition", ex); |
| } |
| }); |
| } |
| // -------------------------------------------------- |
| new MenuItem(mPop, SWT.SEPARATOR); |
| |
| MenuItem miCopy = new MenuItem(mPop, SWT.PUSH); |
| miCopy.setText(BaseMessages.getString(PKG, "ConditionEditor.CopyToClipboard")); |
| miCopy.addListener( |
| SWT.Selection, |
| e -> { |
| Condition c = activeCondition.getCondition(conditionIndex); |
| try { |
| String xml = c.getXml(); |
| GuiResource.getInstance().toClipboard(xml); |
| widget.redraw(); |
| } catch (Exception ex) { |
| new ErrorDialog(shell, "Error", "Error encoding to XML", ex); |
| } |
| }); |
| MenuItem miPasteBef = new MenuItem(mPop, SWT.PUSH); |
| miPasteBef.setText( |
| BaseMessages.getString(PKG, "ConditionEditor.PasteFromClipboardBeforeCondition")); |
| miPasteBef.addListener( |
| SWT.Selection, |
| e -> { |
| String xml = GuiResource.getInstance().fromClipboard(); |
| try { |
| Document d = XmlHandler.loadXmlString(xml); |
| Node condNode = XmlHandler.getSubNode(d, "condition"); |
| if (condNode != null) { |
| Condition c = new Condition(condNode); |
| activeCondition.addCondition(conditionIndex, c); |
| widget.redraw(); |
| } else { |
| new ErrorDialog( |
| shell, |
| BaseMessages.getString(PKG, "ConditionEditor.Error"), |
| BaseMessages.getString(PKG, "ConditionEditor.NoConditionFoundXML"), |
| new HopXmlException( |
| BaseMessages.getString( |
| PKG, |
| "ConditionEditor.NoConditionFoundXML.Exception", |
| Const.CR + Const.CR + xml))); |
| } |
| } catch (Exception ex) { |
| new ErrorDialog( |
| shell, |
| BaseMessages.getString(PKG, "ConditionEditor.Error"), |
| BaseMessages.getString(PKG, "ConditionEditor.ErrorParsingCondition"), |
| ex); |
| } |
| }); |
| // -------------------------------------------------- |
| new MenuItem(mPop, SWT.SEPARATOR); |
| |
| MenuItem miPasteAft = new MenuItem(mPop, SWT.PUSH); |
| miPasteAft.setText( |
| BaseMessages.getString(PKG, "ConditionEditor.PasteFromClipboardAfterCondition")); |
| miPasteAft.addListener( |
| SWT.Selection, |
| e -> { |
| String xml = GuiResource.getInstance().fromClipboard(); |
| try { |
| Document d = XmlHandler.loadXmlString(xml); |
| Node condNode = XmlHandler.getSubNode(d, "condition"); |
| if (condNode != null) { |
| Condition c = new Condition(condNode); |
| activeCondition.addCondition(conditionIndex + 1, c); |
| widget.redraw(); |
| } else { |
| new ErrorDialog( |
| shell, |
| BaseMessages.getString(PKG, "ConditionEditor.Error"), |
| BaseMessages.getString(PKG, "ConditionEditor.NoConditionFoundXML"), |
| new HopXmlException( |
| BaseMessages.getString( |
| PKG, |
| "ConditionEditor.NoConditionFoundXML.Exception", |
| Const.CR + Const.CR + xml))); |
| } |
| } catch (Exception ex) { |
| new ErrorDialog( |
| shell, |
| BaseMessages.getString(PKG, "ConditionEditor.Error"), |
| BaseMessages.getString(PKG, "ConditionEditor.ErrorParsingCondition"), |
| ex); |
| } |
| }); |
| // -------------------------------------------------- |
| new MenuItem(mPop, SWT.SEPARATOR); |
| MenuItem miMoveSub = new MenuItem(mPop, SWT.PUSH); |
| miMoveSub.setText( |
| BaseMessages.getString(PKG, "ConditionEditor.MoveConditionToSubCondition")); |
| miMoveSub.addListener( |
| SWT.Selection, |
| e -> { |
| try { |
| // Move the condition lower: this means create a subcondition and put the condition |
| // there in the list. |
| // |
| Condition down = activeCondition.getCondition(conditionIndex); |
| Condition c = new Condition(); |
| c.setOperator(down.getOperator()); |
| down.setOperator(NONE); |
| activeCondition.setCondition(conditionIndex, c); |
| c.addCondition(down); |
| |
| widget.redraw(); |
| } catch (Exception ex) { |
| new ErrorDialog(shell, "Error", "Error moving condition", ex); |
| } |
| }); |
| MenuItem miMoveParent = new MenuItem(mPop, SWT.PUSH); |
| miMoveParent.setText( |
| BaseMessages.getString(PKG, "ConditionEditor.MoveConditionToParentCondition")); |
| if (getLevel() == 0) { |
| miMoveParent.setEnabled(false); |
| } |
| miMoveParent.addListener( |
| SWT.Selection, |
| e -> { |
| try { |
| // Move the condition lower: this means delete the condition from the |
| // active_condition. |
| // After that, move it to the parent. |
| Condition up = activeCondition.getCondition(conditionIndex); |
| activeCondition.removeCondition(conditionIndex); |
| Condition parent = parents.get(getLevel() - 1); |
| |
| parent.addCondition(up); |
| |
| // Take a look upward... |
| goUp(); |
| |
| widget.redraw(); |
| } catch (Exception ex) { |
| new ErrorDialog(shell, "Error", "Error removing condition", ex); |
| } |
| }); |
| // -------------------------------------------------- |
| new MenuItem(mPop, SWT.SEPARATOR); |
| MenuItem miMoveDown = new MenuItem(mPop, SWT.PUSH); |
| miMoveDown.setText(BaseMessages.getString(PKG, "ConditionEditor.MoveConditionDown")); |
| if (conditionIndex >= activeCondition.nrConditions() - 1) { |
| miMoveDown.setEnabled(false); |
| } |
| miMoveDown.addListener( |
| SWT.Selection, |
| e -> { |
| try { |
| Condition down = activeCondition.getCondition(conditionIndex); |
| activeCondition.removeCondition(conditionIndex); |
| activeCondition.addCondition(conditionIndex + 1, down); |
| |
| widget.redraw(); |
| } catch (Exception ex) { |
| new ErrorDialog(shell, "Error", "Error moving condition", ex); |
| } |
| }); |
| MenuItem miMoveUp = new MenuItem(mPop, SWT.PUSH); |
| miMoveUp.setText(BaseMessages.getString(PKG, "ConditionEditor.MoveConditionUp")); |
| if (conditionIndex == 0) { |
| miMoveUp.setEnabled(false); |
| } |
| miMoveUp.addListener( |
| SWT.Selection, |
| e -> { |
| try { |
| Condition up = activeCondition.getCondition(conditionIndex); |
| activeCondition.removeCondition(conditionIndex); |
| activeCondition.addCondition(conditionIndex - 1, up); |
| |
| widget.redraw(); |
| } catch (Exception ex) { |
| new ErrorDialog(shell, "Error", "Error moving condition", ex); |
| } |
| }); |
| |
| setMenu(mPop); |
| |
| break; |
| case AREA_OPERATOR: |
| Menu mPop = new Menu(widget); |
| MenuItem miDown = new MenuItem(mPop, SWT.PUSH); |
| miDown.setText(BaseMessages.getString(PKG, "ConditionEditor.MoveDown")); |
| miDown.addSelectionListener( |
| new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| // Move a condition down! |
| // oper_nr = 1 : means move down |
| setModified(); |
| widget.redraw(); |
| } |
| }); |
| setMenu(mPop); |
| break; |
| |
| default: |
| setMenu(null); |
| break; |
| } |
| } |
| |
| public void repaint(GC gc, int width, int height) { |
| // Initialize some information |
| sizeNot = getNotSize(gc); |
| sizeWidget = getWidgetSize(gc); |
| sizeAndNot = getAndNotSize(gc); |
| sizeUp = getUpSize(gc); |
| sizeAdd = getAddSize(gc); |
| sizeLeft = null; |
| sizeFn = null; |
| sizeRightval = null; |
| sizeRightex = null; |
| |
| // Clear the background... |
| gc.setBackground(white); |
| gc.setForeground(black); |
| gc.fillRectangle(0, 0, width, height); |
| |
| // Set the fixed font: |
| gc.setFont(fixed); |
| |
| // Atomic condition? |
| if (activeCondition.isAtomic()) { |
| sizeCond = null; |
| drawNegated(gc, 0, 0, activeCondition); |
| |
| drawAtomic(gc, 0, 0, activeCondition); |
| |
| } else { |
| drawNegated(gc, 0, 0, activeCondition); |
| |
| sizeCond = new Rectangle[activeCondition.nrConditions()]; |
| sizeOper = new Rectangle[activeCondition.nrConditions()]; |
| |
| int basex = 10; |
| int basey = sizeNot.y + 5; |
| |
| for (int i = 0; i < activeCondition.nrConditions(); i++) { |
| Point to = drawCondition(gc, basex, basey, i, activeCondition.getCondition(i)); |
| basey += sizeAndNot.height + to.y + 15; |
| } |
| } |
| |
| gc.drawImage(imageAdd, sizeAdd.x, sizeAdd.y); |
| |
| /* |
| * Draw the up-symbol if needed... |
| */ |
| if (parents.size() > 0) { |
| drawUp(gc); |
| } |
| |
| if (messageString != null) { |
| drawMessage(gc); |
| } |
| |
| /* |
| * Determine the maximum size of the displayed items... Normally, they are all size up already. |
| */ |
| getMaxSize(); |
| |
| /* |
| * Set the scroll bars: show/don't show and set the size |
| */ |
| setBars(); |
| } |
| |
| private Rectangle getNotSize(GC gc) { |
| Point p = gc.textExtent(STRING_NOT); |
| return new Rectangle(0, 0, p.x + 10, p.y + 4); |
| } |
| |
| private Rectangle getWidgetSize(GC gc) { |
| return widget.getBounds(); |
| } |
| |
| private Rectangle getAndNotSize(GC gc) { |
| Point p = gc.textExtent(Condition.operators[Condition.OPERATOR_AND_NOT]); |
| return new Rectangle(0, 0, p.x, p.y); |
| } |
| |
| private Rectangle getUpSize(GC gc) { |
| Point p = gc.textExtent(STRING_UP); |
| return new Rectangle(sizeNot.x + sizeNot.width + 40, sizeNot.y, p.x + 20, sizeNot.height); |
| } |
| |
| private Rectangle getAddSize(GC gc) { |
| Rectangle is = imageAdd.getBounds(); // image size |
| Rectangle cs = getBounds(); // Canvas size |
| |
| return new Rectangle(cs.width - is.width - 5 - X_PADDING, 5, is.width, is.height); |
| } |
| |
| private void drawNegated(GC gc, int x, int y, Condition condition) { |
| Color color = gc.getForeground(); |
| |
| if (hoverNot) { |
| gc.setBackground(gray); |
| } |
| gc.fillRectangle(real2Screen(sizeNot)); |
| gc.drawRectangle(real2Screen(sizeNot)); |
| |
| if (condition.isNegated()) { |
| if (hoverNot) { |
| gc.setForeground(green); |
| } |
| gc.drawText( |
| STRING_NOT, sizeNot.x + 5 + offsetx, sizeNot.y + 2 + offsety, SWT.DRAW_TRANSPARENT); |
| gc.drawText( |
| STRING_NOT, sizeNot.x + 6 + offsetx, sizeNot.y + 2 + offsety, SWT.DRAW_TRANSPARENT); |
| if (hoverNot) { |
| gc.setForeground(color); |
| } |
| } else { |
| if (hoverNot) { |
| gc.setForeground(red); |
| gc.drawText( |
| STRING_NOT, sizeNot.x + 5 + offsetx, sizeNot.y + 2 + offsety, SWT.DRAW_TRANSPARENT); |
| gc.drawText( |
| STRING_NOT, sizeNot.x + 6 + offsetx, sizeNot.y + 2 + offsety, SWT.DRAW_TRANSPARENT); |
| gc.setForeground(color); |
| } |
| } |
| |
| if (hoverNot) { |
| gc.setBackground(bg); |
| } |
| } |
| |
| private void drawAtomic(GC gc, int x, int y, Condition condition) { |
| try { |
| // First the text sizes... |
| String left = Const.rightPad(condition.getLeftValueName(), maxFieldLength); |
| Point extLeft = gc.textExtent(left); |
| if (condition.getLeftValueName() == null) { |
| extLeft = gc.textExtent("<field>"); |
| } |
| |
| String fnMax = Condition.functions[Condition.FUNC_NOT_NULL]; |
| String fn = condition.getFunctionDesc(); |
| Point extFn = gc.textExtent(fnMax); |
| |
| String rightval = Const.rightPad(condition.getRightValueName(), maxFieldLength); |
| Point extRval = gc.textExtent(rightval); |
| if (condition.getLeftValueName() == null) { |
| extRval = gc.textExtent("<field>"); |
| } |
| |
| String rightex = condition.getRightValueString(); |
| |
| String rightexMax = rightex; |
| if (rightex == null) { |
| rightexMax = Const.rightPad(" ", 10); |
| } else { |
| if (rightex.length() < 10) { |
| rightexMax = Const.rightPad(rightex, 10); |
| } |
| } |
| |
| Point extRex = gc.textExtent(rightexMax); |
| |
| sizeLeft = new Rectangle(x + 5, y + sizeNot.height + 5, extLeft.x + 5, extLeft.y + 5); |
| |
| sizeFn = |
| new Rectangle( |
| sizeLeft.x + sizeLeft.width + 15, y + sizeNot.height + 5, extFn.x + 5, extFn.y + 5); |
| |
| sizeRightval = |
| new Rectangle( |
| sizeFn.x + sizeFn.width + 15, y + sizeNot.height + 5, extRval.x + 5, extRval.y + 5); |
| |
| sizeRightex = |
| new Rectangle( |
| sizeFn.x + sizeFn.width + 15, |
| y + sizeNot.height + 5 + sizeRightval.height + 5, |
| extRex.x + 5, |
| extRex.y + 5); |
| |
| if (hoverLeft) { |
| gc.setBackground(gray); |
| } |
| gc.fillRectangle(real2Screen(sizeLeft)); |
| gc.drawRectangle(real2Screen(sizeLeft)); |
| gc.setBackground(bg); |
| |
| if (hoverFn) { |
| gc.setBackground(gray); |
| } |
| gc.fillRectangle(real2Screen(sizeFn)); |
| gc.drawRectangle(real2Screen(sizeFn)); |
| gc.setBackground(bg); |
| |
| if (hoverRightval) { |
| gc.setBackground(gray); |
| } |
| gc.fillRectangle(real2Screen(sizeRightval)); |
| gc.drawRectangle(real2Screen(sizeRightval)); |
| gc.setBackground(bg); |
| |
| if (hoverRightex) { |
| gc.setBackground(gray); |
| } |
| gc.fillRectangle(real2Screen(sizeRightex)); |
| gc.drawRectangle(real2Screen(sizeRightex)); |
| gc.setBackground(bg); |
| |
| if (condition.getLeftValueName() != null) { |
| gc.drawText(left, sizeLeft.x + 1 + offsetx, sizeLeft.y + 1 + offsety, SWT.DRAW_TRANSPARENT); |
| } else { |
| gc.setForeground(gray); |
| gc.drawText( |
| "<field>", sizeLeft.x + 1 + offsetx, sizeLeft.y + 1 + offsety, SWT.DRAW_TRANSPARENT); |
| gc.setForeground(black); |
| } |
| |
| gc.drawText(fn, sizeFn.x + 1 + offsetx, sizeFn.y + 1 + offsety, SWT.DRAW_TRANSPARENT); |
| |
| if (condition.getFunction() != NOT_NULL && condition.getFunction() != NULL) { |
| String re = rightex == null ? "" : rightex; |
| String stype = ""; |
| Condition.CValue v = condition.getRightValue(); |
| if (v != null) { |
| stype = " (" + v.createValueMeta().getTypeDesc() + ")"; |
| } |
| |
| if (condition.getRightValueName() != null) { |
| gc.drawText( |
| rightval, |
| sizeRightval.x + 1 + offsetx, |
| sizeRightval.y + 1 + offsety, |
| SWT.DRAW_TRANSPARENT); |
| } else { |
| String nothing = rightex == null ? "<field>" : ""; |
| gc.setForeground(gray); |
| gc.drawText( |
| nothing, |
| sizeRightval.x + 1 + offsetx, |
| sizeRightval.y + 1 + offsety, |
| SWT.DRAW_TRANSPARENT); |
| if (condition.getRightValueName() == null) { |
| gc.setForeground(black); |
| } |
| } |
| |
| if (rightex != null) { |
| gc.drawText( |
| re, sizeRightex.x + 1 + offsetx, sizeRightex.y + 1 + offsety, SWT.DRAW_TRANSPARENT); |
| } else { |
| String nothing = condition.getRightValueName() == null ? "<value>" : ""; |
| gc.setForeground(gray); |
| gc.drawText( |
| nothing, |
| sizeRightex.x + 1 + offsetx, |
| sizeRightex.y + 1 + offsety, |
| SWT.DRAW_TRANSPARENT); |
| gc.setForeground(black); |
| } |
| |
| gc.drawText( |
| stype, |
| sizeRightex.x + 1 + sizeRightex.width + 10 + offsetx, |
| sizeRightex.y + 1 + offsety, |
| SWT.DRAW_TRANSPARENT); |
| } else { |
| gc.drawText( |
| "-", sizeRightval.x + 1 + offsetx, sizeRightval.y + 1 + offsety, SWT.DRAW_TRANSPARENT); |
| gc.drawText( |
| "-", sizeRightex.x + 1 + offsetx, sizeRightex.y + 1 + offsety, SWT.DRAW_TRANSPARENT); |
| } |
| } catch (Exception e) { |
| new ErrorDialog(shell, "Error", "Error drawing condition", e); |
| } |
| } |
| |
| private Point drawCondition(GC gc, int x, int y, int nr, Condition condition) { |
| int opx; |
| int opy; |
| int opw; |
| int oph; |
| int cx; |
| int cy; |
| int cw; |
| int ch; |
| |
| opx = x; |
| opy = y; |
| opw = sizeAndNot.width + 6; |
| oph = sizeAndNot.height + 2; |
| |
| /* |
| * First draw the operator ... |
| */ |
| if (nr > 0) { |
| String operator = condition.getOperatorDesc(); |
| // Remember the size of the rectangle! |
| sizeOper[nr] = new Rectangle(opx, opy, opw, oph); |
| if (nr == hoverOperator) { |
| gc.setBackground(gray); |
| gc.fillRectangle(real2Screen(sizeOper[nr])); |
| gc.drawRectangle(real2Screen(sizeOper[nr])); |
| gc.setBackground(bg); |
| } |
| gc.drawText( |
| operator, |
| sizeOper[nr].x + 2 + offsetx, |
| sizeOper[nr].y + 2 + offsety, |
| SWT.DRAW_TRANSPARENT); |
| } |
| |
| /* |
| * Then draw the condition below, possibly negated! |
| */ |
| String str = condition.toString(0, true, false); // don't show the operator! |
| Point p = gc.textExtent(str); |
| |
| cx = opx + 23; |
| cy = opy + oph + 10; |
| cw = p.x + 5; |
| ch = p.y + 5; |
| |
| // Remember the size of the rectangle! |
| sizeCond[nr] = new Rectangle(cx, cy, cw, ch); |
| |
| if (nr == hoverCondition) { |
| gc.setBackground(gray); |
| gc.fillRectangle(real2Screen(sizeCond[nr])); |
| gc.drawRectangle(real2Screen(sizeCond[nr])); |
| gc.setBackground(bg); |
| } |
| gc.drawText( |
| str, |
| sizeCond[nr].x + 2 + offsetx, |
| sizeCond[nr].y + 5 + offsety, |
| SWT.DRAW_DELIMITER | SWT.DRAW_TRANSPARENT | SWT.DRAW_TAB | SWT.DRAW_MNEMONIC); |
| |
| p.x += 0; |
| p.y += 5; |
| |
| return p; |
| } |
| |
| public void drawUp(GC gc) { |
| if (hoverUp) { |
| gc.setBackground(gray); |
| gc.fillRectangle(sizeUp); |
| } |
| gc.drawRectangle(sizeUp); |
| gc.drawText(STRING_UP, sizeUp.x + 1 + offsetx, sizeUp.y + 1 + offsety, SWT.DRAW_TRANSPARENT); |
| } |
| |
| public void drawMessage(GC gc) { |
| gc.setForeground(blue); |
| gc.drawText( |
| getMessageString(), |
| sizeUp.x + sizeUp.width + offsetx + 40, |
| sizeUp.y + 1 + offsety, |
| SWT.DRAW_TRANSPARENT); |
| } |
| |
| private boolean isInNot(Point screen) { |
| if (sizeNot == null) { |
| return false; |
| } |
| return real2Screen(sizeNot).contains(screen); |
| } |
| |
| private boolean isInUp(Point screen) { |
| if (sizeUp == null || parents.isEmpty()) { |
| return false; // not displayed! |
| } |
| |
| return real2Screen(sizeUp).contains(screen); |
| } |
| |
| private boolean isInAdd(Point screen) { |
| if (sizeAdd == null || screen == null) { |
| return false; |
| } |
| return sizeAdd.contains(screen); |
| } |
| |
| private boolean isInWidget(Point screen) { |
| if (sizeWidget == null) { |
| return false; |
| } |
| |
| return real2Screen(sizeWidget).contains(screen); |
| } |
| |
| private int getNrSubcondition(Point screen) { |
| if (sizeCond == null) { |
| return -1; |
| } |
| |
| for (int i = 0; i < sizeCond.length; i++) { |
| if (sizeCond[i] != null && screen2Real(sizeCond[i]).contains(screen)) { |
| return i; |
| } |
| } |
| return -1; |
| } |
| |
| private boolean isInSubcondition(Point screen) { |
| return getNrSubcondition(screen) >= 0; |
| } |
| |
| private int getNrOperator(Point screen) { |
| if (sizeOper == null) { |
| return -1; |
| } |
| |
| for (int i = 0; i < sizeOper.length; i++) { |
| if (sizeOper[i] != null && screen2Real(sizeOper[i]).contains(screen)) { |
| return i; |
| } |
| } |
| return -1; |
| } |
| |
| private boolean isInOperator(Point screen) { |
| return getNrOperator(screen) >= 0; |
| } |
| |
| private boolean isInLeft(Point screen) { |
| if (sizeLeft == null) { |
| return false; |
| } |
| return real2Screen(sizeLeft).contains(screen); |
| } |
| |
| private boolean isInFunction(Point screen) { |
| if (sizeFn == null) { |
| return false; |
| } |
| return real2Screen(sizeFn).contains(screen); |
| } |
| |
| private boolean isInRightValue(Point screen) { |
| if (sizeRightval == null) { |
| return false; |
| } |
| return real2Screen(sizeRightval).contains(screen); |
| } |
| |
| private boolean isInRightExact(Point screen) { |
| if (sizeRightex == null) { |
| return false; |
| } |
| return real2Screen(sizeRightex).contains(screen); |
| } |
| |
| private int getAreaCode(Point screen) { |
| if (isInNot(screen)) { |
| return AREA_NOT; |
| } |
| if (isInUp(screen)) { |
| return AREA_UP; |
| } |
| if (isInAdd(screen)) { |
| return AREA_ICON_ADD; |
| } |
| |
| if (activeCondition.isAtomic()) { |
| if (isInLeft(screen)) { |
| return AREA_LEFT; |
| } |
| if (isInFunction(screen)) { |
| return AREA_FUNCTION; |
| } |
| if (isInRightExact(screen)) { |
| return AREA_RIGHT_EXACT; |
| } |
| if (isInRightValue(screen)) { |
| return AREA_RIGHT_VALUE; |
| } |
| } else { |
| if (isInSubcondition(screen)) { |
| return AREA_SUBCONDITION; |
| } |
| if (isInOperator(screen)) { |
| return AREA_OPERATOR; |
| } |
| } |
| |
| if (isInWidget(screen)) { |
| return AREA_BACKGROUND; |
| } |
| |
| return AREA_NONE; |
| } |
| |
| /** |
| * Edit the condition in a separate dialog box... |
| * |
| * @param nr The condition nr to be edited |
| */ |
| private void editCondition(int nr) { |
| if (activeCondition.isComposite()) { |
| parents.add(activeCondition); |
| activeCondition = activeCondition.getCondition(nr); |
| } |
| } |
| |
| private void addCondition() throws HopValueException { |
| Condition c = new Condition(); |
| c.setOperator(AND); |
| |
| addCondition(c); |
| setModified(); |
| |
| widget.redraw(); |
| } |
| |
| /** |
| * Add a sub-condition to the active condition... |
| * |
| * @param condition The condition to which we want to add one more. |
| */ |
| private void addCondition(Condition condition) throws HopValueException { |
| activeCondition.addCondition(condition); |
| } |
| |
| /** |
| * Remove a sub-condition from the active condition... |
| * |
| * @param nr The condition nr to be removed. |
| */ |
| private void removeCondition(int nr) { |
| activeCondition.removeCondition(nr); |
| } |
| |
| /** |
| * @param messageString The messageString to set. |
| */ |
| public void setMessageString(String messageString) { |
| this.messageString = messageString; |
| } |
| |
| /** |
| * @return Returns the messageString. |
| */ |
| public String getMessageString() { |
| return messageString; |
| } |
| |
| private Rectangle real2Screen(Rectangle r) { |
| return new Rectangle(r.x + offsetx, r.y + offsety, r.width, r.height); |
| } |
| |
| private Rectangle screen2Real(Rectangle r) { |
| return new Rectangle(r.x - offsetx, r.y - offsety, r.width, r.height); |
| } |
| |
| /** Determine the maximum rectangle of used canvas variables... */ |
| private void getMaxSize() { |
| // Top line... |
| maxdrawn = sizeNot.union(sizeUp); |
| |
| // Atomic |
| if (activeCondition.isAtomic()) { |
| maxdrawn = maxdrawn.union(sizeLeft); |
| maxdrawn = maxdrawn.union(sizeFn); |
| maxdrawn = maxdrawn.union(sizeRightval); |
| maxdrawn = maxdrawn.union(sizeRightex); |
| maxdrawn.width += 100; |
| } else { |
| if (sizeCond != null) { |
| for (int i = 0; i < sizeCond.length; i++) { |
| if (sizeCond[i] != null) { |
| maxdrawn = maxdrawn.union(sizeCond[i]); |
| } |
| } |
| } |
| if (sizeOper != null) { |
| for (int i = 0; i < sizeOper.length; i++) { |
| if (sizeOper[i] != null) { |
| maxdrawn = maxdrawn.union(sizeOper[i]); |
| } |
| } |
| } |
| } |
| |
| maxdrawn.width += 10; |
| maxdrawn.height += 10; |
| } |
| |
| private void setBars() { |
| if (sizeWidget == null || maxdrawn == null) { |
| return; |
| } |
| |
| // Horizontal scrollbar behavior |
| // |
| if (sizeWidget.width > maxdrawn.width) { |
| offsetx = 0; |
| sbHorizontal.setSelection(0); |
| sbHorizontal.setVisible(false); |
| } else { |
| offsetx = -sbHorizontal.getSelection(); |
| sbHorizontal.setVisible(true); |
| // Set the bar's parameters... |
| sbHorizontal.setMaximum(maxdrawn.width); |
| sbHorizontal.setMinimum(0); |
| if (!EnvironmentUtils.getInstance().isWeb()) { |
| sbHorizontal.setPageIncrement(sizeWidget.width); |
| sbHorizontal.setIncrement(10); |
| } |
| } |
| |
| // Vertical scrollbar behavior |
| // |
| if (sizeWidget.height > maxdrawn.height) { |
| offsety = 0; |
| sbVertical.setSelection(0); |
| sbVertical.setVisible(false); |
| } else { |
| offsety = sbVertical.getSelection(); |
| sbVertical.setVisible(true); |
| // Set the bar's parameters... |
| sbVertical.setMaximum(maxdrawn.height); |
| sbVertical.setMinimum(0); |
| if (!EnvironmentUtils.getInstance().isWeb()) { |
| sbVertical.setPageIncrement(sizeWidget.height); |
| sbVertical.setIncrement(10); |
| } |
| } |
| } |
| |
| public void addModifyListener(ModifyListener lsMod) { |
| modListeners.add(lsMod); |
| } |
| |
| public void setModified() { |
| for (int i = 0; i < modListeners.size(); i++) { |
| ModifyListener lsMod = modListeners.get(i); |
| if (lsMod != null) { |
| Event e = new Event(); |
| e.widget = this; |
| lsMod.modifyText(new ModifyEvent(e)); |
| } |
| } |
| } |
| |
| @Override |
| public void mouseMove(MouseEvent e) { |
| |
| Point screen = new Point(e.x, e.y); |
| int area = getAreaCode(screen); |
| |
| int nr = 0; |
| boolean needRedraw = false; |
| |
| hoverCondition = -1; |
| hoverOperator = -1; |
| hoverNot = false; |
| hoverUp = false; |
| hoverLeft = false; |
| hoverFn = false; |
| hoverRightval = false; |
| hoverRightex = false; |
| |
| if (area != AREA_ICON_ADD) { |
| setToolTipText(null); |
| } else { |
| setToolTipText(BaseMessages.getString(PKG, "ConditionEditor.AddCondition.Label")); |
| } |
| |
| switch (area) { |
| case AREA_NOT: |
| hoverNot = true; |
| nr = 1; |
| break; |
| case AREA_UP: |
| hoverUp = getLevel() > 0; |
| nr = 1; |
| break; |
| case AREA_BACKGROUND: |
| break; |
| case AREA_SUBCONDITION: |
| hoverCondition = getNrSubcondition(screen); |
| nr = hoverCondition; |
| break; |
| case AREA_OPERATOR: |
| hoverOperator = getNrOperator(screen); |
| nr = hoverOperator; |
| break; |
| case AREA_LEFT: |
| hoverLeft = true; |
| nr = 1; |
| break; |
| case AREA_FUNCTION: |
| hoverFn = true; |
| nr = 1; |
| break; |
| case AREA_RIGHT_VALUE: |
| hoverRightval = true; |
| nr = 1; |
| break; |
| case AREA_RIGHT_EXACT: |
| hoverRightex = true; |
| nr = 1; |
| break; |
| case AREA_CONDITION: |
| break; |
| case AREA_NONE: |
| break; |
| default: |
| break; |
| } |
| |
| if (area != previousArea || nr != previousAreaNr) { |
| needRedraw = true; |
| } |
| |
| if (needRedraw) { |
| offsetx = -sbHorizontal.getSelection(); |
| offsety = -sbVertical.getSelection(); |
| widget.redraw(); |
| } |
| |
| previousArea = area; |
| previousAreaNr = nr; |
| } |
| } |