public RuleAttributeWidget(
      final RuleModeller parent, final RuleModel model, final boolean isReadOnly) {
    this.parent = parent;
    this.model = model;
    FormStyleLayout layout = new FormStyleLayout();
    // Adding metadata here, seems redundant to add a new widget for metadata. Model does handle
    // meta data separate.
    RuleMetadata[] meta = model.metadataList;
    if (meta.length > 0) {
      HorizontalPanel hp = new HorizontalPanel();
      hp.add(new SmallLabel(Constants.INSTANCE.Metadata2()));
      layout.addRow(hp);
    }
    for (int i = 0; i < meta.length; i++) {
      RuleMetadata rmd = meta[i];
      layout.addAttribute(rmd.getAttributeName(), getEditorWidget(rmd, i, isReadOnly));
    }
    RuleAttribute[] attrs = model.attributes;
    if (attrs.length > 0) {
      HorizontalPanel hp = new HorizontalPanel();
      hp.add(new SmallLabel(Constants.INSTANCE.Attributes1()));
      layout.addRow(hp);
    }
    for (int i = 0; i < attrs.length; i++) {
      RuleAttribute at = attrs[i];
      layout.addAttribute(at.getAttributeName(), getEditorWidget(at, i, isReadOnly));
    }

    initWidget(layout);
  }
  private TextBox textBoxEditor(final RuleAttribute at, final boolean isReadOnly) {
    final TextBox box = new TextBox();
    box.setEnabled(!isReadOnly);
    box.setVisibleLength((at.getValue().length() < 3) ? 3 : at.getValue().length());
    box.setText(at.getValue());
    box.addChangeHandler(
        new ChangeHandler() {
          public void onChange(ChangeEvent event) {
            at.setValue(box.getText());
          }
        });

    if (at.getAttributeName().equals(DATE_EFFECTIVE_ATTR)
        || at.getAttributeName().equals(DATE_EXPIRES_ATTR)) {
      if (at.getValue() == null || "".equals(at.getValue())) {
        box.setText("");
      }

      box.setVisibleLength(10);
    }

    box.addKeyUpHandler(
        new KeyUpHandler() {
          public void onKeyUp(KeyUpEvent event) {
            int length = box.getText().length();
            box.setVisibleLength(length > 0 ? length : 1);
          }
        });
    return box;
  }
  private Widget checkBoxEditor(final RuleAttribute at, final boolean isReadOnly) {
    final CheckBox box = new CheckBox();
    box.setEnabled(!isReadOnly);
    if (at.getValue() == null || at.getValue().isEmpty()) {
      box.setValue(false);
      at.setValue(FALSE_VALUE);
    } else {
      box.setValue((at.getValue().equals(TRUE_VALUE)));
    }

    box.addClickHandler(
        new ClickHandler() {
          public void onClick(ClickEvent event) {
            at.setValue((box.getValue()) ? TRUE_VALUE : FALSE_VALUE);
          }
        });
    return box;
  }
  private Widget getEditorWidget(final RuleAttribute at, final int idx, final boolean isReadOnly) {
    Widget editor = null;

    final String attributeName = at.getAttributeName();
    if (attributeName.equals(RULEFLOW_GROUP_ATTR)
        || attributeName.equals(AGENDA_GROUP_ATTR)
        || attributeName.equals(ACTIVATION_GROUP_ATTR)
        || attributeName.equals(TIMER_ATTR)
        || attributeName.equals(CALENDARS_ATTR)) {
      final TextBox tb = TextBoxFactory.getTextBox(DataType.TYPE_STRING);
      tb.setValue(at.getValue());
      tb.setEnabled(!isReadOnly);
      if (!isReadOnly) {
        tb.addValueChangeHandler(
            new ValueChangeHandler<String>() {

              public void onValueChange(ValueChangeEvent<String> event) {
                at.setValue(tb.getValue());
              }
            });
      }
      editor = tb;

    } else if (attributeName.equals(SALIENCE_ATTR)) {
      final TextBox tb = TextBoxFactory.getTextBox(DataType.TYPE_NUMERIC_INTEGER);
      tb.setValue(at.getValue());
      tb.setEnabled(!isReadOnly);
      if (!isReadOnly) {
        tb.addValueChangeHandler(
            new ValueChangeHandler<String>() {

              public void onValueChange(ValueChangeEvent<String> event) {
                at.setValue(tb.getValue());
              }
            });
      }
      editor = tb;

    } else if (attributeName.equals(DURATION_ATTR)) {
      final TextBox tb = TextBoxFactory.getTextBox(DataType.TYPE_NUMERIC_LONG);
      tb.setValue(at.getValue());
      tb.setEnabled(!isReadOnly);
      if (!isReadOnly) {
        tb.addValueChangeHandler(
            new ValueChangeHandler<String>() {

              public void onValueChange(ValueChangeEvent<String> event) {
                at.setValue(tb.getValue());
              }
            });
      }
      editor = tb;

    } else if (attributeName.equals(NO_LOOP_ATTR)
        || attributeName.equals(LOCK_ON_ACTIVE_ATTR)
        || attributeName.equals(AUTO_FOCUS_ATTR)
        || attributeName.equals(ENABLED_ATTR)) {
      editor = checkBoxEditor(at, isReadOnly);

    } else if (attributeName.equals(DATE_EFFECTIVE_ATTR)
        || attributeName.equals(DATE_EXPIRES_ATTR)) {
      if (isReadOnly) {
        final TextBox tb = TextBoxFactory.getTextBox(DataType.TYPE_STRING);
        tb.setValue(at.getValue());
        tb.setEnabled(false);
      } else {
        final PopupDatePicker dp = new PopupDatePicker(false);
        dp.setValue(at.getValue());
        dp.addValueChangeHandler(
            new ValueChangeHandler<Date>() {

              public void onValueChange(ValueChangeEvent<Date> event) {
                at.setValue(PopupDatePicker.convertToString(event));
              }
            });
        editor = dp;
      }
    } else if (attributeName.equals(DIALECT_ATTR)) {
      final ListBox lb = new ListBox();
      lb.addItem(DIALECTS[0]);
      lb.addItem(DIALECTS[1]);
      lb.setEnabled(!isReadOnly);
      if (!isReadOnly) {
        lb.addChangeHandler(
            new ChangeHandler() {
              @Override
              public void onChange(ChangeEvent event) {
                final int selectedIndex = lb.getSelectedIndex();
                if (selectedIndex < 0) {
                  return;
                }
                at.setValue(lb.getValue(selectedIndex));
              }
            });
      }
      if (at.getValue() == null || at.getValue().isEmpty()) {
        lb.setSelectedIndex(1);
        at.setValue(DIALECTS[1]);
      } else if (at.getValue().equals(DIALECTS[0])) {
        lb.setSelectedIndex(0);
      } else if (at.getValue().equals(DIALECTS[1])) {
        lb.setSelectedIndex(1);
      } else {
        lb.setSelectedIndex(1);
        at.setValue(DIALECTS[1]);
      }
      editor = lb;
    }

    DirtyableHorizontalPane horiz = new DirtyableHorizontalPane();
    if (editor != null) {
      horiz.add(editor);
      if (!isReadOnly) {
        horiz.add(getRemoveIcon(idx));
      }
    }

    return horiz;
  }