Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » Eclipse Scout » Table and GroupBox for details on row selection
Table and GroupBox for details on row selection [message #1172004] Tue, 05 November 2013 16:35 Go to next message
Jeremie Bresson is currently offline Jeremie BressonFriend
Messages: 1252
Registered: October 2011
Senior Member
Assume you have this use case:
A table fields contains some rows. When a row is selected, some detail information are displayed in a Group Box near the table field.

I have used this pattern:
* I extracted my DetailGroupBox in a Template => AbstractDetailGroupBox.
* The SDK generate the AbstractDetailGroupBoxData corresponding to the AbstractDetailGroupBox template.
* In the shared plugin in created a concrete class: MyDetailGroupBoxData (extends AbstractDetailGroupBoxData). [this is an example: in the real world I do not use "My" as suffix]
* In the table, I add a not-displayable column: DetailColumn (extends AbstractColumn<MyDetailGroupBoxData>)
* On the DetailBox I add @FormData(sdkCommand = IGNORE) => Because I want that from the server, the data are put in the TableData of the FormData instead of directly in the formData.

Now I have following Form Tree:

Form
-- MainBox
----TableField
------Table
--------NameColumn: String
--------DetailColumn: Column<MyDetailGroupBoxData>
----DetailBox: GroupBox with FormData IGNORE command


In the execRowsSelected I want to do the DetailBox handling.

I was assuming that is was possible to do:
MyDatailGroupBoxData source = getTable().getDetailColumn().getValue(row);
getDetailGroupBox().importFormFieldData(source, false);


BUT the implementation is empty!!! For my DetailBox the method is:
org.eclipse.scout.rt.client.ui.form.fields.AbstractFormField.importFormFieldData(AbstractFormFieldData, boolean)

This is probably OK in the generic case, but it means that I need to do it by myself.
Override importFormFieldData(..) in DetailBox.

I was thinking: why can't I reuse the logic in org.eclipse.scout.rt.client.ui.form.AbstractForm.importFormData(..)
Re: Table and GroupBox for details on row selection [message #1173662 is a reply to message #1172004] Wed, 06 November 2013 17:24 Go to previous messageGo to next message
Jeremie Bresson is currently offline Jeremie BressonFriend
Messages: 1252
Registered: October 2011
Senior Member
I have copy-pasted and adapted the code I needed to be able to write something like this:

@Order(20.0)
@FormData(sdkCommand = SdkCommand.IGNORE)
public class DetailBox extends AbstractDetailBox {
  @Override
  public void importFormFieldData(AbstractFormFieldData source, boolean valueChangeTriggersEnabled) throws ProcessingException {
    FormDataUtility2.importFormFieldData(this, source, valueChangeTriggersEnabled, null, null);
  }

  @Override
  public void exportFormFieldData(AbstractFormFieldData target) throws ProcessingException {
    FormDataUtility2.exportFormData(this, target);
  }
}


For me this code should goes in the FormDataUtility and should be mutualized between importFormData() on the form and importFormFieldData() in the GroupBox.

The current implementation of importFormFieldData() should stay empty in GroupBox, but for people who needs it, it should be simple to activate import/export in a GroupBox.
Re: Table and GroupBox for details on row selection [message #1288221 is a reply to message #1173662] Tue, 08 April 2014 11:26 Go to previous messageGo to next message
Jeremie Bresson is currently offline Jeremie BressonFriend
Messages: 1252
Registered: October 2011
Senior Member
Related to this pattern, for the Table implementation (NameColumn and DetailColumn) see also this thread about @ColumnData(IGNORE).

The annotation should be used on NameColumn in this example.
Re: Table and GroupBox for details on row selection [message #1295232 is a reply to message #1288221] Mon, 14 April 2014 05:23 Go to previous messageGo to next message
Jeremie Bresson is currently offline Jeremie BressonFriend
Messages: 1252
Registered: October 2011
Senior Member
I had the chance to continue to work on this pattern.

For such a use case, the default Scout approach would be to use an editable table. But if the Details you want to display are too important, I think that this is how you can do it in a scout application.

Here the solution I developed for master table row and detail group box:

By default the "Detail" group box (containing the edition zone for the selected row) is disabled:

index.php/fa/17914/0/

On click, the values are imported:

index.php/fa/17915/0/

It is possible to define a field that will request the focus [in this case getFirstNameField().requestFocus()]

When a value is edited, it is updated in the table when the focus changed (similar to execChangedValue):

index.php/fa/17916/0/

index.php/fa/17917/0/
Re: Table and GroupBox for details on row selection [message #1295233 is a reply to message #1295232] Mon, 14 April 2014 05:25 Go to previous messageGo to next message
Jeremie Bresson is currently offline Jeremie BressonFriend
Messages: 1252
Registered: October 2011
Senior Member
Adding a row is possible with the Empty Space Menu "New":

index.php/fa/17918/0/


Like in the edit case, the first field gets the focus.

index.php/fa/17919/0/

If no value has been set in any of the edit fields when the selection changes in the table, the empty row is removed (because it is also invisible for the user).


There is also a menu to delete a row:

index.php/fa/17920/0/



I have an implementation relying on templates (generic enough to be reusable). If someone is interested I could share the code somewhere.

Do not hesitate to discuss a point or to send feedback...

.
Re: Table and GroupBox for details on row selection [message #1297527 is a reply to message #1295233] Tue, 15 April 2014 18:53 Go to previous messageGo to next message
Jeremie Bresson is currently offline Jeremie BressonFriend
Messages: 1252
Registered: October 2011
Senior Member
I was asked to present how this pattern is implemented. If you use it, please give us feedback. Maybe support for this pattern (Scout RT and Scout SDK) will be included in the next release of Eclipse Scout.

Because of the lack of support in the current Scout Version, implementing this pattern is not as easy as other task that you can do with the Scout SDK. You should have some experience with Scout and some Java Knowledge.

I have tested this with Scout Luna M6.


1/ Prepare your form:

Like for any other form, you can use the SDK to make your form (MyMasterDetailForm).

You will need at least:
- A Table Field (that will be the master Table).
- A GroupBox containing the detail that will be displayed.

In your table field, you can already create a column called ContentColumn. For the moment this column can have the type ObjectColumn. (I put this column as first column, but this does not maters).

In my example the other columns are simple String Column because I want to handle string fields (first name and last name). It is possible to imagine other types (SmartColumn, IntegerColumn). It is important that the type match the type of the fields in the detail box.

To keep this example simple, the detail box only contains 3 String fields. Create the detail box (in my example it is named SelectedPersonDetailBox) and add the fields
In the detail box you can imagine the content you want. (Multiple group boxes, other fields, even a table...)


2/ Create a template to obtain the DetailBoxData

We need a java object to hold the content of the detail box for each row.
You can work with a plain Java Bean, but in this case, you will need to write the import/export from the bean into the detail box (SelectedPersonDetailBox).

An easiest way is to use the Scout SDK functionality (exactly like for FormData). This way your java object to hold the Data is keep in sync with the detail box.

Select your GroupBox in the Scout Explorer and create a template: AbstractSelectedPersonDetailBox.

Important is to let following options checked:
- "use Template for 'SelectedPersonDetailBox'
- "create external formData".

This way you obtain an "AbstractSelectedPersonDetailBoxData" in the shared plugin. Because this class is created abstract by the SDK you need to create a child class: PersonBoxData
public class PersonBoxData extends AbstractSelectedPersonDetailBoxData {
  private static final long serialVersionUID = 1L;

}


In the MyFormData (corresponding to MyForm) you do not want to set data in the server for the SelectedPersonDetailBox (because what will be displayed in the fields comes from the selection in the table field). You can add @FormData(sdkCommand = SdkCommand.IGNORE) on the field :
@Order(20.0)
@FormData(sdkCommand = SdkCommand.IGNORE)
public class SelectedPersonDetailBox extends AbstractSelectedPersonDetailBox {

}



3/ Use @ColumnData(Ignore)

The idea of this pattern is that the data are stored in a not-displayable column (the ContentColumn described in step 1). If you have not created this column, do so now.

We do not want somebody to set a value for the column FirstNameColumn and LastNameColumn in the server.

Do what is described in this forum thread:
- Make the 2 getters for the 2 columns (FirstName and LastName) protected instead of public.
- Add @ColumnData(SdkColumnCommand.IGNORE) on the 2 columns
- Change the type of the ContentColumn: AbstractContentColumn<T> where T is PersonBoxData.
- Implement the requested updateTableColumns(ITableRow, PersonBoxData) method. This method is responsible for the update of the columns that are ignored in the formData.

@Order(10.0)
public class ContentColumn extends AbstractContentColumn<PersonBoxData> {

  @Override
  protected boolean getConfiguredDisplayable() {
    return false;
  }

  @Override
  protected void updateTableColumns(ITableRow r, PersonBoxData data) throws ProcessingException {
    getFirstNameColumn().setValue(r, data.getFirstName().getValue());
    getLastNameColumn().setValue(r, data.getLastName().getValue());
  }
}



4a/ Change the type of AbstractSelectedPersonDetailBox to AbstractSelectedGroupBox<PersonBoxData>

We need to change the type of AbstractSelectedPersonDetailBox: instead of AbstractGroupBox set the type to AbstractSelectedGroupBox<PersonBoxData>

In AbstractSelectedPersonDetailBox you need to implement createEmptyBoxData(). It will be used by the framework to clear the selection in the detail box and for new rows:
@Override
public PersonBoxData createEmptyBoxData() {
  PersonBoxData boxData = new PersonBoxData();
  boxData.getFirstName().setValue(null);
  boxData.getLastName().setValue(null);
  boxData.getComments().setValue(null);
  return boxData;
}


Notice that you need to set the value to null (or at least setValueSet() with true as parameter). It is possible to use a Utility function to do so on each fieldData instead of having to call them individually.

In SelectedPersonDetailBox in the form you need to implement provideColumn to link the group box with the column.
@Override
public AbstractDetailBoxColumn<PersonBoxData> provideColumn() {
  return getPersonTableField().getTable().getContentColumn();
}

NB: FormDataClientUtility is the new name of FormDataUtility2 attached in this forum thread.


4b/ Change the type of the content Column to AbstractDetailBoxColumn<PersonBoxData>

Instead of AbstractContentColumn the ContentColumn needs to be from type AbstractDetailBoxColumn<PersonBoxData>.

To link the column with the group box you need to implement provideGroupBox():
@Override
public AbstractSelectedGroupBox<PersonBoxData> provideGroupBox() {
  return getSelectedPersonDetailBox();
}



4c/ Change the type of the Table in the TableField

Instead of AbstractExtensibleTable the Table in the PersonTableField needs tob e from type AbstractTableWithDetailBox. This table will add the new and delete menu and handle the import of the data in the detail GroupBox.

You need to implement provideColumns that need to return the list of the AbstractDetailBoxColumn in the table. These columns will be notified.
@Override
protected List<? extends AbstractDetailBoxColumn<?>> provideColumns() {
  return Collections.singletonList(getTable().getContentColumn());
}



4d/ Change the type of the TableField

In order for the Step 3 to work we need to work with bean based table data.

In the step 1 if your table field has the type AbstractTableField (default) change this to AbstractTableWithDetailBoxField. It contains the appropriate @FormData annotation to use bean based table data.


5/ Advanced configuration:

In AbstractSelectedPersonDetailBox you can implement:

* execStartGroupBoxEdit that will be called when a row is selected and the details data have been imported:

@Override
public void execStartGroupBoxEdit() {
  getFirstNameField().requestFocus();
}


* execUpdateGroupBoxFields: where you can define your own logic to enable or disable the fields. For example:
@Override
public void execUpdateGroupBoxFields(boolean isEditing) {
  getFirstNameField().setEnabled(isEditing);
  getFirstNameField().setMandatory(isEditing);
  
  getLastNameField().setEnabled(isEditing);
  getLastNameField().setMandatory(isEditing);

  getCommentsField().setEnabled(isEditing);
}

NB: you need to have also validation rules on the table. Having them on the field is not enough, because the user can leave the edit mode and the form will be valid even if the values in the different rows are not set.


A/ Appendix: server implementation

I recommend to test step by step your form (between each step). Here is how the server method can looks like at the end:
@Override
public MyMasterDetailFormData load(MyMasterDetailFormData formData) {
  addPersonRow(formData, "Bob", "Johnson", "Lorem ipsum");
  addPersonRow(formData, "Alan", "Smith", "");
  return formData;
}

private void addPersonRow(MyMasterDetailFormData formData, String firstName, String lastName, String comments) {
  PersonBoxData personBoxData = new PersonBoxData();
  personBoxData.getFirstName().setValue(firstName);
  personBoxData.getLastName().setValue(lastName);
  personBoxData.getComments().setValue(comments);

  PersonTableRowData row = formData.getPersonTable().addRow();
  row.setContent(personBoxData);
}


Feel free to ask questions.

[Updated on: Wed, 16 April 2014 07:05]

Report message to a moderator

Re: Table and GroupBox for details on row selection [message #1431445 is a reply to message #1297527] Thu, 25 September 2014 17:54 Go to previous messageGo to next message
Jeremie Bresson is currently offline Jeremie BressonFriend
Messages: 1252
Registered: October 2011
Senior Member
We are using a similar pattern in our current project. The first tests show a problem that is not solved in the solution mentioned here:

A change of selection in the table should not mark the form as dirty (see Form lifecycle and unsaved changes in particular for more information). This is something I did not take into account.

Each field has a contribution to the unsaved changes state. I have tried a first solution where I add to each field in my "edit the selected row" following code:
@Override
protected boolean execIsSaveNeeded() throws ProcessingException {
  return false;
}

This tells that those fields never contribute something to the global state checking if the form has unsaved changes. This should be the responsibility of the table (and the code I have needs some fine tuning in order to work in all cases).

In my project we also have a lot of server calculation and the problem is not only with this pattern but with a lot of values coming from the server (information computed by the server and displayed to the user in the form). I have also a flag isFormDataImporting() on each field. So I will check if I can use this information to influence the whole "unsaved changes" logic.
Re: Table and GroupBox for details on row selection [message #1578089 is a reply to message #1431445] Thu, 22 January 2015 07:17 Go to previous messageGo to next message
Jeremie Bresson is currently offline Jeremie BressonFriend
Messages: 1252
Registered: October 2011
Senior Member
This week I had the opportunity to work on this pattern again.
Code is in the AbstractTableWithDetail gist.

We have decided to use an easier pattern. We have in the table a hidden column: DetailDataColumn. This column stores the content of the detail box in a POJO (a simple java bean). This means that in comparison to the previous discussed pattern, we need to do the mapping "POJO" <=> "Scout Fields in the detail box" by hand.

We introduce 3 new methods:
* execSelectionNo(): is called by the table when there is no selection
* execSelectionNew(ITableRow): is called by the table when there is one new selection (the TableRow passed as parameter). You should use this method to populate your detail box.
* execSelectionSave(ITableRow): is called by the table, when you need to collect the value contained in the detail box and save them back into the

The code is spitted into an abstract Table (a template) and a Form using this table. Feel free to reuse this in your application.

index.php/fa/20540/0/

index.php/fa/20541/0/

In my opinion the biggest limitation of this pattern is that the data are collected when the selection changes and not when the value changes in the field. This is a problem if you use the detail box to update values of the visible columns ("first name" and "last name" in my case).

The provided code requires Bug 455478 (meaning Scout Version >= 4.2). If you are on an older version of Scout, you just need to remove the generic parameter <DETAIL_TYPE> from AbstractTableWithDetail and switch back to an ObjectColumn for the DetailDataColumn. The getConfiguredDetailDataType() method is also not necessary without the generic parameter. Of course if you use an ObjectColumn you will need to cast the value contained in the column.
Re: Table and GroupBox for details on row selection [message #1720815 is a reply to message #1578089] Thu, 21 January 2016 09:06 Go to previous message
Jeremie Bresson is currently offline Jeremie BressonFriend
Messages: 1252
Registered: October 2011
Senior Member
Not completely related to this topic, I would like to add some input about the possibility to import a GroupBoxData in a GroupBox

I have seen this pattern used in one other project since this post. The use case is not only the one described here, but the possibility to import the GroupBoxData is the common denominator.

Today the same question was asked on StackOverflow:
http://stackoverflow.com/questions/34874854/eclipse-scout-neon-importformfielddata-in-template

One important point we have observed:
If you implement the pattern as described here, when you import a formData the ValueFields contained in each GroupBoxData will be imported twice.
If you need both approaches (importing a GroupBoxData and a FormData) you need to exclude the concerned GroupBox Fields (in this case all Fields extending AbstractDetailGroupBox) from the list when the formData is imported. This can easily be done in your AbstractMyProjectForm (that extends AbstractForm and that is used everywhere).

I am not sure if the feedback I got in 2013 "Importing a GroupBoxData in a GroupBox Field is not a common use-case" is still valid.
Previous Topic:Problem with the @Replace annotation
Next Topic:[Neon]ValidationRule
Goto Forum:
  


Current Time: Thu Apr 18 04:03:06 GMT 2024

Powered by FUDForum. Page generated in 0.02676 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top