Skip to content

Instantly share code, notes, and snippets.

@jmini
Created January 22, 2015 07:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jmini/31b768f00e9a48da3f48 to your computer and use it in GitHub Desktop.
Save jmini/31b768f00e9a48da3f48 to your computer and use it in GitHub Desktop.
AbstractTableWithDetail template: implementation of the master/detail pattern.
/*******************************************************************************
* Copyright (c) 2015 BSI Business Systems Integration AG.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* BSI Business Systems Integration AG - initial API and implementation
******************************************************************************/
import java.util.List;
import org.eclipse.scout.commons.annotations.Order;
import org.eclipse.scout.commons.exception.ProcessingException;
import org.eclipse.scout.rt.client.ui.basic.table.AbstractTable;
import org.eclipse.scout.rt.client.ui.basic.table.ITableRow;
import org.eclipse.scout.rt.client.ui.basic.table.columns.AbstractColumn;
import org.eclipse.scout.rt.shared.data.form.fields.tablefield.AbstractTableFieldBeanData;
/**
* Specific {@link AbstractTable} to support master/detail pattern
*/
public abstract class AbstractTableWithDetail<DETAIL_TYPE> extends AbstractTable {
private ITableRow m_previousSelection;
protected abstract Class<DETAIL_TYPE> getConfiguredDetailDataType();
public DetailDataColumn getDetailDataColumn() {
@SuppressWarnings("unchecked")
DetailDataColumn column = getColumnSet().getColumnByClass(DetailDataColumn.class);
return column;
}
@Order(0.0)
public class DetailDataColumn extends AbstractColumn<DETAIL_TYPE> {
@Override
protected boolean getConfiguredDisplayable() {
return false;
}
@Override
public Class<DETAIL_TYPE> getDataType() {
return getConfiguredDetailDataType();
}
}
@Override
protected boolean getConfiguredMultiSelect() {
return false;
}
@Override
protected final void execRowsSelected(List<? extends ITableRow> rows) throws ProcessingException {
savePreviousSelection();
if (rows.size() == 1) {
ITableRow selection = rows.get(0);
execSelectionNew(selection);
m_previousSelection = selection;
}
else {
execSelectionNo();
m_previousSelection = null;
}
super.execRowsSelected(rows);
}
@Override
public void exportToTableBeanData(AbstractTableFieldBeanData target) throws ProcessingException {
savePreviousSelection();
super.exportToTableBeanData(target);
}
@Override
public void importFromTableBeanData(AbstractTableFieldBeanData source) throws ProcessingException {
execSelectionNo();
super.importFromTableBeanData(source);
}
private void savePreviousSelection() throws ProcessingException {
if (m_previousSelection != null) {
boolean changed = execSelectionSave(m_previousSelection);
if (changed && m_previousSelection.getStatus() == ITableRow.STATUS_NON_CHANGED) {
m_previousSelection.setStatusUpdated();
}
m_previousSelection = null;
}
}
/**
* Called when the content of the detail group box needs to be put in the {@link #getDetailDataColumn()} for the
* selectionRow.
*
* @param selectionRow
* @return a boolean indicating if the content was changed or not
* @throws ProcessingException
*/
protected boolean execSelectionSave(ITableRow selectionRow) throws ProcessingException {
return false;
}
/**
* Called when there is one new selection. The content of the {@link #getDetailDataColumn()} for the selectionRow
* should be imported on the detail group box.
*
* @param selectionRow
* @throws ProcessingException
*/
protected void execSelectionNew(ITableRow selectionRow) throws ProcessingException {
}
/**
* Called when there is no selection. Can be used to disable or to hide the detail group box.
*
* @throws ProcessingException
*/
protected void execSelectionNo() throws ProcessingException {
}
}
/*******************************************************************************
* Copyright (c) 2015 BSI Business Systems Integration AG.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* BSI Business Systems Integration AG - initial API and implementation
******************************************************************************/
package m4test.client.core;
import java.util.Set;
import m4test.client.core.WithMasterDetailTableForm.MainBox.CancelButton;
import m4test.client.core.WithMasterDetailTableForm.MainBox.DetailsBox;
import m4test.client.core.WithMasterDetailTableForm.MainBox.DetailsBox.ChildrenField;
import m4test.client.core.WithMasterDetailTableForm.MainBox.DetailsBox.FirstNameField;
import m4test.client.core.WithMasterDetailTableForm.MainBox.DetailsBox.LastNameField;
import m4test.client.core.WithMasterDetailTableForm.MainBox.DetailsBox.UzdCodeField;
import m4test.client.core.WithMasterDetailTableForm.MainBox.OkButton;
import m4test.client.core.WithMasterDetailTableForm.MainBox.PersonsTableField;
import m4test.shared.core.IWithMasterDetailTableService;
import m4test.shared.core.PersonDetailBean;
import m4test.shared.core.UpdateWithMasterDetailTablePermission;
import m4test.shared.core.WithMasterDetailTableFormData;
import org.eclipse.scout.commons.CollectionUtility;
import org.eclipse.scout.commons.CompareUtility;
import org.eclipse.scout.commons.annotations.FormData;
import org.eclipse.scout.commons.annotations.Order;
import org.eclipse.scout.commons.exception.ProcessingException;
import org.eclipse.scout.rt.client.ui.action.menu.IMenuType;
import org.eclipse.scout.rt.client.ui.action.menu.TableMenuType;
import org.eclipse.scout.rt.client.ui.basic.table.ITableRow;
import org.eclipse.scout.rt.client.ui.basic.table.columns.AbstractStringColumn;
import org.eclipse.scout.rt.client.ui.form.AbstractForm;
import org.eclipse.scout.rt.client.ui.form.AbstractFormHandler;
import org.eclipse.scout.rt.client.ui.form.fields.button.AbstractCancelButton;
import org.eclipse.scout.rt.client.ui.form.fields.button.AbstractOkButton;
import org.eclipse.scout.rt.client.ui.form.fields.groupbox.AbstractGroupBox;
import org.eclipse.scout.rt.client.ui.form.fields.integerfield.AbstractIntegerField;
import org.eclipse.scout.rt.client.ui.form.fields.stringfield.AbstractStringField;
import org.eclipse.scout.rt.client.ui.form.fields.tablefield.AbstractTableField;
import org.eclipse.scout.rt.extension.client.ui.action.menu.AbstractExtensibleMenu;
import org.eclipse.scout.rt.shared.TEXTS;
import org.eclipse.scout.service.SERVICES;
/**
* @author jbr
*/
@FormData(value = WithMasterDetailTableFormData.class, sdkCommand = FormData.SdkCommand.CREATE)
public class WithMasterDetailTableForm extends AbstractForm {
/**
* @throws org.eclipse.scout.commons.exception.ProcessingException
*/
public WithMasterDetailTableForm() throws ProcessingException {
super();
}
@Override
protected String getConfiguredTitle() {
return TEXTS.get("FormWithMasterDetailTable");
}
/**
* @throws org.eclipse.scout.commons.exception.ProcessingException
*/
public void startModify() throws ProcessingException {
startInternal(new ModifyHandler());
}
/**
* @throws org.eclipse.scout.commons.exception.ProcessingException
*/
public void startNew() throws ProcessingException {
startInternal(new NewHandler());
}
/**
* @return the CancelButton
*/
public CancelButton getCancelButton() {
return getFieldByClass(CancelButton.class);
}
/**
* @return the ChildrenField
*/
public ChildrenField getChildrenField() {
return getFieldByClass(ChildrenField.class);
}
/**
* @return the DetailsBox
*/
public DetailsBox getDetailsBox() {
return getFieldByClass(DetailsBox.class);
}
/**
* @return the FirstNameField
*/
public FirstNameField getFirstNameField() {
return getFieldByClass(FirstNameField.class);
}
/**
* @return the LastNameField
*/
public LastNameField getLastNameField() {
return getFieldByClass(LastNameField.class);
}
/**
* @return the MainBox
*/
public MainBox getMainBox() {
return getFieldByClass(MainBox.class);
}
/**
* @return the OkButton
*/
public OkButton getOkButton() {
return getFieldByClass(OkButton.class);
}
/**
* @return the PersonsTableField
*/
public PersonsTableField getPersonsTableField() {
return getFieldByClass(PersonsTableField.class);
}
/**
* @return the UzdCodeField
*/
public UzdCodeField getUzdCodeField() {
return getFieldByClass(UzdCodeField.class);
}
@Order(1000.0)
public class MainBox extends AbstractGroupBox {
@Order(1000.0)
public class PersonsTableField extends AbstractTableField<PersonsTableField.Table> {
@Override
protected String getConfiguredLabel() {
return TEXTS.get("Persons");
}
@Override
protected int getConfiguredGridH() {
return 5;
}
@Override
protected int getConfiguredGridW() {
return 2;
}
@Order(1000.0)
public class Table extends AbstractTableWithDetail<PersonDetailBean> {
@Override
protected Class<PersonDetailBean> getConfiguredDetailDataType() {
return PersonDetailBean.class;
}
public FirstNameColumn getFirstNameColumn() {
return getColumnSet().getColumnByClass(FirstNameColumn.class);
}
public LastNameColumn getLastNameColumn() {
return getColumnSet().getColumnByClass(LastNameColumn.class);
}
@Override
protected boolean execSelectionSave(ITableRow selectionRow) throws ProcessingException {
boolean hasChanged = false;
PersonDetailBean detailBean = getDetailDataColumn().getValue(selectionRow);
if (detailBean == null) {
detailBean = new PersonDetailBean();
getDetailDataColumn().setValue(selectionRow, detailBean);
}
if (CompareUtility.notEquals(getFirstNameField().getValue(), getFirstNameColumn().getValue(selectionRow))) {
hasChanged = true;
getFirstNameColumn().setValue(selectionRow, getFirstNameField().getValue());
}
if (CompareUtility.notEquals(getLastNameField().getValue(), getLastNameColumn().getValue(selectionRow))) {
hasChanged = true;
getLastNameColumn().setValue(selectionRow, getLastNameField().getValue());
}
if (CompareUtility.notEquals(getUzdCodeField().getValue(), detailBean.getUzdCode())) {
hasChanged = true;
detailBean.setUzdCode(getUzdCodeField().getValue());
}
if (CompareUtility.notEquals(getChildrenField().getValue(), detailBean.getChildren())) {
hasChanged = true;
detailBean.setChildren(getChildrenField().getValue());
}
return hasChanged;
}
@Override
protected void execSelectionNew(ITableRow selectionRow) throws ProcessingException {
PersonDetailBean detailBean = getDetailDataColumn().getValue(selectionRow);
if (detailBean == null) {
detailBean = new PersonDetailBean();
}
getFirstNameField().setValue(getFirstNameColumn().getValue(selectionRow));
getLastNameField().setValue(getLastNameColumn().getValue(selectionRow));
getUzdCodeField().setValue(detailBean.getUzdCode());
getChildrenField().setValue(detailBean.getChildren());
getDetailsBox().setEnabled(true);
getFirstNameField().requestFocus();
}
@Override
protected void execSelectionNo() throws ProcessingException {
getFirstNameField().setValue(null);
getLastNameField().setValue(null);
getUzdCodeField().setValue(null);
getChildrenField().setValue(null);
getDetailsBox().setEnabled(false);
getDetailsBox().requestFocus();
}
@Order(1000.0)
public class FirstNameColumn extends AbstractStringColumn {
@Override
protected String getConfiguredHeaderText() {
return TEXTS.get("FirstName");
}
@Override
protected int getConfiguredWidth() {
return 120;
}
}
@Order(2000.0)
public class LastNameColumn extends AbstractStringColumn {
@Override
protected String getConfiguredHeaderText() {
return TEXTS.get("LastName");
}
@Override
protected int getConfiguredWidth() {
return 120;
}
}
@Order(1000.0)
public class NewPersonMenu extends AbstractExtensibleMenu {
@Override
protected Set<? extends IMenuType> getConfiguredMenuTypes() {
return CollectionUtility.<IMenuType> hashSet(TableMenuType.EmptySpace);
}
@Override
protected String getConfiguredText() {
return TEXTS.get("NewPerson");
}
@Override
protected void execAction() throws ProcessingException {
ITableRow row = createRow();
row = addRow(row);
selectRow(row);
}
}
@Order(2000.0)
public class DeletePersonMenu extends AbstractExtensibleMenu {
@Override
protected String getConfiguredText() {
return TEXTS.get("DeletePerson");
}
@Override
protected void execAction() throws ProcessingException {
getSelectedRow().delete();
}
}
}
}
@Order(2000.0)
public class DetailsBox extends AbstractGroupBox {
@Override
protected String getConfiguredLabel() {
return TEXTS.get("DetailsForTheSelectedPerson");
}
@Order(1000.0)
@FormData(sdkCommand = FormData.SdkCommand.IGNORE)
public class FirstNameField extends AbstractStringField {
@Override
protected String getConfiguredLabel() {
return TEXTS.get("FirstName");
}
@Override
protected boolean execIsSaveNeeded() throws ProcessingException {
return false;
}
}
@Order(2000.0)
@FormData(sdkCommand = FormData.SdkCommand.IGNORE)
public class LastNameField extends AbstractStringField {
@Override
protected String getConfiguredLabel() {
return TEXTS.get("LastName");
}
@Override
protected boolean execIsSaveNeeded() throws ProcessingException {
return false;
}
}
@Order(3000.0)
@FormData(sdkCommand = FormData.SdkCommand.IGNORE)
public class UzdCodeField extends AbstractStringField {
@Override
protected String getConfiguredLabel() {
return TEXTS.get("CodeUDZ");
}
@Override
protected boolean execIsSaveNeeded() throws ProcessingException {
return false;
}
}
@Order(4000.0)
@FormData(sdkCommand = FormData.SdkCommand.IGNORE)
public class ChildrenField extends AbstractIntegerField {
@Override
protected String getConfiguredLabel() {
return TEXTS.get("NumberOfChildren");
}
@Override
protected boolean execIsSaveNeeded() throws ProcessingException {
return false;
}
}
}
@Order(100000.0)
public class OkButton extends AbstractOkButton {
}
@Order(101000.0)
public class CancelButton extends AbstractCancelButton {
}
}
public class ModifyHandler extends AbstractFormHandler {
@Override
protected void execLoad() throws ProcessingException {
IWithMasterDetailTableService service = SERVICES.getService(IWithMasterDetailTableService.class);
WithMasterDetailTableFormData formData = new WithMasterDetailTableFormData();
exportFormData(formData);
formData = service.load(formData);
importFormData(formData);
setEnabledPermission(new UpdateWithMasterDetailTablePermission());
}
@Override
protected void execStore() throws ProcessingException {
IWithMasterDetailTableService service = SERVICES.getService(IWithMasterDetailTableService.class);
WithMasterDetailTableFormData formData = new WithMasterDetailTableFormData();
exportFormData(formData);
formData = service.store(formData);
}
}
public class NewHandler extends AbstractFormHandler {
@Override
protected void execLoad() throws ProcessingException {
IWithMasterDetailTableService service = SERVICES.getService(IWithMasterDetailTableService.class);
WithMasterDetailTableFormData formData = new WithMasterDetailTableFormData();
exportFormData(formData);
formData = service.prepareCreate(formData);
importFormData(formData);
}
@Override
protected void execStore() throws ProcessingException {
IWithMasterDetailTableService service = SERVICES.getService(IWithMasterDetailTableService.class);
WithMasterDetailTableFormData formData = new WithMasterDetailTableFormData();
exportFormData(formData);
formData = service.create(formData);
}
}
}
@jmini
Copy link
Author

jmini commented Jan 22, 2015

See also the corresponding description in the Eclipse Scout Forum.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment