0

I am looking for component for tree representation of table field.

What I am looking for is table with columns but with option with collapsing of cell like tree.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Marko Zadravec
  • 8,298
  • 10
  • 55
  • 97
  • Out-of-the-box there is no tree table in the Scout model. Some projects have managed to misuse the table widget (to expand and collapse rows, like in a tree table). I will take the time to share the solution (because the question comes again and again) – Jmini Dec 10 '14 at 08:37

1 Answers1

2

There is no built in Tree Table in Scout, but it is possible to make misuse the Table to make it look like a tree table. I just proposed an implementation in this Gist.

AbstractTreeTable is a table template that adds 2 columns in the table:

  • KeyColumn: a primary key for the table
  • ParentKeyColumn: the key of the parent row or null if the row is at the tree root.

AbstractTreeTable handles the collapsed state or not of each node row. It also decorates the first column (indentation and [+] &[-] marker on the nodes). It handle the row action (execRowAction(..)).

If you use this in a table page, it is recommended to use a TablePageData and not Object[][]. If you use this in a table fields, it only works if the table field is using a bean based table data.

My prototype could be improved:

  • No sort support (for one column, it is possible to define how the row needs to be sorted: if they have different parent -> comparison of the 2 parent values; if they have the same parent -> cell value).
  • I did not test how the content behaves if you try to apply filter on it (could also be improved).
  • Performance with a lot of rows needs to be checked.
  • execMethods should not be used at template level

Examples:

Cars TreeTable with Eclipse Scout

@Order(10.0)
@FormData(value = AbstractTableFieldBeanData.class, sdkCommand = SdkCommand.USE, defaultSubtypeSdkCommand = DefaultSubtypeSdkCommand.CREATE)
public class CarsTableField extends AbstractTableField<CarsTableField.Table> {

  @Override
  protected int getConfiguredGridH() {
    return 8;
  }

  @Override
  protected int getConfiguredGridW() {
    return 2;
  }

  @Override
  protected String getConfiguredLabel() {
    return TEXTS.get("Cars");
  }

  @Order(10.0)
  public class Table extends AbstractTreeTable {

    /**
     * @return the PriceFromColumn
     */
    public PriceFromColumn getPriceFromColumn() {
      return getColumnSet().getColumnByClass(PriceFromColumn.class);
    }

    /**
     * @return the NameColumn
     */
    public NameColumn getNameColumn() {
      return getColumnSet().getColumnByClass(NameColumn.class);
    }

    @Override
    protected boolean execIsNode(ITableRow row) {
      return getParentKeyColumn().getValue(row) == null;
    }

    @Override
    protected void execDecorateRow(ITableRow row) throws ProcessingException {
      if (execIsNode(row)) {
        row.setFont(FontSpec.parse("BOLD"));
      }
    }

    @Override
    public void importFromTableBeanData(AbstractTableFieldBeanData source) throws ProcessingException {
      super.importFromTableBeanData(source);

      toggleExpandedState(getRows());
    }

    @Order(10.0)
    public class NameColumn extends AbstractStringColumn {

      @Override
      protected String getConfiguredHeaderText() {
        return TEXTS.get("CarModel");
      }
    }

    @Order(20.0)
    public class PriceFromColumn extends AbstractIntegerColumn {

      @Override
      protected String getConfiguredHeaderText() {
        return TEXTS.get("PriceFrom");
      }
    }
  }
}

Files Tree Table with Eclipse Scout

@Order(10.0)
@FormData(value = AbstractTableFieldBeanData.class, sdkCommand = SdkCommand.USE, defaultSubtypeSdkCommand = DefaultSubtypeSdkCommand.CREATE)
public class FilesTableField extends AbstractTableField<FilesTableField.Table> {

  @Override
  protected int getConfiguredGridH() {
    return 8;
  }

  @Override
  protected int getConfiguredGridW() {
    return 2;
  }

  @Override
  protected String getConfiguredLabel() {
    return TEXTS.get("Files");
  }

  @Order(10.0)
  public class Table extends AbstractTreeTable {

    @Override
    protected boolean execIsNode(ITableRow row) {
      Long type = getTypeColumn().getValue(row);
      return FileTypeCodeType.FolderCode.ID.equals(type);
    }

    @Override
    public void importFromTableBeanData(AbstractTableFieldBeanData source) throws ProcessingException {
      super.importFromTableBeanData(source);

      toggleExpandedState(getRows());
    }

