/* * Copyright 2005 JBoss Inc * * 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.drools.guvnor.client.modeldriven.ui; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.drools.guvnor.client.common.ClickableLabel; import org.drools.guvnor.client.common.DirtyableComposite; import org.drools.guvnor.client.common.DirtyableFlexTable; import org.drools.guvnor.client.common.DirtyableHorizontalPane; import org.drools.guvnor.client.common.DirtyableVerticalPane; import org.drools.guvnor.client.common.ErrorPopup; import org.drools.guvnor.client.common.FormStylePopup; import org.drools.guvnor.client.common.ImageButton; import org.drools.guvnor.client.common.InfoPopup; import org.drools.guvnor.client.common.LoadingPopup; import org.drools.guvnor.client.common.SmallLabel; import org.drools.guvnor.client.messages.Constants; import org.drools.guvnor.client.modeldriven.HumanReadable; import org.drools.guvnor.client.packages.SuggestionCompletionCache; import org.drools.guvnor.client.packages.WorkingSetManager; import org.drools.guvnor.client.resources.Images; import org.drools.guvnor.client.rpc.AnalysisReport; import org.drools.guvnor.client.rpc.AnalysisReportLine; import org.drools.guvnor.client.rpc.RuleAsset; import org.drools.guvnor.client.rpc.VerificationService; import org.drools.guvnor.client.rpc.VerificationServiceAsync; import org.drools.guvnor.client.ruleeditor.RuleViewer; import org.drools.guvnor.client.security.Capabilities; import org.drools.guvnor.client.security.CapabilitiesManager; import org.drools.guvnor.client.util.Format; import org.drools.ide.common.client.modeldriven.SuggestionCompletionEngine; import org.drools.ide.common.client.modeldriven.brl.ActionCallMethod; import org.drools.ide.common.client.modeldriven.brl.ActionGlobalCollectionAdd; import org.drools.ide.common.client.modeldriven.brl.ActionInsertFact; import org.drools.ide.common.client.modeldriven.brl.ActionInsertLogicalFact; import org.drools.ide.common.client.modeldriven.brl.ActionRetractFact; import org.drools.ide.common.client.modeldriven.brl.ActionSetField; import org.drools.ide.common.client.modeldriven.brl.ActionUpdateField; import org.drools.ide.common.client.modeldriven.brl.CompositeFactPattern; import org.drools.ide.common.client.modeldriven.brl.DSLSentence; import org.drools.ide.common.client.modeldriven.brl.FactPattern; import org.drools.ide.common.client.modeldriven.brl.FreeFormLine; import org.drools.ide.common.client.modeldriven.brl.FromAccumulateCompositeFactPattern; import org.drools.ide.common.client.modeldriven.brl.FromCollectCompositeFactPattern; import org.drools.ide.common.client.modeldriven.brl.FromCompositeFactPattern; import org.drools.ide.common.client.modeldriven.brl.IAction; import org.drools.ide.common.client.modeldriven.brl.IPattern; import org.drools.ide.common.client.modeldriven.brl.RuleMetadata; import org.drools.ide.common.client.modeldriven.brl.RuleModel; import com.google.gwt.core.client.GWT; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.event.dom.client.KeyUpEvent; import com.google.gwt.event.dom.client.KeyUpHandler; import com.google.gwt.resources.client.ImageResource; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.HasHorizontalAlignment; import com.google.gwt.user.client.ui.HasVerticalAlignment; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.Image; import com.google.gwt.user.client.ui.ListBox; import com.google.gwt.user.client.ui.Widget; /** * This is the parent widget that contains the model based rule builder. * * @author Michael Neale * */ public class RuleModeller extends DirtyableComposite implements RuleModelEditor { private Constants constants = GWT.create( Constants.class ); private static Images images = GWT.create( Images.class ); private DirtyableFlexTable layout; private RuleModel model; private RuleModellerConfiguration configuration = RuleModellerConfiguration.getInstance(); private boolean showingOptions = false; private int currentLayoutRow = 0; private String packageName; private RuleAsset asset; private ModellerWidgetFactory widgetFactory; private List<RuleModellerWidget> lhsWidgets = new ArrayList<RuleModellerWidget>(); private List<RuleModellerWidget> rhsWidgets = new ArrayList<RuleModellerWidget>(); private boolean hasModifiedWidgets; private final Command onWidgetModifiedCommand = new Command() { public void execute() { hasModifiedWidgets = true; } }; public RuleModeller(RuleAsset asset, RuleViewer viewer, ModellerWidgetFactory widgetFactory) { this( asset, widgetFactory ); } public RuleModeller(RuleAsset asset, ModellerWidgetFactory widgetFactory) { this.asset = asset; this.model = (RuleModel) asset.content; this.packageName = asset.metaData.packageName; this.widgetFactory = widgetFactory; layout = new DirtyableFlexTable(); initWidget(); layout.setStyleName( "model-builder-Background" ); initWidget( layout ); setWidth( "100%" ); setHeight( "100%" ); } /** * This updates the widget to reflect the state of the model. */ public void initWidget() { layout.clear(); this.currentLayoutRow = 0; Image addPattern = new ImageButton( images.newItem() ); addPattern.setTitle( constants.AddAConditionToThisRule() ); addPattern.addClickHandler( new ClickHandler() { public void onClick(ClickEvent event) { showConditionSelector( (Widget) event.getSource(), null ); } } ); layout.getColumnFormatter().setWidth( 0, "8%" ); layout.getColumnFormatter().setWidth( 1, "87%" ); layout.getColumnFormatter().setWidth( 2, "5%" ); if ( this.showLHS() ) { layout.setWidget( currentLayoutRow, 0, new SmallLabel( "<b>" + constants.WHEN() + "</b>" ) ); if ( !lockLHS() ) { layout.setWidget( currentLayoutRow, 2, addPattern ); } currentLayoutRow++; renderLhs( this.model ); } if ( this.showRHS() ) { layout.setWidget( currentLayoutRow, 0, new SmallLabel( "<b>" + constants.THEN() + "</b>" ) ); Image addAction = new ImageButton( images.newItem() ); addAction.setTitle( constants.AddAnActionToThisRule() ); addAction.addClickHandler( new ClickHandler() { public void onClick(ClickEvent event) { showActionSelector( (Widget) event.getSource(), null ); } } ); if ( !lockRHS() ) { layout.setWidget( currentLayoutRow, 2, addAction ); } currentLayoutRow++; renderRhs( this.model ); } if ( showAttributes() ) { final int tmp1 = currentLayoutRow; final int tmp2 = currentLayoutRow + 1; final RuleModeller self = this; if ( !this.showingOptions ) { ClickableLabel showMoreOptions = new ClickableLabel( "(show options...)", new ClickHandler() { public void onClick(ClickEvent event) { showingOptions = true; layout.setWidget( tmp1, 0, new SmallLabel( constants.optionsRuleModeller() ) ); layout.setWidget( tmp1, 2, getAddAttribute() ); layout.setWidget( tmp2, 1, new RuleAttributeWidget( self, self.model ) ); } } ); layout.setWidget( tmp1, 0, showMoreOptions ); } else { layout.setWidget( tmp1, 0, new SmallLabel( constants.optionsRuleModeller() ) ); layout.setWidget( tmp1, 2, getAddAttribute() ); layout.setWidget( tmp2, 1, new RuleAttributeWidget( self, self.model ) ); } } currentLayoutRow++; layout.setWidget( currentLayoutRow + 1, 1, spacerWidget() ); layout.getCellFormatter().setHeight( currentLayoutRow + 1, 1, "100%" ); this.verifyRule( null ); } private boolean isLock(String attr) { if ( this.asset.isreadonly ) { return true; } if ( this.model.metadataList.length == 0 ) { return false; } for ( RuleMetadata at : this.model.metadataList ) { if ( at.attributeName.equals( attr ) ) { return true; } } return false; } public boolean showRHS() { return !this.configuration.isHideRHS(); } /** return true if we should not allow unfrozen editing of the RHS */ public boolean lockRHS() { return isLock( RuleAttributeWidget.LOCK_RHS ); } public boolean showLHS() { return !this.configuration.isHideLHS(); } /** return true if we should not allow unfrozen editing of the LHS */ public boolean lockLHS() { return isLock( RuleAttributeWidget.LOCK_LHS ); } private boolean showAttributes() { if ( !CapabilitiesManager.getInstance().shouldShow( Capabilities.SHOW_PACKAGE_VIEW ) ) { return false; } return !this.configuration.isHideAttributes(); } public void refreshWidget() { initWidget(); showWarningsAndErrors(); makeDirty(); } private Widget getAddAttribute() { Image add = new ImageButton( images.newItem() ); add.setTitle( constants.AddAnOptionToTheRuleToModifyItsBehaviorWhenEvaluatedOrExecuted() ); add.addClickHandler( new ClickHandler() { public void onClick(ClickEvent event) { showAttributeSelector(); } } ); return add; } protected void showAttributeSelector() { AttributeSelectorPopup pop = new AttributeSelectorPopup( model, lockLHS(), lockRHS(), new Command() { public void execute() { refreshWidget(); } } ); pop.show(); } /** * Do all the widgets for the RHS. */ private void renderRhs(final RuleModel model) { for ( int i = 0; i < model.rhs.length; i++ ) { DirtyableVerticalPane widget = new DirtyableVerticalPane(); widget.setWidth( "100%" ); IAction action = model.rhs[i]; //if lockRHS() set the widget RO, otherwise let them decide. Boolean readOnly = this.lockRHS() ? true : null; RuleModellerWidget w = getWidgetFactory().getWidget( this, action, readOnly ); w.addOnModifiedCommand( this.onWidgetModifiedCommand ); w.setWidth( "100%" ); widget.add( spacerWidget() ); DirtyableHorizontalPane horiz = new DirtyableHorizontalPane(); horiz.setWidth( "100%" ); //horiz.setBorderWidth(2); Image remove = new ImageButton( images.deleteItemSmall() ); remove.setTitle( constants.RemoveThisAction() ); final int idx = i; remove.addClickHandler( new ClickHandler() { public void onClick(ClickEvent event) { if ( Window.confirm( constants.RemoveThisItem() ) ) { model.removeRhsItem( idx ); refreshWidget(); } } } ); horiz.add( w ); if ( !(w instanceof ActionRetractFactWidget) ) { w.setWidth( "100%" ); //NON-NLS horiz.setWidth( "100%" ); } if ( !(this.lockRHS() || w.isReadOnly()) ) { horiz.add( remove ); } widget.add( horiz ); layout.setHTML( currentLayoutRow, 0, "<div class='x-form-field'>" + (i + 1) + ".</div>" ); layout.getFlexCellFormatter().setHorizontalAlignment( currentLayoutRow, 0, HasHorizontalAlignment.ALIGN_CENTER ); layout.getFlexCellFormatter().setVerticalAlignment( currentLayoutRow, 0, HasVerticalAlignment.ALIGN_MIDDLE ); layout.setWidget( currentLayoutRow, 1, widget ); layout.getFlexCellFormatter().setHorizontalAlignment( currentLayoutRow, 1, HasHorizontalAlignment.ALIGN_LEFT ); layout.getFlexCellFormatter().setVerticalAlignment( currentLayoutRow, 1, HasVerticalAlignment.ALIGN_TOP ); layout.getFlexCellFormatter().setWidth( currentLayoutRow, 1, "100%" ); final int index = i; if ( !(this.lockRHS() || w.isReadOnly()) ) { this.addActionsButtonsToLayout( constants.AddAnActionBelow(), new ClickHandler() { public void onClick(ClickEvent event) { showActionSelector( (Widget) event.getSource(), index + 1 ); } }, new ClickHandler() { public void onClick(ClickEvent event) { model.moveRhsItemDown( index ); refreshWidget(); } }, new ClickHandler() { public void onClick(ClickEvent event) { model.moveRhsItemUp( index ); refreshWidget(); } } ); } this.rhsWidgets.add( w ); currentLayoutRow++; } } /** * Pops up the fact selector. */ protected void showConditionSelector(final Widget w, Integer position) { final FormStylePopup popup = new FormStylePopup(); popup.setTitle( constants.AddAConditionToTheRule() ); final Map<String, Command> cmds = new HashMap<String, Command>(); final ListBox positionCbo = new ListBox(); if ( position == null ) { positionCbo.addItem( constants.Bottom(), String.valueOf( this.model.lhs.length ) ); positionCbo.addItem( constants.Top(), "0" ); for ( int i = 1; i < model.lhs.length; i++ ) { positionCbo.addItem( Format.format( constants.Line0(), i ), String.valueOf( i ) ); } } else { //if position is fixed, we just add one element to the drop down. positionCbo.addItem( String.valueOf( position ) ); positionCbo.setSelectedIndex( 0 ); } final ListBox choices = new ListBox( true ); // // The list of DSL sentences // SuggestionCompletionEngine completions = SuggestionCompletionCache.getInstance().getEngineFromCache( packageName ); if ( completions.getDSLConditions().length > 0 ) { for ( int i = 0; i < completions.getDSLConditions().length; i++ ) { final DSLSentence sen = completions.getDSLConditions()[i]; String key = "DSL" + i; choices.addItem( sen.toString(), key ); cmds.put( key, new Command() { public void execute() { addNewDSLLhs( sen, Integer.parseInt( positionCbo.getValue( positionCbo.getSelectedIndex() ) ) ); popup.hide(); } } ); } } // // The list of facts // final String[] facts = completions.getFactTypes(); if ( facts.length > 0 ) { choices.addItem( ".................." ); for ( int i = 0; i < facts.length; i++ ) { final String f = facts[i]; String key = "NF" + f; choices.addItem( f + " ...", key ); cmds.put( key, new Command() { public void execute() { addNewFact( f, Integer.parseInt( positionCbo.getValue( positionCbo.getSelectedIndex() ) ) ); popup.hide(); } } ); } } // // The list of top level CEs // String ces[] = HumanReadable.CONDITIONAL_ELEMENTS; choices.addItem( ".................." ); for ( int i = 0; i < ces.length; i++ ) { final String ce = ces[i]; String key = "CE" + ce; choices.addItem( HumanReadable.getCEDisplayName( ce ) + " ...", key ); cmds.put( key, new Command() { public void execute() { addNewCE( ce, Integer.parseInt( positionCbo.getValue( positionCbo.getSelectedIndex() ) ) ); popup.hide(); } } ); } String fces[] = HumanReadable.FROM_CONDITIONAL_ELEMENTS; choices.addItem( ".................." ); for ( int i = 0; i < fces.length; i++ ) { final String ce = fces[i]; String key = "FCE" + ce; choices.addItem( HumanReadable.getCEDisplayName( ce ) + " ...", key ); cmds.put( key, new Command() { public void execute() { addNewFCE( ce, Integer.parseInt( positionCbo.getValue( positionCbo.getSelectedIndex() ) ) ); popup.hide(); } } ); } if ( CapabilitiesManager.getInstance().shouldShow( Capabilities.SHOW_PACKAGE_VIEW ) ) { choices.addItem( ".................." ); choices.addItem( constants.FreeFormDrl(), "FF" ); cmds.put( "FF", new Command() { public void execute() { model.addLhsItem( new FreeFormLine(), Integer.parseInt( positionCbo.getValue( positionCbo.getSelectedIndex() ) ) ); refreshWidget(); popup.hide(); } } ); } if ( completions.getDSLConditions().length == 0 && facts.length == 0 ) { popup.addRow( new HTML( "<div class='highlight'>" + constants.NoModelTip() + "</div>" ) ); //NON-NLS } choices.addKeyUpHandler( new KeyUpHandler() { public void onKeyUp(com.google.gwt.event.dom.client.KeyUpEvent event) { if ( event.getNativeKeyCode() == KeyCodes.KEY_ENTER ) { selectSomething( choices, cmds ); } } } ); //only show the drop down if we are not using fixed position. if ( position == null ) { HorizontalPanel hp0 = new HorizontalPanel(); hp0.add( new HTML( constants.PositionColon() ) ); hp0.add( positionCbo ); hp0.add( new InfoPopup( constants.PositionColon(), constants.ConditionPositionExplanation() ) ); popup.addRow( hp0 ); } HorizontalPanel hp = new HorizontalPanel(); hp.add( choices ); Button ok = new Button( constants.OK() ); hp.add( ok ); ok.addClickHandler( new ClickHandler() { public void onClick(ClickEvent event) { selectSomething( choices, cmds ); } } ); Button cancel = new Button( constants.Cancel() ); hp.add( cancel ); cancel.addClickHandler( new ClickHandler() { public void onClick(ClickEvent event) { popup.hide(); } } ); popup.addRow( hp ); popup.show(); choices.setFocus( true ); popup.setAfterShow( new Command() { public void execute() { choices.setFocus( true ); } } ); } private void selectSomething(ListBox choices, Map<String, Command> cmds) { int sel = choices.getSelectedIndex(); if ( sel != -1 ) { Command cmd = cmds.get( choices.getValue( choices.getSelectedIndex() ) ); if ( cmd != null ) { cmd.execute(); } verifyRule( null ); } } protected void addNewDSLLhs(DSLSentence sentence, int position) { model.addLhsItem( sentence.copy(), position ); refreshWidget(); } protected void showActionSelector(Widget w, Integer position) { final FormStylePopup popup = new FormStylePopup(); popup.setTitle( constants.AddANewAction() ); final ListBox positionCbo = new ListBox(); if ( position == null ) { positionCbo.addItem( constants.Bottom(), String.valueOf( this.model.rhs.length ) ); positionCbo.addItem( constants.Top(), "0" ); for ( int i = 1; i < model.rhs.length; i++ ) { positionCbo.addItem( Format.format( constants.Line0(), i ), String.valueOf( i ) ); } } else { //if position is fixed, we just add one element to the drop down. positionCbo.addItem( String.valueOf( position ) ); positionCbo.setSelectedIndex( 0 ); } final ListBox choices = new ListBox( true ); final Map<String, Command> cmds = new HashMap<String, Command>(); // // First load up the stuff to do with bound variables or globals // SuggestionCompletionEngine completions = SuggestionCompletionCache.getInstance().getEngineFromCache( packageName ); List<String> vars = model.getBoundFacts(); List<String> vars2 = model.getRhsBoundFacts(); String[] globals = completions.getGlobalVariables(); // // The list of DSL sentences // if ( completions.getDSLActions().length > 0 ) { for ( int i = 0; i < completions.getDSLActions().length; i++ ) { final DSLSentence sen = completions.getDSLActions()[i]; if ( sen != null ) { String sentence = sen.toString(); choices.addItem( sentence, "DSL" + sentence ); //NON-NLS cmds.put( "DSL" + sentence, new Command() { //NON-NLS public void execute() { addNewDSLRhs( sen, Integer.parseInt( positionCbo.getValue( positionCbo.getSelectedIndex() ) ) ); popup.hide(); } } ); } } choices.addItem( "................" ); } //Do Set field (NOT modify) for ( Iterator<String> iter = vars.iterator(); iter.hasNext(); ) { final String v = iter.next(); choices.addItem( Format.format( constants.ChangeFieldValuesOf0(), v ), "VAR" + v ); //NON-NLS cmds.put( "VAR" + v, new Command() { //NON-NLS public void execute() { addActionSetField( v, Integer.parseInt( positionCbo.getValue( positionCbo.getSelectedIndex() ) ) ); popup.hide(); } } ); } for ( int i = 0; i < globals.length; i++ ) { //we also do globals here... final String v = globals[i]; choices.addItem( Format.format( constants.ChangeFieldValuesOf0(), v ), "GLOBVAR" + v ); //NON-NLS cmds.put( "GLOBVAR" + v, new Command() { //NON-NLS public void execute() { addActionSetField( v, Integer.parseInt( positionCbo.getValue( positionCbo.getSelectedIndex() ) ) ); popup.hide(); } } ); } //RETRACT for ( Iterator<String> iter = vars.iterator(); iter.hasNext(); ) { final String v = iter.next(); choices.addItem( Format.format( constants.Retract0(), v ), "RET" + v ); //NON-NLS cmds.put( "RET" + v, new Command() { //NON-NLS public void execute() { addRetract( v, Integer.parseInt( positionCbo.getValue( positionCbo.getSelectedIndex() ) ) ); popup.hide(); } } ); } //MODIFY for ( Iterator<String> iter = vars.iterator(); iter.hasNext(); ) { final String v = iter.next(); choices.addItem( Format.format( constants.Modify0(), v ), "MOD" + v ); //NON-NLS cmds.put( "MOD" + v, new Command() { //NON-NLS public void execute() { addModify( v, Integer.parseInt( positionCbo.getValue( positionCbo.getSelectedIndex() ) ) ); popup.hide(); } } ); } choices.addItem( "................" ); //Now inserts: for ( int i = 0; i < completions.getFactTypes().length; i++ ) { final String item = completions.getFactTypes()[i]; choices.addItem( Format.format( constants.InsertFact0(), item ), "INS" + item ); //NON-NLS cmds.put( "INS" + item, new Command() { //NON-NLS public void execute() { model.addRhsItem( new ActionInsertFact( item ), Integer.parseInt( positionCbo.getValue( positionCbo.getSelectedIndex() ) ) ); refreshWidget(); popup.hide(); } } ); } for ( int i = 0; i < completions.getFactTypes().length; i++ ) { final String item = completions.getFactTypes()[i]; choices.addItem( Format.format( constants.LogicallyInsertFact0(), item ), "LINS" + item ); //NON-NLS cmds.put( "LINS" + item, new Command() { //NON-NLS public void execute() { model.addRhsItem( new ActionInsertLogicalFact( item ), Integer.parseInt( positionCbo.getValue( positionCbo.getSelectedIndex() ) ) ); refreshWidget(); popup.hide(); } } ); } choices.addItem( "................" ); //now global collections if ( completions.getGlobalCollections().length > 0 && vars.size() > 0 ) { for ( String bf : vars ) { for ( int i = 0; i < completions.getGlobalCollections().length; i++ ) { final String glob = completions.getGlobalCollections()[i]; final String var = bf; choices.addItem( Format.format( constants.Append0ToList1(), var, glob ), "GLOBCOL" + glob + var ); //NON-NLS cmds.put( "GLOBCOL" + glob + var, new Command() { //NON-NLS public void execute() { ActionGlobalCollectionAdd gca = new ActionGlobalCollectionAdd(); gca.globalName = glob; gca.factName = var; model.addRhsItem( gca, Integer.parseInt( positionCbo.getValue( positionCbo.getSelectedIndex() ) ) ); refreshWidget(); popup.hide(); } } ); } } } if ( CapabilitiesManager.getInstance().shouldShow( Capabilities.SHOW_PACKAGE_VIEW ) ) { choices.addItem( constants.AddFreeFormDrl(), "FF" ); //NON-NLS cmds.put( "FF", new Command() { //NON-NLS public void execute() { model.addRhsItem( new FreeFormLine(), Integer.parseInt( positionCbo.getValue( positionCbo.getSelectedIndex() ) ) ); refreshWidget(); popup.hide(); } } ); for ( int i = 0; i < globals.length; i++ ) { //we also do globals here... final String v = globals[i]; choices.addItem( Format.format( constants.CallMethodOn0(), v ), "GLOBCALL" + v ); //NON-NLS cmds.put( "GLOBCALL" + v, new Command() { //NON-NLS public void execute() { addCallMethod( v, Integer.parseInt( positionCbo.getValue( positionCbo.getSelectedIndex() ) ) ); popup.hide(); } } ); } //CALL methods for ( Iterator<String> iter = vars.iterator(); iter.hasNext(); ) { final String v = iter.next(); choices.addItem( Format.format( constants.CallMethodOn0(), v ), "CALL" + v ); //NON-NLS cmds.put( "CALL" + v, new Command() { //NON-NLS public void execute() { addCallMethod( v, Integer.parseInt( positionCbo.getValue( positionCbo.getSelectedIndex() ) ) ); popup.hide(); } } ); } //Do Set field (NOT modify) for ( Iterator<String> iter = vars2.iterator(); iter.hasNext(); ) { final String v = iter.next(); choices.addItem( Format.format( constants.CallMethodOn0(), v ), "CALL" + v ); //NON-NLS cmds.put( "CALL" + v, new Command() { //NON-NLS public void execute() { addCallMethod( v, Integer.parseInt( positionCbo.getValue( positionCbo.getSelectedIndex() ) ) ); popup.hide(); } } ); } } //only show the drop down if we are not using fixed position. if ( position == null ) { HorizontalPanel hp0 = new HorizontalPanel(); hp0.add( new HTML( constants.PositionColon() ) ); hp0.add( positionCbo ); hp0.add( new InfoPopup( constants.PositionColon(), constants.ActionPositionExplanation() ) ); popup.addRow( hp0 ); } HorizontalPanel hp = new HorizontalPanel(); choices.addKeyUpHandler( new KeyUpHandler() { public void onKeyUp(KeyUpEvent event) { selectSomethingElse( choices, cmds ); } } ); Button ok = new Button( constants.OK() ); ok.addClickHandler( new ClickHandler() { public void onClick(ClickEvent event) { selectSomethingElse( choices, cmds ); } } ); hp.add( choices ); hp.add( ok ); popup.addRow( hp ); popup.show(); choices.setFocus( true ); } private void selectSomethingElse(final ListBox choices, final Map<String, Command> cmds) { int sel = choices.getSelectedIndex(); if ( sel != -1 ) { cmds.get( choices.getValue( sel ) ).execute(); } } protected void addModify(String itemText, int position) { this.model.addRhsItem( new ActionUpdateField( itemText ), position ); refreshWidget(); } protected void addNewDSLRhs(DSLSentence sentence, int position) { this.model.addRhsItem( sentence.copy(), position ); refreshWidget(); } protected void addRetract(String var, int position) { this.model.addRhsItem( new ActionRetractFact( var ), position ); refreshWidget(); } protected void addActionSetField(String itemText, int position) { this.model.addRhsItem( new ActionSetField( itemText ), position ); refreshWidget(); } protected void addCallMethod(String itemText, int position) { this.model.addRhsItem( new ActionCallMethod( itemText ), position ); refreshWidget(); } protected void addNewCE(String s, int position) { this.model.addLhsItem( new CompositeFactPattern( s ), position ); refreshWidget(); } protected void addNewFCE(String type, int position) { FromCompositeFactPattern p = null; if ( type.equals( "from" ) ) { p = new FromCompositeFactPattern(); } else if ( type.equals( "from accumulate" ) ) { p = new FromAccumulateCompositeFactPattern(); } else if ( type.equals( "from collect" ) ) { p = new FromCollectCompositeFactPattern(); } this.model.addLhsItem( p, position ); refreshWidget(); } /** * Adds a fact to the model, and then refreshes the display. */ protected void addNewFact(String itemText, int position) { this.model.addLhsItem( new FactPattern( itemText ), position ); refreshWidget(); } /** * Builds all the condition widgets. */ private void renderLhs(final RuleModel model) { for ( int i = 0; i < model.lhs.length; i++ ) { DirtyableVerticalPane vert = new DirtyableVerticalPane(); vert.setWidth( "100%" ); //if lockLHS() set the widget RO, otherwise let them decide. Boolean readOnly = this.lockLHS() ? true : null; IPattern pattern = model.lhs[i]; RuleModellerWidget w = getWidgetFactory().getWidget( this, pattern, readOnly ); w.addOnModifiedCommand( this.onWidgetModifiedCommand ); vert.add( wrapLHSWidget( model, i, w ) ); vert.add( spacerWidget() ); layout.setWidget( currentLayoutRow, 0, this.wrapLineNumber( i + 1, true ) ); layout.getFlexCellFormatter().setHorizontalAlignment( currentLayoutRow, 0, HasHorizontalAlignment.ALIGN_CENTER ); layout.getFlexCellFormatter().setVerticalAlignment( currentLayoutRow, 0, HasVerticalAlignment.ALIGN_MIDDLE ); layout.setWidget( currentLayoutRow, 1, vert ); layout.getFlexCellFormatter().setHorizontalAlignment( currentLayoutRow, 1, HasHorizontalAlignment.ALIGN_LEFT ); layout.getFlexCellFormatter().setVerticalAlignment( currentLayoutRow, 1, HasVerticalAlignment.ALIGN_TOP ); layout.getFlexCellFormatter().setWidth( currentLayoutRow, 1, "100%" ); final int index = i; if ( !(this.lockLHS() || w.isReadOnly()) ) { this.addActionsButtonsToLayout( constants.AddAConditionBelow(), new ClickHandler() { public void onClick(ClickEvent event) { showConditionSelector( (Widget) event.getSource(), index + 1 ); } }, new ClickHandler() { public void onClick(ClickEvent event) { model.moveLhsItemDown( index ); refreshWidget(); } }, new ClickHandler() { public void onClick(ClickEvent event) { model.moveLhsItemUp( index ); refreshWidget(); } } ); } this.lhsWidgets.add( w ); currentLayoutRow++; } } private HTML spacerWidget() { HTML h = new HTML( " " ); //NON-NLS h.setHeight( "2px" ); //NON-NLS return h; } /** * This adds the widget to the UI, also adding the remove icon. */ private Widget wrapLHSWidget(final RuleModel model, int i, RuleModellerWidget w) { DirtyableHorizontalPane horiz = new DirtyableHorizontalPane(); final Image remove = new ImageButton( images.deleteItemSmall() ); remove.setTitle( constants.RemoveThisENTIREConditionAndAllTheFieldConstraintsThatBelongToIt() ); final int idx = i; remove.addClickHandler( new ClickHandler() { public void onClick(ClickEvent event) { if ( Window.confirm( constants.RemoveThisEntireConditionQ() ) ) { if ( model.removeLhsItem( idx ) ) { refreshWidget(); } else { ErrorPopup.showMessage( constants.CanTRemoveThatItemAsItIsUsedInTheActionPartOfTheRule() ); } } } } ); horiz.setWidth( "100%" ); w.setWidth( "100%" ); horiz.add( w ); if ( !(this.lockLHS() || w.isReadOnly()) ) { horiz.add( remove ); } return horiz; } private Widget wrapLineNumber(int number, boolean isLHSLine) { String id = "rhsLine"; if ( isLHSLine ) { id = "lhsLine"; } id += number; DirtyableHorizontalPane horiz = new DirtyableHorizontalPane(); horiz.add( new HTML( "<div class='x-form-field' id='" + id + "'>" + number + ".</div>" ) ); return horiz; } private void addLineIcon(int row, ImageResource img, String title) { Widget widget = layout.getWidget( row, 0 ); if ( widget instanceof DirtyableHorizontalPane ) { DirtyableHorizontalPane horiz = (DirtyableHorizontalPane) widget; final Image icon = new ImageButton( img ); icon.setTitle( title ); horiz.add( icon ); } } private void clearLineIcons(int row) { if ( layout.getCellCount( row ) <= 0 ) { return; } Widget widget = layout.getWidget( row, 0 ); if ( widget instanceof DirtyableHorizontalPane ) { DirtyableHorizontalPane horiz = (DirtyableHorizontalPane) widget; while ( horiz.getWidgetCount() > 1 ) { horiz.remove( horiz.getWidgetCount() - 1 ); } } } private void clearLinesIcons() { for ( int i = 0; i < layout.getRowCount(); i++ ) { this.clearLineIcons( i ); } } private void addActionsButtonsToLayout(String title, ClickHandler addBelowListener, ClickHandler moveDownListener, ClickHandler moveUpListener) { final DirtyableHorizontalPane hp = new DirtyableHorizontalPane(); Image addPattern = new ImageButton( images.newItemBelow() ); addPattern.setTitle( title ); addPattern.addClickHandler( addBelowListener ); Image moveDown = new ImageButton( images.shuffleDown() ); moveDown.setTitle( constants.MoveDown() ); moveDown.addClickHandler( moveDownListener ); Image moveUp = new ImageButton( images.shuffleUp() ); moveUp.setTitle( constants.MoveUp() ); moveUp.addClickHandler( moveUpListener ); hp.add( addPattern ); hp.add( moveDown ); hp.add( moveUp ); layout.setWidget( currentLayoutRow, 2, hp ); layout.getFlexCellFormatter().setHorizontalAlignment( currentLayoutRow, 2, HasHorizontalAlignment.ALIGN_CENTER ); layout.getFlexCellFormatter().setVerticalAlignment( currentLayoutRow, 2, HasVerticalAlignment.ALIGN_MIDDLE ); } public RuleModel getModel() { return model; } /** * Returns true is a var name has already been used * either by the rule, or as a global. */ public boolean isVariableNameUsed(String name) { SuggestionCompletionEngine completions = SuggestionCompletionCache.getInstance().getEngineFromCache( packageName ); return model.isVariableNameUsed( name ) || completions.isGlobalVariable( name ); } @Override public boolean isDirty() { return (layout.hasDirty() || dirtyflag); } public SuggestionCompletionEngine getSuggestionCompletions() { return SuggestionCompletionCache.getInstance().getEngineFromCache( packageName ); } private List<AnalysisReportLine> errors; private List<AnalysisReportLine> warnings; public void verifyRule(final Command cmd) { this.verifyRule( cmd, false ); } public void verifyRule(final Command cmd, boolean forceVerification) { errors = new ArrayList<AnalysisReportLine>(); warnings = new ArrayList<AnalysisReportLine>(); //if AutoVerifierEnabled is off or there are not modified widgets, //just execute cmd and return. if ( !forceVerification && (!WorkingSetManager.getInstance().isAutoVerifierEnabled() || !this.hasModifiedWidgets) ) { if ( cmd != null ) { cmd.execute(); } return; } LoadingPopup.showMessage( constants.VerifyingItemPleaseWait() ); Set<String> activeWorkingSets = WorkingSetManager.getInstance().getActiveAssetUUIDs( asset.metaData.packageName ); VerificationServiceAsync verificationService = GWT.create( VerificationService.class ); verificationService.verifyAssetWithoutVerifiersRules( this.asset, activeWorkingSets, new AsyncCallback<AnalysisReport>() { public void onSuccess(AnalysisReport report) { LoadingPopup.close(); errors = Arrays.asList( report.errors ); warnings = Arrays.asList( report.warnings ); processWarningsAndErrors(); hasModifiedWidgets = false; if ( cmd != null ) { cmd.execute(); } } public void onFailure(Throwable arg0) { LoadingPopup.close(); } } ); } private void processWarningsAndErrors() { if ( this.warnings.isEmpty() && this.errors.isEmpty() ) { for ( RuleModellerWidget ruleModellerWidget : this.lhsWidgets ) { ruleModellerWidget.setModified( false ); } for ( RuleModellerWidget ruleModellerWidget : this.rhsWidgets ) { ruleModellerWidget.setModified( false ); } } showWarningsAndErrors(); } private void showWarningsAndErrors() { this.clearLinesIcons(); if ( this.warnings != null ) { for ( AnalysisReportLine warning : this.warnings ) { if ( warning.patternOrderNumber != null ) { this.addLineIcon( warning.patternOrderNumber + 1, images.warning(), warning.description ); } } } if ( this.errors != null ) { for ( AnalysisReportLine error : this.errors ) { if ( error.patternOrderNumber != null ) { this.addLineIcon( error.patternOrderNumber + 1, images.error(), error.description ); } } } } public boolean hasVerifierErrors() { return this.errors != null && this.errors.size() > 0; } public boolean hasVerifierWarnings() { return this.warnings != null && this.warnings.size() > 0; } public ModellerWidgetFactory getWidgetFactory() { return widgetFactory; } public void setWidgetFactory(ModellerWidgetFactory widgetFactory) { this.widgetFactory = widgetFactory; } public RuleModeller getRuleModeller() { return this; } public boolean isTemplate() { return widgetFactory.isTemplate(); } public RuleAsset getAsset() { return asset; } }