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 Widget getEditorWidget(final RuleMetadata rm, final int idx, final boolean isReadOnly) {
    Widget editor;

    if (rm.getAttributeName().equals(LOCK_LHS) || rm.getAttributeName().equals(LOCK_RHS)) {
      editor =
          new InfoPopup(Constants.INSTANCE.FrozenAreas(), Constants.INSTANCE.FrozenExplanation());
    } else {
      editor = textBoxEditor(rm, isReadOnly);
    }

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

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

    box.addKeyUpHandler(
        new KeyUpHandler() {
          public void onKeyUp(KeyUpEvent event) {
            box.setVisibleLength(box.getText().length());
          }
        });
    return box;
  }