    @Override
    protected void execDecorateRow(ITableRow row) throws ProcessingException {
      Long type = getTypeColumn().getValue(row);
      if (FileTypeCodeType.FolderCode.ID.equals(type)) {
        row.setIconId(Icons.FOLDER);
      }
      else if (FileTypeCodeType.FileCode.ID.equals(type)) {
        row.setIconId(Icons.DOCUMENT);
      }
      else if (FileTypeCodeType.EmailCode.ID.equals(type)) {
        row.setIconId(Icons.EMAIL);
      }
      else if (FileTypeCodeType.VCardCode.ID.equals(type)) {
        row.setIconId(Icons.VCARD);
      }
    }

    /**
     * @return the TypeColumn
     */
    public TypeColumn getTypeColumn() {
      return getColumnSet().getColumnByClass(TypeColumn.class);
    }

    /**
     * @return the ModifiedDateColumn
     */
    public ModifiedDateColumn getModifiedDateColumn() {
      return getColumnSet().getColumnByClass(ModifiedDateColumn.class);
    }

    /**
     * @return the NameColumn
     */
    public NameColumn getNameColumn() {
      return getColumnSet().getColumnByClass(NameColumn.class);
    }

    @Order(20.0)
    public class NameColumn extends AbstractStringColumn {

      @Override
      protected String getConfiguredHeaderText() {
        return TEXTS.get("Name");
      }

      @Override
      protected int getConfiguredWidth() {
        return 400;
      }
    }

    @Order(30.0)
    public class ModifiedDateColumn extends AbstractDateColumn {

      @Override
      protected String getConfiguredFormat() {
        return "dd.MM.yyyy hh:mm";
      }

      @Override
      protected String getConfiguredHeaderText() {
        return TEXTS.get("DateModified");
      }

      @Override
      protected int getConfiguredWidth() {
        return 200;
      }
    }

    @Order(40.0)
    public class TypeColumn extends AbstractSmartColumn<Long> {

      @Override
      protected Class<? extends ICodeType<?, Long>> getConfiguredCodeType() {
        return FileTypeCodeType.class;
      }

      @Override
      protected String getConfiguredHeaderText() {
        return TEXTS.get("Type");
      }

      @Override
      protected int getConfiguredWidth() {
        return 200;
      }
    }
  }
}

Of course, this is only a workaround for the real problem: scout is missing a representation for tree-tables at model level. If there was something like that, it would be possible to use real tree table widgets in the different UIs.

Jmini
  • 9,189
  • 2
  • 55
  • 77
  • Very important question. I follow your example and download templates, but now I have one problem. Form data for AbstractTreeTable are not generated and in table field all other columns are inside, except those columns from tree table. How to fix this? – Marko Zadravec Feb 06 '15 at 08:22
  • It only works if the table field is using a [bean based table data](https://wiki.eclipse.org/Scout/Concepts/TableData#Bean_based_TableData) because array based table data does not support Table inheritance. – Jmini Feb 06 '15 at 08:33
  • I don't quite understand this. I thought that if I use form data, this is bean based table data. In my Table Field I have like this : @FormData(value = AbstractPurchasePriceHistoryTableData.class, sdkCommand = FormData.SdkCommand.USE, defaultSubtypeSdkCommand = FormData.DefaultSubtypeSdkCommand.CREATE) and in tree table I have @FormData(value = AbstractTreeTableData.class, sdkCommand = FormData.SdkCommand.USE, defaultSubtypeSdkCommand = FormData.DefaultSubtypeSdkCommand.CREATE) but AbstractTreeTableData.class is always empty. – Marko Zadravec Feb 06 '15 at 08:38
  • `@FormData` annotation is always for the `TableField` class (It is possible to define something at each hierarchy level). The first level is `AbstractTableField` (in the scout jar). The `TableField` in your form is directly extending this class or you have an other Abstract class (aka a template) in the class inheritance graph. No need to have a `@FormData` on the `Table` class; the SDK do not read it. Depending on your case, the parameters of the annotation are not the same. Several example are provided on the wiki page. Feel free to open an othre question to discuss this in detail. – Jmini Feb 06 '15 at 09:18
  • I ask another question http://stackoverflow.com/questions/28362697/column-in-extended-table-are-not-presented-in-form-data-on-eclipse-scout – Marko Zadravec Feb 06 '15 at 09:39