001: package org.drools.eclipse.rulebuilder.ui;
002:
003: import java.util.ArrayList;
004: import java.util.List;
005:
006: import org.drools.brms.client.modeldriven.SuggestionCompletionEngine;
007: import org.drools.brms.client.modeldriven.brl.CompositeFactPattern;
008: import org.drools.brms.client.modeldriven.brl.CompositeFieldConstraint;
009: import org.drools.brms.client.modeldriven.brl.ConnectiveConstraint;
010: import org.drools.brms.client.modeldriven.brl.FactPattern;
011: import org.drools.brms.client.modeldriven.brl.FieldConstraint;
012: import org.drools.brms.client.modeldriven.brl.ISingleFieldConstraint;
013: import org.drools.brms.client.modeldriven.brl.SingleFieldConstraint;
014: import org.drools.eclipse.rulebuilder.modeldriven.HumanReadable;
015: import org.eclipse.swt.SWT;
016: import org.eclipse.swt.events.ModifyEvent;
017: import org.eclipse.swt.events.ModifyListener;
018: import org.eclipse.swt.graphics.Color;
019: import org.eclipse.swt.layout.GridData;
020: import org.eclipse.swt.layout.GridLayout;
021: import org.eclipse.swt.widgets.Combo;
022: import org.eclipse.swt.widgets.Composite;
023: import org.eclipse.swt.widgets.Display;
024: import org.eclipse.swt.widgets.Event;
025: import org.eclipse.swt.widgets.Label;
026: import org.eclipse.swt.widgets.Listener;
027: import org.eclipse.swt.widgets.MessageBox;
028: import org.eclipse.swt.widgets.Text;
029: import org.eclipse.ui.forms.events.HyperlinkEvent;
030: import org.eclipse.ui.forms.events.IHyperlinkListener;
031: import org.eclipse.ui.forms.widgets.FormToolkit;
032: import org.eclipse.ui.forms.widgets.ImageHyperlink;
033:
034: /**
035: * This is the new smart widget that works off the model.
036: *
037: * @author Michael Neale
038: * @author Ahti Kitsik
039: * @author Anton Arhipov
040: *
041: */
042: public class FactPatternWidget extends Widget {
043:
044: private final CompositeFactPattern parentPattern;
045:
046: private final FactPattern pattern;
047:
048: private boolean bindable;
049:
050: public FactPatternWidget(FormToolkit toolkit, Composite parent,
051: RuleModeller mod, FactPattern factPattern,
052: CompositeFactPattern parentPattern, int idx, boolean canBind) {
053:
054: super (parent, toolkit, mod, idx);
055:
056: this .pattern = factPattern;
057: this .parentPattern = parentPattern;
058: this .bindable = canBind;
059:
060: GridLayout l = new GridLayout();
061: l.numColumns = 4;
062: l.marginBottom = 0;
063: l.marginHeight = 0;
064: l.marginLeft = 0;
065: l.marginRight = 0;
066: l.marginTop = 0;
067: l.marginWidth = 0;
068: l.verticalSpacing = 0;
069: parent.setLayout(l);
070:
071: create();
072: }
073:
074: private void create() {
075: Label l = toolkit.createLabel(parent, getPatternLabel());
076:
077: GridData labelGD = new GridData(GridData.FILL_BOTH
078: | GridData.GRAB_HORIZONTAL);
079: labelGD.horizontalSpan = 2;
080: //labelGD.verticalAlignment = SWT.CENTER;
081: //labelGD.horizontalAlignment = SWT.CENTER;
082: l.setLayoutData(labelGD);
083: l.setBackground(new Color(parent.getShell().getDisplay(), 240,
084: 240, 240));
085:
086: addDeleteAction();
087: addMoreOptionsAction();
088:
089: Composite constraintComposite = toolkit.createComposite(parent);
090: GridLayout constraintLayout = new GridLayout();
091: constraintLayout.numColumns = 8;
092: constraintComposite.setLayout(constraintLayout);
093:
094: for (int row = 0; row < pattern.getFieldConstraints().length; row++) {
095: renderFieldConstraints(constraintComposite, pattern
096: .getFieldConstraints()[row], null, row, true, false);
097: }
098:
099: toolkit.paintBordersFor(constraintComposite);
100: }
101:
102: private void addMoreOptionsAction() {
103: ImageHyperlink link = addImage(parent, "icons/new_item.gif");
104:
105: link.addHyperlinkListener(new IHyperlinkListener() {
106: public void linkActivated(HyperlinkEvent e) {
107: RuleDialog popup = new AddNewFieldConstraintDialog(
108: parent.getShell(), toolkit, getModeller(),
109: pattern, parentPattern != null);
110: popup.open();
111: }
112:
113: public void linkEntered(HyperlinkEvent e) {
114: }
115:
116: public void linkExited(HyperlinkEvent e) {
117: }
118: });
119: link
120: .setToolTipText("Add a field to this condition, or bind a varible to this fact.");
121: }
122:
123: private void addDeleteAction() {
124: ImageHyperlink delWholeLink = addImage(parent,
125: "icons/delete_obj.gif");
126: delWholeLink.addHyperlinkListener(new IHyperlinkListener() {
127: public void linkActivated(HyperlinkEvent e) {
128: MessageBox dialog = new MessageBox(Display.getCurrent()
129: .getActiveShell(), SWT.YES | SWT.NO
130: | SWT.ICON_WARNING);
131: dialog
132: .setMessage("Remove this ENTIRE condition, "
133: + "and all the field constraints that belong to it.");
134: dialog.setText("Remove this entire condition?");
135: if (dialog.open() == SWT.YES) {
136: if (parentPattern == null) {
137: if (getModeller().getModel().removeLhsItem(
138: index)) {
139: getModeller().reloadLhs();
140: } else {
141: showMessage("Can't remove that item as it is used in the action part of the rule.");
142: }
143: } else {
144: deleteBindedFact();
145: }
146: getModeller().setDirty(true);
147: }
148: }
149:
150: public void linkEntered(HyperlinkEvent e) {
151: }
152:
153: public void linkExited(HyperlinkEvent e) {
154: }
155: });
156: delWholeLink.setToolTipText("Remove this condition.");
157: }
158:
159: private void renderFieldConstraints(Composite constraintComposite,
160: FieldConstraint constraint,
161: final CompositeFieldConstraint parentConstraint, int row,
162: boolean showBinding, boolean nested) {
163: if (constraint instanceof SingleFieldConstraint) {
164: renderSingleFieldConstraint(constraintComposite, row,
165: constraint, parentConstraint, showBinding, nested);
166: } else if (constraint instanceof CompositeFieldConstraint) {
167: compositeFieldConstraintEditor(constraintComposite,
168: (CompositeFieldConstraint) constraint,
169: parentConstraint, row, nested);
170: }
171: }
172:
173: private void compositeFieldConstraintEditor(
174: Composite constraintComposite,
175: final CompositeFieldConstraint constraint,
176: final CompositeFieldConstraint parentConstraint,
177: final int row, boolean nested) {
178:
179: // Label
180: if (constraint.compositeJunctionType
181: .equals(CompositeFieldConstraint.COMPOSITE_TYPE_AND)) {
182: toolkit.createLabel(constraintComposite, "All of:");
183: } else {
184: toolkit.createLabel(constraintComposite, "Any of:");
185: }
186:
187: addRemoveButton(constraintComposite, parentConstraint, row,
188: "icons/delete_obj.gif", nested);
189:
190: // button "add"
191: ImageHyperlink link = addImage(constraintComposite,
192: "icons/new_item.gif");
193: link.addHyperlinkListener(new IHyperlinkListener() {
194: public void linkActivated(HyperlinkEvent e) {
195: RuleDialog popup = new AddCompositeConstraintOptionDialog(
196: parent.getShell(), getModeller(), constraint,
197: pattern);
198: popup.open();
199: }
200:
201: public void linkEntered(HyperlinkEvent e) {
202: }
203:
204: public void linkExited(HyperlinkEvent e) {
205: }
206: });
207:
208: link.setToolTipText("Add fields to this constriant.");
209:
210: addNestedElements(constraintComposite, constraint);
211: }
212:
213: private void addNestedElements(Composite constraintComposite,
214: final CompositeFieldConstraint constraint) {
215: // Nested elementss
216: FieldConstraint[] nestedConstraints = constraint.constraints;
217: if (nestedConstraints != null) {
218: Composite nestedComposite = toolkit
219: .createComposite(constraintComposite);
220: GridData gd = new GridData(GridData.FILL_HORIZONTAL);
221: gd.horizontalSpan = 5;
222: nestedComposite.setLayoutData(gd);
223:
224: GridLayout l = new GridLayout();
225: l.numColumns = 8;
226: l.marginBottom = 0;
227: l.marginHeight = 0;
228: l.marginLeft = 0;
229: l.marginRight = 0;
230: l.marginTop = 0;
231: l.marginWidth = 0;
232: l.verticalSpacing = 0;
233: nestedComposite.setLayout(l);
234:
235: for (int i = 0; i < nestedConstraints.length; i++) {
236: renderFieldConstraints(nestedComposite,
237: nestedConstraints[i], constraint, i, false,
238: true);
239: toolkit.paintBordersFor(nestedComposite);
240: }
241: } else {
242: GridData gd = new GridData(GridData.FILL_HORIZONTAL);
243: gd.horizontalSpan = 5;
244: Label dummyLabel = toolkit.createLabel(constraintComposite,
245: ""); // dummy
246: dummyLabel.setLayoutData(gd);
247: }
248: }
249:
250: private void renderSingleFieldConstraint(
251: Composite constraintComposite, int row,
252: FieldConstraint constraint,
253: CompositeFieldConstraint parentConstraint,
254: boolean showBinding, boolean nested) {
255: final SingleFieldConstraint c = (SingleFieldConstraint) constraint;
256: if (c.constraintValueType != ISingleFieldConstraint.TYPE_PREDICATE) {
257: createConstraintRow(constraintComposite, parentConstraint,
258: row, c, showBinding, nested);
259: } else {
260: createPredicateConstraintRow(constraintComposite, row, c);
261: }
262: }
263:
264: private void createConstraintRow(Composite constraintComposite,
265: CompositeFieldConstraint parentConstraint, int row,
266: final SingleFieldConstraint c, boolean showBinding,
267: boolean nested) {
268: addBindingField(constraintComposite, c, showBinding);
269: toolkit.createLabel(constraintComposite, c.fieldName);
270: if (c.connectives == null || c.connectives.length == 0) {
271: addRemoveButton(constraintComposite, parentConstraint, row,
272: "icons/delete_item_small.gif", nested);
273: } else {
274: toolkit.createLabel(constraintComposite, "");
275: }
276: operatorDropDown(constraintComposite, c);
277:
278: constraintValueEditor(constraintComposite, c, c.fieldName);
279:
280: createConnectives(constraintComposite, c);
281: addConnectiveAction(constraintComposite, c);
282: }
283:
284: private void addBindingField(Composite constraintComposite,
285: final SingleFieldConstraint c, boolean showBinding) {
286: if (!c.isBound()) {
287: if (bindable && showBinding) {
288: ImageHyperlink link = addImage(constraintComposite,
289: "icons/new_item.gif");
290: link.addHyperlinkListener(new IHyperlinkListener() {
291: public void linkActivated(HyperlinkEvent e) {
292: RuleDialog popup = new AssignFieldVariableDialog(
293: parent.getShell(), toolkit,
294: getModeller(), c);
295: popup.open();
296: }
297:
298: public void linkEntered(HyperlinkEvent e) {
299: }
300:
301: public void linkExited(HyperlinkEvent e) {
302: }
303: });
304:
305: link.setToolTipText("Bind the field called ["
306: + c.fieldName + "] to a variable.");
307: } else {
308: toolkit.createLabel(constraintComposite, "");
309: }
310: } else {
311: toolkit.createLabel(constraintComposite, "["
312: + c.fieldBinding + "]");
313: }
314:
315: }
316:
317: private void createPredicateConstraintRow(
318: Composite constraintComposite, int row,
319: final SingleFieldConstraint c) {
320: GridData gd = new GridData(GridData.FILL_HORIZONTAL);
321: gd.horizontalSpan = 6;
322: addImage(constraintComposite, "icons/function_assets.gif");
323: formulaValueEditor(constraintComposite, c, gd);
324: addRemoveButton(constraintComposite, null, row,
325: "icons/delete_item_small.gif", false);
326: }
327:
328: private void createConnectives(Composite parent,
329: SingleFieldConstraint c) {
330: if (c.connectives != null && c.connectives.length > 0) {
331: for (int i = 0; i < c.connectives.length; i++) {
332: toolkit.createLabel(parent, ""); // dummy
333: toolkit.createLabel(parent, ""); // dummy
334: toolkit.createLabel(parent, ""); // dummy
335: ConnectiveConstraint con = c.connectives[i];
336: addRemoveConstraintAction(parent, c, con);
337: connectiveOperatorDropDown(parent, con, c.fieldName);
338: constraintValueEditor(parent, con, c.fieldName);
339:
340: }
341: }
342: }
343:
344: private void constraintValueEditor(Composite parent,
345: ISingleFieldConstraint c, String name) {
346: String type = this .modeller.getSuggestionCompletionEngine()
347: .getFieldType(pattern.factType, name);
348: new ConstraintValueEditor(parent, c, toolkit, modeller, type);
349: }
350:
351: private void addConnectiveAction(Composite constraintComposite,
352: final SingleFieldConstraint c) {
353: ImageHyperlink link = addImage(constraintComposite,
354: "icons/add_connective.gif");
355: link.setToolTipText("Add more options to this fields values.");
356: link.addHyperlinkListener(new IHyperlinkListener() {
357: public void linkActivated(HyperlinkEvent e) {
358: c.addNewConnective();
359: getModeller().reloadLhs();
360: getModeller().setDirty(true);
361: }
362:
363: public void linkEntered(HyperlinkEvent e) {
364: }
365:
366: public void linkExited(HyperlinkEvent e) {
367: }
368: });
369:
370: link.setLayoutData(new GridData(GridData.FILL_HORIZONTAL
371: | GridData.HORIZONTAL_ALIGN_BEGINNING));
372: }
373:
374: private void addRemoveButton(Composite constraintComposite,
375: final CompositeFieldConstraint parentConstraint,
376: final int row, String iconRef, boolean nested) {
377: if (nested) {
378: addNestedConstraintDeleteAction(constraintComposite,
379: parentConstraint, row, iconRef);
380: } else {
381: addRemoveFieldAction(constraintComposite, row, iconRef);
382: }
383:
384: }
385:
386: private void addNestedConstraintDeleteAction(
387: Composite constraintComposite,
388: final CompositeFieldConstraint parentConstraint,
389: final int row, String iconRef) {
390: ImageHyperlink delLink = addImage(constraintComposite, iconRef);
391: // "icons/delete_obj.gif");
392: delLink.addHyperlinkListener(new IHyperlinkListener() {
393: public void linkActivated(HyperlinkEvent e) {
394: MessageBox dialog = new MessageBox(Display.getCurrent()
395: .getActiveShell(), SWT.YES | SWT.NO
396: | SWT.ICON_WARNING);
397: dialog.setMessage("Remove this (nested) restriction.");
398: dialog
399: .setText("Remove this item from nested constraint?");
400: if (dialog.open() == SWT.YES) {
401: parentConstraint.removeConstraint(row);
402: getModeller().reloadLhs();
403: getModeller().setDirty(true);
404: }
405: }
406:
407: public void linkEntered(HyperlinkEvent e) {
408: }
409:
410: public void linkExited(HyperlinkEvent e) {
411: }
412: });
413: }
414:
415: private void addRemoveFieldAction(Composite constraintComposite,
416: final int currentRow, String iconRef) {
417: ImageHyperlink delLink = addImage(constraintComposite, iconRef);
418: delLink.setToolTipText("Remove this fieldconstraint");
419: delLink.addHyperlinkListener(new IHyperlinkListener() {
420: public void linkActivated(HyperlinkEvent e) {
421: MessageBox dialog = new MessageBox(Display.getCurrent()
422: .getActiveShell(), SWT.YES | SWT.NO
423: | SWT.ICON_WARNING);
424: dialog.setMessage("Remove this item?");
425: dialog.setText("Remove this item?");
426: if (dialog.open() == SWT.YES) {
427: pattern.removeConstraint(currentRow);
428: getModeller().reloadLhs();
429: getModeller().setDirty(true);
430: }
431: }
432:
433: public void linkEntered(HyperlinkEvent e) {
434: }
435:
436: public void linkExited(HyperlinkEvent e) {
437: }
438: });
439: delLink.setLayoutData(new GridData(GridData.FILL_HORIZONTAL
440: | GridData.HORIZONTAL_ALIGN_BEGINNING));
441: }
442:
443: private void addRemoveConstraintAction(Composite composite,
444: final SingleFieldConstraint constraint,
445: final ConnectiveConstraint connConstraint) {
446: ImageHyperlink delLink = addImage(composite,
447: "icons/delete_item_small.gif");
448: delLink.setToolTipText("Remove this field constraint");
449: delLink.addHyperlinkListener(new IHyperlinkListener() {
450: public void linkActivated(HyperlinkEvent e) {
451: MessageBox dialog = new MessageBox(Display.getCurrent()
452: .getActiveShell(), SWT.YES | SWT.NO
453: | SWT.ICON_WARNING);
454: dialog.setMessage("Remove this item?");
455: dialog.setText("Remove this item?");
456: if (dialog.open() == SWT.YES) {
457: ConnectiveConstraint[] connectives = constraint.connectives;
458: List nConnectives = new ArrayList();
459: for (int i = 0; i < connectives.length; i++) {
460: if (connectives[i] != connConstraint) {
461: nConnectives.add(connectives[i]);
462: }
463: }
464: constraint.connectives = (ConnectiveConstraint[]) nConnectives
465: .toArray(new ConnectiveConstraint[nConnectives
466: .size()]);
467:
468: getModeller().reloadLhs();
469: getModeller().setDirty(true);
470: }
471: }
472:
473: public void linkEntered(HyperlinkEvent e) {
474: }
475:
476: public void linkExited(HyperlinkEvent e) {
477: }
478: });
479: delLink.setLayoutData(new GridData(GridData.FILL_HORIZONTAL
480: | GridData.HORIZONTAL_ALIGN_END));
481: }
482:
483: /**
484: * This returns the pattern label.
485: */
486: private String getPatternLabel() {
487: if (pattern.boundName != null) {
488: return pattern.factType + " [" + pattern.boundName + "]";
489: }
490: return pattern.factType;
491: }
492:
493: private void operatorDropDown(Composite parent,
494: final SingleFieldConstraint c) {
495: String[] ops = getCompletions().getOperatorCompletions(
496: pattern.factType, c.fieldName);
497: final Combo box = new Combo(parent, SWT.SIMPLE | SWT.DROP_DOWN
498: | SWT.READ_ONLY);
499: for (int i = 0; i < ops.length; i++) {
500: String op = ops[i];
501: box.add(HumanReadable.getOperatorDisplayName(op));
502: if (op.equals(c.operator)) {
503: box.select(i);
504: }
505: }
506: GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
507: gridData.horizontalSpan = 2;
508: box.setLayoutData(gridData);
509: box.addListener(SWT.Selection, new Listener() {
510: public void handleEvent(Event event) {
511: c.operator = HumanReadable.getOperatorName(box
512: .getText());
513: getModeller().setDirty(true);
514: }
515: });
516: }
517:
518: private void connectiveOperatorDropDown(Composite parent,
519: final ConnectiveConstraint con, String fieldName) {
520: String[] ops = getCompletions()
521: .getConnectiveOperatorCompletions(pattern.factType,
522: fieldName);
523: final Combo box = new Combo(parent, SWT.SIMPLE | SWT.DROP_DOWN
524: | SWT.READ_ONLY);
525: for (int i = 0; i < ops.length; i++) {
526: String op = ops[i];
527: box.add(HumanReadable.getOperatorDisplayName(op));
528: if (op.equals(con.operator)) {
529: box.select(i);
530: }
531: }
532: GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
533: gridData.horizontalSpan = 2;
534: box.setLayoutData(gridData);
535: box.addModifyListener(new ModifyListener() {
536: public void modifyText(ModifyEvent e) {
537: con.operator = HumanReadable.getOperatorName(box
538: .getText());
539: getModeller().setDirty(true);
540:
541: }
542: });
543: }
544:
545: private void formulaValueEditor(Composite parent,
546: final ISingleFieldConstraint c, GridData gd) {
547:
548: final Text box = toolkit.createText(parent, "");
549:
550: if (c.value != null) {
551: box.setText(c.value);
552: }
553:
554: gd.grabExcessHorizontalSpace = true;
555: gd.minimumWidth = 100;
556: box.setLayoutData(gd);
557:
558: box.addModifyListener(new ModifyListener() {
559: public void modifyText(ModifyEvent e) {
560: c.value = box.getText();
561: getModeller().setDirty(true);
562: }
563: });
564: }
565:
566: private void deleteBindedFact() {
567: List newPatterns = new ArrayList();
568: for (int i = 0; i < parentPattern.patterns.length; i++) {
569: if (parentPattern.patterns[i] != pattern) {
570: newPatterns.add(parentPattern.patterns[i]);
571: }
572: }
573: parentPattern.patterns = (FactPattern[]) newPatterns
574: .toArray(new FactPattern[newPatterns.size()]);
575: getModeller().reloadLhs();
576: }
577:
578: private SuggestionCompletionEngine getCompletions() {
579: return getModeller().getSuggestionCompletionEngine();
580: }
581:
582: }
|