org.drools.guvnor.client.modeldriven.ui.ExpressionBuilder.java Source code

Java tutorial

Introduction

Here is the source code for org.drools.guvnor.client.modeldriven.ui.ExpressionBuilder.java

Source

/*
 * Copyright 2010 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 static org.drools.ide.common.client.modeldriven.brl.ExpressionPartHelper.getExpressionPartForField;
import static org.drools.ide.common.client.modeldriven.brl.ExpressionPartHelper.getExpressionPartForGlobalVariable;
import static org.drools.ide.common.client.modeldriven.brl.ExpressionPartHelper.getExpressionPartForMethod;

import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.drools.guvnor.client.common.ClickableLabel;
import org.drools.guvnor.client.common.FormStylePopup;
import org.drools.guvnor.client.common.SmallLabel;
import org.drools.guvnor.client.messages.Constants;
import org.drools.guvnor.client.util.Format;
import org.drools.ide.common.client.modeldriven.SuggestionCompletionEngine;
import org.drools.ide.common.client.modeldriven.brl.ExpressionCollectionIndex;
import org.drools.ide.common.client.modeldriven.brl.ExpressionFieldVariable;
import org.drools.ide.common.client.modeldriven.brl.ExpressionFormLine;
import org.drools.ide.common.client.modeldriven.brl.ExpressionMethod;
import org.drools.ide.common.client.modeldriven.brl.ExpressionPart;
import org.drools.ide.common.client.modeldriven.brl.ExpressionText;
import org.drools.ide.common.client.modeldriven.brl.ExpressionVariable;
import org.drools.ide.common.client.modeldriven.brl.FactPattern;
import org.drools.ide.common.client.modeldriven.brl.RuleModel;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;

public class ExpressionBuilder extends RuleModellerWidget
        implements HasExpressionTypeChangeHandlers, HasExpressionChangeHandlers {

    private static final String DELETE_VALUE = "_delete_";
    private static final String FIElD_VALUE_PREFIX = "fl";
    private static final String VARIABLE_VALUE_PREFIX = "va";
    // private static final String GLOBAL_COLLECTION_VALUE_PREFIX = "gc";
    private static final String GLOBAL_VARIABLE_VALUE_PREFIX = "gv";
    private static final String METHOD_VALUE_PREFIX = "mt";
    private final SmallLabelClickHandler slch = new SmallLabelClickHandler();
    private Constants constants = ((Constants) GWT.create(Constants.class));
    // private FlowPanel panel = new FlowPanel();
    private HorizontalPanel panel = new HorizontalPanel();
    private ExpressionFormLine expression;
    private boolean readOnly;

    public ExpressionBuilder(RuleModeller modeller, ExpressionFormLine expression) {
        this(modeller, expression, false);
    }

    public ExpressionBuilder(RuleModeller modeller, ExpressionFormLine expression, Boolean readOnly) {
        super(modeller);

        if (readOnly == null) {
            this.readOnly = !modeller.getSuggestionCompletions()
                    .containsFactType(modeller.getSuggestionCompletions()
                            .getFactNameFromType(this.expression.getRootExpression().getClassType()));
        } else {
            this.readOnly = readOnly;
        }

        panel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);

        this.expression = expression;
        if (expression == null || expression.isEmpty()) {
            if (this.readOnly) {
                panel.add(new SmallLabel("<b>-</b>"));
            } else {
                panel.add(createStartPointWidget());
            }
        } else {
            if (this.readOnly) {
                panel.add(createWidgetForExpression("<b>" + getBoundText() + expression.getText(false) + "</b>"));
            } else {
                panel.add(createWidgetForExpression("<b>" + getBoundText() + expression.getText(false) + ".</b>"));
                panel.add(getWidgetForCurrentType());
            }
        }
        initWidget(panel);
    }

    private String getBoundText() {
        if (expression.isBound()) {
            return "[" + expression.getBinding() + "] ";
        }
        return "";
    }

    private Widget createStartPointWidget() {
        ListBox startPoint = new ListBox();
        panel.add(startPoint);

        startPoint.addItem(constants.ChooseDotDotDot(), "");

        // TODO {baunax} uncomment when global collections is implemented.
        // for (String gc : getCompletionEngine().getGlobalCollections()) {
        // startPoint.addItem(gc, GLOBAL_COLLECTION_VALUE_PREFIX + "." + gc);
        // }

        for (String gv : getCompletionEngine().getGlobalVariables()) {
            startPoint.addItem(gv, GLOBAL_VARIABLE_VALUE_PREFIX + "." + gv);
        }

        for (String v : getRuleModel().getBoundFacts()) {
            startPoint.addItem(v, VARIABLE_VALUE_PREFIX + "." + v);
        }

        startPoint.setVisibleItemCount(1);
        startPoint.addChangeHandler(new ChangeHandler() {

            public void onChange(ChangeEvent event) {
                ListBox lb = (ListBox) event.getSource();
                int index = lb.getSelectedIndex();
                if (index > 0) {
                    ExpressionBuilder.this.makeDirty();
                    startPointChange(lb.getValue(index));
                }
            }
        });
        return startPoint;
    }

    @Override
    public void makeDirty() {
        super.makeDirty();
        setModified(true);
    }

    private void startPointChange(String value) {
        setModified(true);
        panel.clear();
        Widget w;
        int dotPos = value.indexOf('.');
        String prefix = value.substring(0, dotPos);
        String attrib = value.substring(dotPos + 1);
        if (prefix.equals(VARIABLE_VALUE_PREFIX)) {
            FactPattern fact = getRuleModel().getBoundFact(attrib);
            ExpressionPart variable;
            if (fact != null) {
                variable = new ExpressionVariable(fact);
            } else {
                //TODO {baunax} fix it!!! to make recursive
                variable = new ExpressionFieldVariable(attrib);
            }
            expression.appendPart(variable);

        } else if (prefix.equals(GLOBAL_VARIABLE_VALUE_PREFIX)) {
            expression.appendPart(getExpressionPartForGlobalVariable(getCompletionEngine(), attrib));
        }
        w = getWidgetForCurrentType();

        if (!expression.isEmpty()) {
            panel.add(createWidgetForExpression("<b>" + expression.getText() + ".</b>"));
        }
        if (w != null) {
            panel.add(w);
        }
        fireExpressionChangeEvent();
        fireExpressionTypeChangeEvent();
    }

    private Widget getWidgetForCurrentType() {
        if (expression.isEmpty()) {
            return createStartPointWidget();
        }

        ChangeHandler ch = new ChangeHandler() {
            public void onChange(ChangeEvent event) {
                ListBox box = (ListBox) event.getSource();
                panel.remove(box);
                if (box.getSelectedIndex() > 0) {
                    onChangeSelection(box.getValue(box.getSelectedIndex()));
                }
            }
        };

        ListBox lb = new ListBox();
        lb.setVisibleItemCount(1);
        lb.addItem(constants.ChooseDotDotDot(), "");
        lb.addItem("<==" + constants.DeleteItem(), DELETE_VALUE);
        for (Map.Entry<String, String> entry : getCompletionsForCurrentType().entrySet()) {
            lb.addItem(entry.getKey(), entry.getValue());
        }
        lb.addChangeHandler(ch);
        return lb;
    }

    private void onCollectionChange(String value) {
        if ("size".contains(value)) {
            expression.appendPart(new ExpressionMethod("size", "int", SuggestionCompletionEngine.TYPE_NUMERIC));
        } else if ("isEmpty".equals(value)) {
            expression.appendPart(
                    new ExpressionMethod("isEmpty", "boolean", SuggestionCompletionEngine.TYPE_BOOLEAN));
        } else {
            ExpressionCollectionIndex collectionIndex;
            String factName = getCompletionEngine().getFactNameFromType(getCurrentParametricType());
            if (getCurrentParametricType() != null && factName != null) {
                collectionIndex = new ExpressionCollectionIndex("get", getCurrentParametricType(), factName);
            } else {
                collectionIndex = new ExpressionCollectionIndex("get", "java.lang.Object",
                        SuggestionCompletionEngine.TYPE_OBJECT);
            }
            if ("first".equals(value)) {
                collectionIndex.putParam("index", new ExpressionFormLine(new ExpressionText("0")));
                expression.appendPart(collectionIndex);
            } else if ("last".equals(value)) {
                ExpressionFormLine index = new ExpressionFormLine(expression);
                index.appendPart(new ExpressionMethod("size", "int", SuggestionCompletionEngine.TYPE_NUMERIC));
                index.appendPart(new ExpressionText("-1"));

                collectionIndex.putParam("index", index);
                expression.appendPart(collectionIndex);
            }
        }
    }

    private void onChangeSelection(String value) {
        setModified(true);
        String oldType = getCurrentGenericType();
        String prevFactName = null;
        if (DELETE_VALUE.equals(value)) {
            expression.removeLast();
        } else if (SuggestionCompletionEngine.TYPE_COLLECTION.equals(getCurrentGenericType())) {
            onCollectionChange(value);
        } else if (SuggestionCompletionEngine.TYPE_STRING.equals(getCurrentGenericType())) {
            if ("size".equals(value)) {
                expression.appendPart(new ExpressionMethod("size", "int", SuggestionCompletionEngine.TYPE_NUMERIC));
            } else if ("isEmpty".equals(value)) {
                expression.appendPart(
                        new ExpressionText(".size() == 0", "", SuggestionCompletionEngine.TYPE_NUMERIC));
            }
        } else {
            int dotPos = value.indexOf('.');
            String prefix = value.substring(0, dotPos);
            String attrib = value.substring(dotPos + 1);

            prevFactName = getCompletionEngine().getFactNameFromType(getCurrentClassType());
            // String genericType = SuggestionCompletionEngine.TYPE_OBJECT;
            if (FIElD_VALUE_PREFIX.equals(prefix)) {
                expression.appendPart(getExpressionPartForField(getCompletionEngine(), prevFactName, attrib));
            } else if (METHOD_VALUE_PREFIX.equals(prefix)) {
                expression.appendPart(getExpressionPartForMethod(getCompletionEngine(), prevFactName, attrib));
            }
        }
        Widget w = getWidgetForCurrentType();

        panel.clear();
        if (!expression.isEmpty()) {
            panel.add(createWidgetForExpression("<b>" + expression.getText() + ".</b>"));
        }
        if (w != null) {
            panel.add(w);
        }
        fireExpressionChangeEvent();
        fireExpressionTypeChangeEvent(oldType);
    }

    private Map<String, String> getCompletionsForCurrentType() {
        Map<String, String> completions = new LinkedHashMap<String, String>();

        if (SuggestionCompletionEngine.TYPE_FINAL_OBJECT.equals(getCurrentGenericType())) {
            return completions;
        }

        if (SuggestionCompletionEngine.TYPE_COLLECTION.equals(getCurrentGenericType())) {
            completions.put("size()", "size");
            completions.put("first()", "first");
            completions.put("last()", "last");
            completions.put("isEmpty()", "isEmpty");
            return completions;
        }

        if (SuggestionCompletionEngine.TYPE_STRING.equals(getCurrentGenericType())) {
            completions.put("size()", "size");
            completions.put("isEmpty()", "isEmpty");
            return completions;
        }

        if (SuggestionCompletionEngine.TYPE_BOOLEAN.equals(getCurrentGenericType())
                || SuggestionCompletionEngine.TYPE_NUMERIC.equals(getCurrentGenericType())
                || SuggestionCompletionEngine.TYPE_DATE.equals(getCurrentGenericType())
                || SuggestionCompletionEngine.TYPE_OBJECT.equals(getCurrentGenericType())) {
            return completions;
        }

        String factName = getCompletionEngine().getFactNameFromType(getCurrentClassType());
        if (factName != null) {
            // we currently only support 0 param method calls
            List<String> methodNames = getCompletionEngine().getMethodFullNames(factName, 0);

            for (String field : getCompletionEngine().getFieldCompletions(factName)) {
                boolean changed = false;
                for (Iterator<String> i = methodNames.iterator(); i.hasNext();) {
                    String method = i.next();
                    if (method.startsWith(field)) {
                        completions.put(method, METHOD_VALUE_PREFIX + "." + method);
                        i.remove();
                        changed = true;
                    }
                }
                if (!changed) {
                    completions.put(field, FIElD_VALUE_PREFIX + "." + field);
                }
            }
        }
        // else {We don't know anything about this type, so return empty map}
        return completions;
    }

    // private String getCurrentPartName() {
    // return expression.getCurrentName();
    // }

    private RuleModel getRuleModel() {
        return this.getModeller().getModel();
    }

    private SuggestionCompletionEngine getCompletionEngine() {
        return this.getModeller().getSuggestionCompletions();
    }

    private String getCurrentClassType() {
        return expression.getClassType();
    }

    private String getCurrentGenericType() {
        return expression.getGenericType();
    }

    private String getPreviousGenericType() {
        return expression.getPreviousGenericType();
    }

    private String getCurrentParametricType() {
        return expression.getParametricType();
    }

    // private String getPreviousClassType() {
    // return expression.getPreviousType();
    // }
    //
    // private ExpressionPart getRootExpression() {
    // return expression.getRootExpression();
    // }

    @Override
    public boolean isReadOnly() {
        return this.readOnly;
    }

    /**
     * @see org.drools.guvnor.client.modeldriven.ui.HasExpressionTypeChangeHandlers#addExpressionTypeChangeHandler(org.drools.guvnor.client.modeldriven.ui.ExpressionTypeChangeHandler)
     */
    public HandlerRegistration addExpressionTypeChangeHandler(ExpressionTypeChangeHandler handler) {
        return addHandler(handler, ExpressionTypeChangeEvent.getType());
    }

    private void fireExpressionChangeEvent() {
        fireEvent(new ExpressionChangeEvent());
    }

    private void fireExpressionTypeChangeEvent() {
        fireExpressionTypeChangeEvent(getPreviousGenericType());
    }

    private void fireExpressionTypeChangeEvent(String previousGenericType) {
        String currentGenericType = getCurrentGenericType();
        if ((previousGenericType == null || !previousGenericType.equals(currentGenericType))
                || currentGenericType != null) {
            fireEvent(new ExpressionTypeChangeEvent(previousGenericType, currentGenericType));
        }
    }

    public HandlerRegistration addExpressionChangeHandler(ExpressionChangeHandler handler) {
        return addHandler(handler, ExpressionChangeEvent.getType());
    }

    private void showBindingPopUp() {
        final FormStylePopup popup = new FormStylePopup();
        popup.setWidth(500 + "px");
        HorizontalPanel vn = new HorizontalPanel();
        final TextBox varName = new TextBox();
        Button ok = new Button(constants.Set());
        vn.add(new Label(constants.BindTheExpressionToAVariable()));
        vn.add(varName);
        vn.add(ok);

        ok.addClickHandler(new ClickHandler() {
            public void onClick(ClickEvent event) {
                String var = varName.getText();
                if (getModeller().isVariableNameUsed(var)) {
                    Window.alert(Format.format(constants.TheVariableName0IsAlreadyTaken(), var));
                    return;
                }
                expression.setBinding(var);
                getModeller().refreshWidget();
                popup.hide();
            }
        });

        popup.addRow(vn);
        popup.show();
    }

    private class SmallLabelClickHandler implements ClickHandler {
        public void onClick(ClickEvent event) {
            showBindingPopUp();
        }
    }

    private ClickableLabel createWidgetForExpression(String text) {
        ClickableLabel label = new ClickableLabel(text, slch);
        return label;
    }
}