001: package org.drools.brms.client.modeldriven.ui;
002:
003: /*
004: * Copyright 2005 JBoss Inc
005: *
006: * Licensed under the Apache License, Version 2.0 (the "License");
007: * you may not use this file except in compliance with the License.
008: * You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */
018:
019: import java.util.List;
020:
021: import org.drools.brms.client.common.DirtyableComposite;
022: import org.drools.brms.client.common.FieldEditListener;
023: import org.drools.brms.client.common.FormStylePopup;
024: import org.drools.brms.client.common.InfoPopup;
025: import org.drools.brms.client.common.Lbl;
026: import org.drools.brms.client.modeldriven.SuggestionCompletionEngine;
027: import org.drools.brms.client.modeldriven.brl.FactPattern;
028: import org.drools.brms.client.modeldriven.brl.ISingleFieldConstraint;
029: import org.drools.brms.client.modeldriven.brl.RuleModel;
030: import org.drools.brms.client.modeldriven.brl.SingleFieldConstraint;
031:
032: import com.google.gwt.user.client.Command;
033: import com.google.gwt.user.client.ui.Button;
034: import com.google.gwt.user.client.ui.ChangeListener;
035: import com.google.gwt.user.client.ui.ClickListener;
036: import com.google.gwt.user.client.ui.HTML;
037: import com.google.gwt.user.client.ui.HorizontalPanel;
038: import com.google.gwt.user.client.ui.Image;
039: import com.google.gwt.user.client.ui.KeyboardListener;
040: import com.google.gwt.user.client.ui.ListBox;
041: import com.google.gwt.user.client.ui.Panel;
042: import com.google.gwt.user.client.ui.SimplePanel;
043: import com.google.gwt.user.client.ui.TextBox;
044: import com.google.gwt.user.client.ui.Widget;
045:
046: /**
047: * This is an editor for constraint values.
048: * How this behaves depends on the constraint value type.
049: * When the constraint value has no type, it will allow the user to choose the first time.
050: *
051: * @author Michael Neale
052: * @author Fernando Meyer
053: */
054: public class ConstraintValueEditor extends DirtyableComposite {
055:
056: private final ISingleFieldConstraint constraint;
057: private final Panel panel;
058: private final RuleModel model;
059: private final boolean numericValue;
060: private String[] enumeratedValues;
061:
062: /**
063: * @param con The constraint being edited.
064: */
065: public ConstraintValueEditor(FactPattern pattern, String fieldName,
066: ISingleFieldConstraint con, RuleModeller modeller,
067: String valueTypeNumeric /* eg is numeric */) {
068: this .constraint = con;
069: if (valueTypeNumeric
070: .equals(SuggestionCompletionEngine.TYPE_NUMERIC)) {
071: this .numericValue = true;
072: } else {
073: this .numericValue = false;
074: }
075: this .model = modeller.getModel();
076: SuggestionCompletionEngine sce = modeller
077: .getSuggestionCompletions();
078: String enumKey = pattern.factType + "." + fieldName;
079: if (sce.dataEnumLists.containsKey(enumKey)) {
080: this .enumeratedValues = (String[]) sce.dataEnumLists
081: .get(enumKey);
082: }
083:
084: panel = new SimplePanel();
085: refreshEditor();
086: initWidget(panel);
087:
088: }
089:
090: private void refreshEditor() {
091: panel.clear();
092:
093: if (constraint.constraintValueType == SingleFieldConstraint.TYPE_UNDEFINED) {
094: Image clickme = new Image("images/edit.gif");
095: clickme.addClickListener(new ClickListener() {
096: public void onClick(Widget w) {
097: showTypeChoice(w, constraint);
098: }
099: });
100: panel.add(clickme);
101: } else {
102: switch (constraint.constraintValueType) {
103: case SingleFieldConstraint.TYPE_LITERAL:
104: panel.add(literalEditor());
105: break;
106: case SingleFieldConstraint.TYPE_RET_VALUE:
107: panel.add(returnValueEditor());
108: break;
109: case SingleFieldConstraint.TYPE_VARIABLE:
110: panel.add(variableEditor());
111: break;
112: default:
113: break;
114: }
115: }
116: }
117:
118: private Widget variableEditor() {
119: List vars = this .model
120: .getBoundVariablesInScope(this .constraint);
121:
122: final ListBox box = new ListBox();
123:
124: if (this .constraint.value == null) {
125: box.addItem("Choose ...");
126: }
127: for (int i = 0; i < vars.size(); i++) {
128: String var = (String) vars.get(i);
129: box.addItem(var);
130: if (this .constraint.value != null
131: && this .constraint.value.equals(var)) {
132: box.setSelectedIndex(i);
133: }
134: }
135:
136: box.addChangeListener(new ChangeListener() {
137: public void onChange(Widget w) {
138: constraint.value = box.getItemText(box
139: .getSelectedIndex());
140: }
141: });
142:
143: return box;
144: }
145:
146: /**
147: * An editor for the retval "formula" (expression).
148: */
149: private Widget returnValueEditor() {
150: TextBox box = boundTextBox(constraint);
151: String msg = "This is a formula expression which will evaluate to a value.";
152: Image img = new Image("images/function_assets.gif");
153: img.setTitle(msg);
154: box.setTitle(msg);
155: Widget ed = widgets(img, box);
156: return ed;
157: }
158:
159: /**
160: * An editor for literal values.
161: */
162: private Widget literalEditor() {
163:
164: //use a drop down if we have a fixed list
165: if (this .enumeratedValues != null) {
166: return enumDropDown(constraint.value, new ValueChanged() {
167: public void valueChanged(String newValue) {
168: constraint.value = newValue;
169: }
170: }, this .enumeratedValues);
171: } else {
172:
173: final TextBox box = boundTextBox(constraint);
174:
175: if (this .numericValue) {
176: box.addKeyboardListener(new KeyboardListener() {
177:
178: public void onKeyDown(Widget arg0, char arg1,
179: int arg2) {
180:
181: }
182:
183: public void onKeyPress(Widget w, char c, int i) {
184: if (Character.isLetter(c)) {
185: ((TextBox) w).cancelKey();
186: }
187: }
188:
189: public void onKeyUp(Widget arg0, char arg1, int arg2) {
190: }
191:
192: });
193: }
194:
195: box
196: .setTitle("This is a literal value. What is shown is what the field is checked against.");
197: return box;
198: }
199: }
200:
201: /**
202: * This will do a drop down for enumerated values..
203: */
204: public static Widget enumDropDown(
205: //final ISingleFieldConstraint constraint,
206: final String currentValue, final ValueChanged valueChanged,
207: final String[] enumeratedValues) {
208: final ListBox box = new ListBox();
209:
210: if (currentValue == null || "".equals(currentValue)) {
211: box.addItem("Choose ...");
212: }
213:
214: for (int i = 0; i < enumeratedValues.length; i++) {
215: String v = enumeratedValues[i];
216: String val;
217: if (v.indexOf('=') > 0) {
218: //using a mapping
219: String[] splut = splitValue(v);
220: String realValue = splut[0];
221: String display = splut[1];
222: val = realValue;
223: box.addItem(display, realValue);
224: } else {
225: box.addItem(v, v);
226: val = v;
227: }
228: if (currentValue != null && currentValue.equals(val)) {
229: box.setSelectedIndex(i);
230: }
231: }
232:
233: if (currentValue != null && box.getSelectedIndex() == -1) {
234: //need to add this value
235: box.addItem(currentValue, currentValue);
236: box.setSelectedIndex(enumeratedValues.length);
237: }
238:
239: box.addChangeListener(new ChangeListener() {
240: public void onChange(Widget w) {
241: valueChanged.valueChanged(box.getValue(box
242: .getSelectedIndex()));
243: //constraint.value = box.getValue( box.getSelectedIndex() );
244: }
245: });
246: return box;
247: }
248:
249: /**
250: * 'Person.age' : ['M=Male', 'F=Female']
251: *
252: * This will split the drop down item into a value and a key.
253: * eg key=value
254: *
255: */
256: public static String[] splitValue(String v) {
257: String[] s = new String[2];
258: int pos = v.indexOf('=');
259: s[0] = v.substring(0, pos);
260: s[1] = v.substring(pos + 1, v.length());
261: return s;
262: }
263:
264: private TextBox boundTextBox(final ISingleFieldConstraint c) {
265: final TextBox box = new TextBox();
266: box.setStyleName("constraint-value-Editor");
267: box.setText(c.value);
268: if (c.value == null || c.value.length() < 5) {
269: box.setVisibleLength(3);
270: } else {
271: box.setVisibleLength(c.value.length() - 1);
272: }
273:
274: box.addChangeListener(new ChangeListener() {
275: public void onChange(Widget w) {
276: c.value = box.getText();
277: makeDirty();
278: }
279:
280: });
281:
282: box.addKeyboardListener(new FieldEditListener(new Command() {
283: public void execute() {
284: box.setVisibleLength(box.getText().length());
285: }
286: }));
287:
288: return box;
289: }
290:
291: /**
292: * Show a list of possibilities for the value type.
293: */
294: private void showTypeChoice(Widget w,
295: final ISingleFieldConstraint con) {
296: final FormStylePopup form = new FormStylePopup(
297: "images/newex_wiz.gif", "Field value");
298:
299: Button lit = new Button("Literal value");
300: lit.addClickListener(new ClickListener() {
301: public void onClick(Widget w) {
302: con.constraintValueType = SingleFieldConstraint.TYPE_LITERAL;
303: doTypeChosen(form);
304: }
305:
306: });
307: form
308: .addAttribute(
309: "Literal value:",
310: widgets(
311: lit,
312: new InfoPopup(
313: "Literal",
314: "A literal value means the "
315: + "constraint is directly against the value that you type (ie. what you see on screen).")));
316:
317: form.addRow(new HTML("<hr/>"));
318: form.addRow(new Lbl("Advanced options", "weak-Text"));
319:
320: //only want to show variables if we have some !
321: if (this .model.getBoundVariablesInScope(this .constraint).size() > 0) {
322: Button variable = new Button("Bound variable");
323: variable.addClickListener(new ClickListener() {
324: public void onClick(Widget w) {
325: con.constraintValueType = SingleFieldConstraint.TYPE_VARIABLE;
326: doTypeChosen(form);
327: }
328: });
329: form
330: .addAttribute(
331: "A variable:",
332: widgets(
333: variable,
334: new InfoPopup("A bound variable",
335: "Will apply a constraint that compares a field to a bound variable.")));
336: }
337:
338: Button formula = new Button("New formula");
339: formula.addClickListener(new ClickListener() {
340: public void onClick(Widget w) {
341: con.constraintValueType = SingleFieldConstraint.TYPE_RET_VALUE;
342: doTypeChosen(form);
343: }
344: });
345:
346: form
347: .addAttribute(
348: "A formula:",
349: widgets(
350: formula,
351: new InfoPopup(
352: "A formula",
353: "A formula is an expression that calculates and returns a value "
354: + ". That value is used to enforce the constraint.")));
355:
356: form.setPopupPosition(w.getAbsoluteLeft(), w.getAbsoluteTop());
357: form.show();
358: }
359:
360: private void doTypeChosen(final FormStylePopup form) {
361: refreshEditor();
362: form.hide();
363: }
364:
365: private Panel widgets(Widget left, Widget right) {
366: HorizontalPanel panel = new HorizontalPanel();
367: panel.add(left);
368: panel.add(right);
369: panel.setWidth("100%");
370: return panel;
371: }
372:
373: public boolean isDirty() {
374: return super .isDirty();
375: }
376:
377: static interface ValueChanged {
378: public void valueChanged(String newValue);
379: }
380:
381: }
|