/*! ****************************************************************************** * * Pentaho Data Integration * * Copyright (C) 2002-2017 by Pentaho : http://www.pentaho.com * ******************************************************************************* * * Licensed 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.pentaho.di.ui.core.widget; import java.util.ArrayList; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ControlAdapter; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.events.MenuDetectEvent; import org.eclipse.swt.events.MenuDetectListener; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.MouseAdapter; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseMoveListener; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; 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.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.pentaho.di.core.Condition; import org.pentaho.di.core.Const; import org.pentaho.di.core.exception.KettleXMLException; import org.pentaho.di.core.row.RowMetaInterface; import org.pentaho.di.core.row.ValueMetaAndData; import org.pentaho.di.core.row.ValueMetaInterface; import org.pentaho.di.core.row.value.ValueMetaFactory; import org.pentaho.di.core.row.value.ValueMetaString; import org.pentaho.di.core.xml.XMLHandler; import org.pentaho.di.i18n.BaseMessages; import org.pentaho.di.ui.core.dialog.EnterSelectionDialog; import org.pentaho.di.ui.core.dialog.EnterValueDialog; import org.pentaho.di.ui.core.dialog.ErrorDialog; import org.pentaho.di.ui.core.gui.GUIResource; import org.w3c.dom.Document; import org.w3c.dom.Node; /** * Widget that allows you to edit a Condition in a graphical way. * * @author Matt * @since 29-07-2004 * */ public class ConditionEditor extends Composite { private static Class<?> PKG = ConditionEditor.class; // for i18n purposes, needed by Translator2!! 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 Composite widget; private Shell shell; private Display display; private Condition active_condition; // private Props props; private Color bg, white, black, red, green, blue, gray; private Font fixed; private Image imageAdd; private Rectangle size_not, size_widget, size_and_not; private Rectangle size_up; private Rectangle size_left, size_fn, size_rightval, size_rightex; private Rectangle[] size_cond; private Rectangle[] size_oper; private Rectangle size_add; private Rectangle maxdrawn; private int hover_condition; private int hover_operator; private boolean hover_not, hover_up; private boolean hover_left, hover_fn, hover_rightval, hover_rightex; private int previous_area; private int previous_area_nr; private ArrayList<Condition> parents; private RowMetaInterface fields; private int max_field_length; private ScrollBar sbVertical, sbHorizontal; private int offsetx, offsety; private ArrayList<ModifyListener> modListeners; private String messageString; private Menu mPop; public ConditionEditor( Composite composite, int arg1, Condition co, RowMetaInterface inputFields ) { super( composite, arg1 | SWT.NO_BACKGROUND | SWT.V_SCROLL | SWT.H_SCROLL ); widget = this; this.active_condition = co; this.fields = inputFields; imageAdd = GUIResource.getInstance().getImage( "ui/images/Add.svg" ); modListeners = new ArrayList<ModifyListener>(); sbVertical = getVerticalBar(); sbHorizontal = getHorizontalBar(); offsetx = 0; offsety = 0; maxdrawn = null; size_not = null; size_widget = null; size_cond = null; previous_area = -1; previous_area_nr = -1; parents = new ArrayList<Condition>(); // Remember parent in drill-down... hover_condition = -1; hover_operator = -1; hover_not = false; hover_up = false; hover_left = false; hover_fn = false; hover_rightval = false; hover_rightex = 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( new PaintListener() { @Override public void paintControl( PaintEvent pe ) { Rectangle r = widget.getBounds(); if ( r.width > 0 && r.height > 0 ) { repaint( pe.gc, r.width, r.height ); } } } ); widget.addMouseMoveListener( new MouseMoveListener() { @Override public void mouseMove( MouseEvent e ) { Point screen = new Point( e.x, e.y ); int area = getAreaCode( screen ); int nr = 0; boolean need_redraw = false; hover_condition = -1; hover_operator = -1; hover_not = false; hover_up = false; hover_left = false; hover_fn = false; hover_rightval = false; hover_rightex = false; if ( area != AREA_ICON_ADD ) { setToolTipText( null ); } else { setToolTipText( BaseMessages.getString( PKG, "ConditionEditor.AddCondition.Label" ) ); } switch ( area ) { case AREA_NOT: hover_not = true; nr = 1; break; case AREA_UP: hover_up = getLevel() > 0; nr = 1; break; case AREA_BACKGROUND: break; case AREA_SUBCONDITION: hover_condition = getNrSubcondition( screen ); nr = hover_condition; break; case AREA_OPERATOR: hover_operator = getNrOperator( screen ); nr = hover_operator; break; case AREA_LEFT: hover_left = true; nr = 1; break; case AREA_FUNCTION: hover_fn = true; nr = 1; break; case AREA_RIGHT_VALUE: hover_rightval = true; nr = 1; break; case AREA_RIGHT_EXACT: hover_rightex = true; nr = 1; break; case AREA_CONDITION: break; case AREA_NONE: break; default: break; } if ( area != previous_area || nr != previous_area_nr ) { need_redraw = true; } if ( need_redraw ) { offsetx = -sbHorizontal.getSelection(); offsety = -sbVertical.getSelection(); widget.redraw(); } previous_area = area; previous_area_nr = nr; } } ); widget.addMouseListener( new MouseAdapter() { @Override public void mouseDown( MouseEvent e ) { Point screen = new Point( e.x, e.y ); // Point real = Screen2Real(screen); int area = getAreaCode( screen ); if ( e.button == 1 ) { // Left click on widget... switch ( area ) { case AREA_NOT: active_condition.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 = active_condition.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 ); active_condition.getCondition( operator ).setOperator( 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 ( active_condition.isAtomic() ) { esd = new EnterSelectionDialog( shell, Condition.functions, BaseMessages.getString( PKG, "ConditionEditor.Functions.Label" ), BaseMessages.getString( PKG, "ConditionEditor.SelectFunction.Label" ) ); esd.setAvoidQuickSearch(); def = active_condition.getFunctionDesc(); defnr = esd.getSelectionNr( def ); selection = esd.open( defnr ); if ( selection != null ) { int fnnr = Condition.getFunction( selection ); active_condition.setFunction( fnnr ); setModified(); } widget.redraw(); } break; case AREA_LEFT: if ( active_condition.isAtomic() && fields != null ) { esd = new EnterSelectionDialog( shell, fields.getFieldNamesAndTypes( max_field_length ), BaseMessages.getString( PKG, "ConditionEditor.Fields" ), BaseMessages.getString( PKG, "ConditionEditor.SelectAField" ) ); esd.setAvoidQuickSearch(); def = active_condition.getLeftValuename(); defnr = esd.getSelectionNr( def ); selection = esd.open( defnr ); if ( selection != null ) { ValueMetaInterface v = fields.getValueMeta( esd.getSelectionNr() ); active_condition.setLeftValuename( v.getName() ); setModified(); } widget.redraw(); } break; case AREA_RIGHT_VALUE: if ( active_condition.isAtomic() && fields != null ) { esd = new EnterSelectionDialog( shell, fields.getFieldNamesAndTypes( max_field_length ), BaseMessages.getString( PKG, "ConditionEditor.Fields" ), BaseMessages.getString( PKG, "ConditionEditor.SelectAField" ) ); esd.setAvoidQuickSearch(); def = active_condition.getLeftValuename(); defnr = esd.getSelectionNr( def ); selection = esd.open( defnr ); if ( selection != null ) { ValueMetaInterface v = fields.getValueMeta( esd.getSelectionNr() ); active_condition.setRightValuename( v.getName() ); active_condition.setRightExact( null ); setModified(); } widget.redraw(); } break; case AREA_RIGHT_EXACT: if ( active_condition.isAtomic() ) { ValueMetaAndData v = active_condition.getRightExact(); if ( v == null ) { ValueMetaInterface leftval = fields != null ? fields.searchValueMeta( active_condition.getLeftValuename() ) : null; if ( leftval != null ) { try { v = new ValueMetaAndData( ValueMetaFactory.createValueMeta( "constant", leftval.getType() ), null ); } catch ( Exception exception ) { new ErrorDialog( shell, "Error", "Error creating value meta object", exception ); } } else { v = new ValueMetaAndData( new ValueMetaString( "constant" ), null ); } } EnterValueDialog evd = new EnterValueDialog( shell, SWT.NONE, v.getValueMeta(), v.getValueData() ); evd.setModalDialog( true ); // To keep the condition editor from being closed with a value dialog still // open. (PDI-140) ValueMetaAndData newval = evd.open(); if ( newval != null ) { active_condition.setRightValuename( null ); active_condition.setRightExact( newval ); setModified(); } widget.redraw(); } break; case AREA_ICON_ADD: addCondition(); break; default: break; } } } @Override public void mouseUp( MouseEvent e ) { } } ); widget.addMenuDetectListener( new MenuDetectListener() { // // set the pop-up menu // @Override public void menuDetected( MenuDetectEvent 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.addSelectionListener( new SelectionAdapter() { @Override public void widgetSelected( SelectionEvent e ) { offsety = -sbVertical.getSelection(); widget.redraw(); } } ); sbHorizontal.addSelectionListener( new SelectionAdapter() { @Override public void widgetSelected( SelectionEvent e ) { offsetx = -sbHorizontal.getSelection(); widget.redraw(); } } ); widget.addControlListener( new ControlAdapter() { @Override public void controlResized( ControlEvent arg0 ) { size_widget = widget.getBounds(); setBars(); } } ); } private void getMaxFieldLength() { max_field_length = 5; if ( fields != null ) { for ( int i = 0; i < fields.size(); i++ ) { ValueMetaInterface value = fields.getValueMeta( i ); if ( value != null && value.getName() != null ) { int len = fields.getValueMeta( i ).getName().length(); if ( len > max_field_length ) { max_field_length = len; } } } } } public int getLevel() { return parents.size(); } public void goUp() { if ( parents.size() > 0 ) { int last = parents.size() - 1; active_condition = 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 cond_nr = getNrSubcondition( screen ); if ( mPop != null && !mPop.isDisposed() ) { mPop.dispose(); } switch ( area ) { case AREA_NOT: mPop = new Menu( widget ); MenuItem miNegate = new MenuItem( mPop, SWT.CASCADE ); miNegate.setText( BaseMessages.getString( PKG, "ConditionEditor.NegateCondition" ) ); miNegate.addSelectionListener( new SelectionAdapter() { @Override public void widgetSelected( SelectionEvent e ) { active_condition.negate(); widget.redraw(); setModified(); } } ); setMenu( mPop ); break; case AREA_BACKGROUND: case AREA_ICON_ADD: mPop = new Menu( widget ); MenuItem miAdd = new MenuItem( mPop, SWT.CASCADE ); miAdd.setText( BaseMessages.getString( PKG, "ConditionEditor.AddCondition.Label" ) ); miAdd.addSelectionListener( new SelectionAdapter() { @Override public void widgetSelected( SelectionEvent e ) { addCondition(); } } ); setMenu( mPop ); break; case AREA_SUBCONDITION: mPop = new Menu( widget ); MenuItem miEdit = new MenuItem( mPop, SWT.CASCADE ); miEdit.setText( "Edit condition" ); miEdit.addSelectionListener( new SelectionAdapter() { @Override public void widgetSelected( SelectionEvent e ) { editCondition( cond_nr ); setModified(); widget.redraw(); } } ); MenuItem miDel = new MenuItem( mPop, SWT.CASCADE ); miDel.setText( BaseMessages.getString( PKG, "ConditionEditor.DeleteCondition.Label" ) ); miDel.addSelectionListener( new SelectionAdapter() { @Override public void widgetSelected( SelectionEvent e ) { removeCondition( cond_nr ); setModified(); widget.redraw(); } } ); // Add a sub-condition in the subcondition... (move down) final Condition sub = active_condition.getCondition( cond_nr ); if ( sub.getLeftValuename() != null ) { miAdd = new MenuItem( mPop, SWT.CASCADE ); miAdd.setText( BaseMessages.getString( PKG, "ConditionEditor.AddSubCondition.Label" ) ); miAdd.addSelectionListener( new SelectionAdapter() { @Override public void widgetSelected( SelectionEvent e ) { Condition c = new Condition(); c.setOperator( Condition.OPERATOR_AND ); sub.addCondition( c ); setModified(); widget.redraw(); } } ); } // -------------------------------------------------- new MenuItem( mPop, SWT.SEPARATOR ); MenuItem miCopy = new MenuItem( mPop, SWT.CASCADE ); miCopy.setText( BaseMessages.getString( PKG, "ConditionEditor.CopyToClipboard" ) ); miCopy.addSelectionListener( new SelectionAdapter() { @Override public void widgetSelected( SelectionEvent e ) { Condition c = active_condition.getCondition( cond_nr ); 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.CASCADE ); miPasteBef.setText( BaseMessages.getString( PKG, "ConditionEditor.PasteFromClipboardBeforeCondition" ) ); miPasteBef.addSelectionListener( new SelectionAdapter() { @Override public void widgetSelected( SelectionEvent 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 ); active_condition.addCondition( cond_nr, c ); widget.redraw(); } else { new ErrorDialog( shell, BaseMessages.getString( PKG, "ConditionEditor.Error" ), BaseMessages .getString( PKG, "ConditionEditor.NoConditionFoundXML" ), new KettleXMLException( BaseMessages .getString( PKG, "ConditionEditor.NoConditionFoundXML.Exception", Const.CR + Const.CR + xml ) ) ); } } catch ( KettleXMLException 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.CASCADE ); miPasteAft.setText( BaseMessages.getString( PKG, "ConditionEditor.PasteFromClipboardAfterCondition" ) ); miPasteAft.addSelectionListener( new SelectionAdapter() { @Override public void widgetSelected( SelectionEvent 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 ); active_condition.addCondition( cond_nr + 1, c ); widget.redraw(); } else { new ErrorDialog( shell, BaseMessages.getString( PKG, "ConditionEditor.Error" ), BaseMessages .getString( PKG, "ConditionEditor.NoConditionFoundXML" ), new KettleXMLException( BaseMessages .getString( PKG, "ConditionEditor.NoConditionFoundXML.Exception", Const.CR + Const.CR + xml ) ) ); } } catch ( KettleXMLException 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.CASCADE ); miMoveSub.setText( BaseMessages.getString( PKG, "ConditionEditor.MoveConditionToSubCondition" ) ); miMoveSub.addSelectionListener( new SelectionAdapter() { @Override public void widgetSelected( SelectionEvent e ) { // Move the condition lower: this means create a subcondition and put the condition there in the list. // Condition down = active_condition.getCondition( cond_nr ); Condition c = new Condition(); c.setOperator( down.getOperator() ); down.setOperator( Condition.OPERATOR_NONE ); active_condition.setCondition( cond_nr, c ); c.addCondition( down ); widget.redraw(); } } ); MenuItem miMoveParent = new MenuItem( mPop, SWT.CASCADE ); miMoveParent.setText( BaseMessages.getString( PKG, "ConditionEditor.MoveConditionToParentCondition" ) ); if ( getLevel() == 0 ) { miMoveParent.setEnabled( false ); } miMoveParent.addSelectionListener( new SelectionAdapter() { @Override public void widgetSelected( SelectionEvent e ) { // Move the condition lower: this means delete the condition from the active_condition. // After that, move it to the parent. Condition up = active_condition.getCondition( cond_nr ); active_condition.removeCondition( cond_nr ); Condition parent = parents.get( getLevel() - 1 ); parent.addCondition( up ); // Take a look upward... goUp(); widget.redraw(); } } ); // -------------------------------------------------- new MenuItem( mPop, SWT.SEPARATOR ); MenuItem miMoveDown = new MenuItem( mPop, SWT.CASCADE ); miMoveDown.setText( BaseMessages.getString( PKG, "ConditionEditor.MoveConditionDown" ) ); if ( cond_nr >= active_condition.nrConditions() - 1 ) { miMoveDown.setEnabled( false ); } miMoveDown.addSelectionListener( new SelectionAdapter() { @Override public void widgetSelected( SelectionEvent e ) { Condition down = active_condition.getCondition( cond_nr ); active_condition.removeCondition( cond_nr ); active_condition.addCondition( cond_nr + 1, down ); widget.redraw(); } } ); MenuItem miMoveUp = new MenuItem( mPop, SWT.CASCADE ); miMoveUp.setText( BaseMessages.getString( PKG, "ConditionEditor.MoveConditionUp" ) ); if ( cond_nr == 0 ) { miMoveUp.setEnabled( false ); } miMoveUp.addSelectionListener( new SelectionAdapter() { @Override public void widgetSelected( SelectionEvent e ) { Condition up = active_condition.getCondition( cond_nr ); active_condition.removeCondition( cond_nr ); active_condition.addCondition( cond_nr - 1, up ); widget.redraw(); } } ); setMenu( mPop ); break; case AREA_OPERATOR: Menu mPop = new Menu( widget ); MenuItem miDown = new MenuItem( mPop, SWT.CASCADE ); 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 dgc, int width, int height ) { Image im = new Image( display, width, height ); GC gc = new GC( im ); // Initialize some information size_not = getNotSize( gc ); size_widget = getWidgetSize( gc ); size_and_not = getAndNotSize( gc ); size_up = getUpSize( gc ); size_add = getAddSize( gc ); size_left = null; size_fn = null; size_rightval = null; size_rightex = 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 ( active_condition.isAtomic() ) { size_cond = null; drawNegated( gc, 0, 0, active_condition ); drawAtomic( gc, 0, 0, active_condition ); // gc.drawText("ATOMIC", 10, size_widget.height-20); } else { drawNegated( gc, 0, 0, active_condition ); size_cond = new Rectangle[active_condition.nrConditions()]; size_oper = new Rectangle[active_condition.nrConditions()]; int basex = 10; int basey = size_not.y + 5; for ( int i = 0; i < active_condition.nrConditions(); i++ ) { Point to = drawCondition( gc, basex, basey, i, active_condition.getCondition( i ) ); basey += size_and_not.height + to.y + 15; } } gc.drawImage( imageAdd, size_add.x, size_add.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(); // Draw the result on the canvas, all in 1 go. dgc.drawImage( im, 0, 0 ); im.dispose(); } 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( size_not.x + size_not.width + 40, size_not.y, p.x + 20, size_not.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 ( hover_not ) { gc.setBackground( gray ); } gc.fillRectangle( Real2Screen( size_not ) ); gc.drawRectangle( Real2Screen( size_not ) ); if ( condition.isNegated() ) { if ( hover_not ) { gc.setForeground( green ); } gc.drawText( STRING_NOT, size_not.x + 5 + offsetx, size_not.y + 2 + offsety, SWT.DRAW_TRANSPARENT ); gc.drawText( STRING_NOT, size_not.x + 6 + offsetx, size_not.y + 2 + offsety, SWT.DRAW_TRANSPARENT ); if ( hover_not ) { gc.setForeground( color ); } } else { if ( hover_not ) { gc.setForeground( red ); gc.drawText( STRING_NOT, size_not.x + 5 + offsetx, size_not.y + 2 + offsety, SWT.DRAW_TRANSPARENT ); gc.drawText( STRING_NOT, size_not.x + 6 + offsetx, size_not.y + 2 + offsety, SWT.DRAW_TRANSPARENT ); gc.setForeground( color ); } } if ( hover_not ) { gc.setBackground( bg ); } } private void drawAtomic( GC gc, int x, int y, Condition condition ) { // First the text sizes... String left = Const.rightPad( condition.getLeftValuename(), max_field_length ); Point ext_left = gc.textExtent( left ); if ( condition.getLeftValuename() == null ) { ext_left = gc.textExtent( "<field>" ); } String fn_max = Condition.functions[Condition.FUNC_NOT_NULL]; String fn = condition.getFunctionDesc(); Point ext_fn = gc.textExtent( fn_max ); String rightval = Const.rightPad( condition.getRightValuename(), max_field_length ); Point ext_rval = gc.textExtent( rightval ); if ( condition.getLeftValuename() == null ) { ext_rval = gc.textExtent( "<field>" ); } String rightex = condition.getRightExactString(); String rightex_max = rightex; if ( rightex == null ) { rightex_max = Const.rightPad( " ", 10 ); } else { if ( rightex.length() < 10 ) { rightex_max = Const.rightPad( rightex, 10 ); } } Point ext_rex = gc.textExtent( rightex_max ); size_left = new Rectangle( x + 5, y + size_not.height + 5, ext_left.x + 5, ext_left.y + 5 ); size_fn = new Rectangle( size_left.x + size_left.width + 15, y + size_not.height + 5, ext_fn.x + 5, ext_fn.y + 5 ); size_rightval = new Rectangle( size_fn.x + size_fn.width + 15, y + size_not.height + 5, ext_rval.x + 5, ext_rval.y + 5 ); size_rightex = new Rectangle( size_fn.x + size_fn.width + 15, y + size_not.height + 5 + size_rightval.height + 5, ext_rex.x + 5, ext_rex.y + 5 ); if ( hover_left ) { gc.setBackground( gray ); } gc.fillRectangle( Real2Screen( size_left ) ); gc.drawRectangle( Real2Screen( size_left ) ); gc.setBackground( bg ); if ( hover_fn ) { gc.setBackground( gray ); } gc.fillRectangle( Real2Screen( size_fn ) ); gc.drawRectangle( Real2Screen( size_fn ) ); gc.setBackground( bg ); if ( hover_rightval ) { gc.setBackground( gray ); } gc.fillRectangle( Real2Screen( size_rightval ) ); gc.drawRectangle( Real2Screen( size_rightval ) ); gc.setBackground( bg ); if ( hover_rightex ) { gc.setBackground( gray ); } gc.fillRectangle( Real2Screen( size_rightex ) ); gc.drawRectangle( Real2Screen( size_rightex ) ); gc.setBackground( bg ); if ( condition.getLeftValuename() != null ) { gc.drawText( left, size_left.x + 1 + offsetx, size_left.y + 1 + offsety, SWT.DRAW_TRANSPARENT ); } else { gc.setForeground( gray ); gc.drawText( "<field>", size_left.x + 1 + offsetx, size_left.y + 1 + offsety, SWT.DRAW_TRANSPARENT ); gc.setForeground( black ); } gc.drawText( fn, size_fn.x + 1 + offsetx, size_fn.y + 1 + offsety, SWT.DRAW_TRANSPARENT ); if ( condition.getFunction() != Condition.FUNC_NOT_NULL && condition.getFunction() != Condition.FUNC_NULL ) { String re = rightex == null ? "" : rightex; String stype = ""; ValueMetaAndData v = condition.getRightExact(); if ( v != null ) { stype = " (" + v.getValueMeta().getTypeDesc() + ")"; } if ( condition.getRightValuename() != null ) { gc.drawText( rightval, size_rightval.x + 1 + offsetx, size_rightval.y + 1 + offsety, SWT.DRAW_TRANSPARENT ); } else { String nothing = rightex == null ? "<field>" : ""; gc.setForeground( gray ); gc.drawText( nothing, size_rightval.x + 1 + offsetx, size_rightval.y + 1 + offsety, SWT.DRAW_TRANSPARENT ); if ( condition.getRightValuename() == null ) { gc.setForeground( black ); } } if ( rightex != null ) { gc.drawText( re, size_rightex.x + 1 + offsetx, size_rightex.y + 1 + offsety, SWT.DRAW_TRANSPARENT ); } else { String nothing = condition.getRightValuename() == null ? "<value>" : ""; gc.setForeground( gray ); gc.drawText( nothing, size_rightex.x + 1 + offsetx, size_rightex.y + 1 + offsety, SWT.DRAW_TRANSPARENT ); gc.setForeground( black ); } gc.drawText( stype, size_rightex.x + 1 + size_rightex.width + 10 + offsetx, size_rightex.y + 1 + offsety, SWT.DRAW_TRANSPARENT ); } else { gc.drawText( "-", size_rightval.x + 1 + offsetx, size_rightval.y + 1 + offsety, SWT.DRAW_TRANSPARENT ); gc.drawText( "-", size_rightex.x + 1 + offsetx, size_rightex.y + 1 + offsety, SWT.DRAW_TRANSPARENT ); } } private Point drawCondition( GC gc, int x, int y, int nr, Condition condition ) { int opx, opy, opw, oph; int cx, cy, cw, ch; opx = x; opy = y; opw = size_and_not.width + 6; oph = size_and_not.height + 2; /* * First draw the operator ... */ if ( nr > 0 ) { String operator = condition.getOperatorDesc(); // Remember the size of the rectangle! size_oper[nr] = new Rectangle( opx, opy, opw, oph ); if ( nr == hover_operator ) { gc.setBackground( gray ); gc.fillRectangle( Real2Screen( size_oper[nr] ) ); gc.drawRectangle( Real2Screen( size_oper[nr] ) ); gc.setBackground( bg ); } gc.drawText( operator, size_oper[nr].x + 2 + offsetx, size_oper[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! size_cond[nr] = new Rectangle( cx, cy, cw, ch ); if ( nr == hover_condition ) { gc.setBackground( gray ); gc.fillRectangle( Real2Screen( size_cond[nr] ) ); gc.drawRectangle( Real2Screen( size_cond[nr] ) ); gc.setBackground( bg ); } gc.drawText( str, size_cond[nr].x + 2 + offsetx, size_cond[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 ( hover_up ) { gc.setBackground( gray ); gc.fillRectangle( size_up ); } gc.drawRectangle( size_up ); gc.drawText( STRING_UP, size_up.x + 1 + offsetx, size_up.y + 1 + offsety, SWT.DRAW_TRANSPARENT ); } public void drawMessage( GC gc ) { gc.setForeground( blue ); gc.drawText( getMessageString(), size_up.x + size_up.width + offsetx + 40, size_up.y + 1 + offsety, SWT.DRAW_TRANSPARENT ); // widget.setToolTipText(getMessageString()); } private boolean isInNot( Point screen ) { if ( size_not == null ) { return false; } return Real2Screen( size_not ).contains( screen ); } private boolean isInUp( Point screen ) { if ( size_up == null || parents.isEmpty() ) { return false; // not displayed! } return Real2Screen( size_up ).contains( screen ); } private boolean isInAdd( Point screen ) { if ( size_add == null || screen == null ) { return false; } return size_add.contains( screen ); } private boolean isInWidget( Point screen ) { if ( size_widget == null ) { return false; } return Real2Screen( size_widget ).contains( screen ); } private int getNrSubcondition( Point screen ) { if ( size_cond == null ) { return -1; } for ( int i = 0; i < size_cond.length; i++ ) { if ( size_cond[i] != null && Screen2Real( size_cond[i] ).contains( screen ) ) { return i; } } return -1; } private boolean isInSubcondition( Point screen ) { return getNrSubcondition( screen ) >= 0; } private int getNrOperator( Point screen ) { if ( size_oper == null ) { return -1; } for ( int i = 0; i < size_oper.length; i++ ) { if ( size_oper[i] != null && Screen2Real( size_oper[i] ).contains( screen ) ) { return i; } } return -1; } private boolean isInOperator( Point screen ) { return getNrOperator( screen ) >= 0; } private boolean isInLeft( Point screen ) { if ( size_left == null ) { return false; } return Real2Screen( size_left ).contains( screen ); } private boolean isInFunction( Point screen ) { if ( size_fn == null ) { return false; } return Real2Screen( size_fn ).contains( screen ); } private boolean isInRightValue( Point screen ) { if ( size_rightval == null ) { return false; } return Real2Screen( size_rightval ).contains( screen ); } private boolean isInRightExact( Point screen ) { if ( size_rightex == null ) { return false; } return Real2Screen( size_rightex ).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 ( active_condition.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 condition * The condition to be edited */ private void editCondition( int nr ) { if ( active_condition.isComposite() ) { parents.add( active_condition ); active_condition = active_condition.getCondition( nr ); } } private void addCondition() { Condition c = new Condition(); c.setOperator( Condition.OPERATOR_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 ) { active_condition.addCondition( condition ); } /** * Remove a sub-condition from the active condition... * * @param condition * The condition to which we want to add one more. */ private void removeCondition( int nr ) { active_condition.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 space... */ private void getMaxSize() { // Top line... maxdrawn = size_not.union( size_up ); // Atomic if ( active_condition.isAtomic() ) { maxdrawn = maxdrawn.union( size_left ); maxdrawn = maxdrawn.union( size_fn ); maxdrawn = maxdrawn.union( size_rightval ); maxdrawn = maxdrawn.union( size_rightex ); maxdrawn.width += 100; } else { if ( size_cond != null ) { for ( int i = 0; i < size_cond.length; i++ ) { if ( size_cond[i] != null ) { maxdrawn = maxdrawn.union( size_cond[i] ); } } } if ( size_oper != null ) { for ( int i = 0; i < size_oper.length; i++ ) { if ( size_oper[i] != null ) { maxdrawn = maxdrawn.union( size_oper[i] ); } } } } maxdrawn.width += 10; maxdrawn.height += 10; } private void setBars() { if ( size_widget == null || maxdrawn == null ) { return; } // Horizontal scrollbar behavior // if ( size_widget.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 ); sbHorizontal.setPageIncrement( size_widget.width ); sbHorizontal.setIncrement( 10 ); } // Vertical scrollbar behavior // if ( size_widget.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 ); sbVertical.setPageIncrement( size_widget.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 ) ); } } } }