/*
* Copyright 2011 JBoss Inc
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.drools.guvnor.client.decisiontable.widget;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.drools.guvnor.client.modeldriven.ui.RuleAttributeWidget;
import org.drools.guvnor.client.util.GWTDateConverter;
import org.drools.guvnor.client.widgets.decoratedgrid.CellValue;
import org.drools.guvnor.client.widgets.decoratedgrid.CellValue.CellState;
import org.drools.guvnor.client.widgets.decoratedgrid.DecoratedGridWidget;
import org.drools.guvnor.client.widgets.decoratedgrid.DynamicColumn;
import org.drools.guvnor.client.widgets.decoratedgrid.HasColumns;
import org.drools.guvnor.client.widgets.decoratedgrid.HasRows;
import org.drools.guvnor.client.widgets.decoratedgrid.HasSystemControlledColumns;
import org.drools.guvnor.client.widgets.decoratedgrid.MergableGridWidget;
import org.drools.guvnor.client.widgets.decoratedgrid.data.Coordinate;
import org.drools.guvnor.client.widgets.decoratedgrid.data.DynamicData;
import org.drools.guvnor.client.widgets.decoratedgrid.data.DynamicDataRow;
import org.drools.guvnor.client.widgets.decoratedgrid.data.GroupedDynamicDataRow;
import org.drools.ide.common.client.modeldriven.SuggestionCompletionEngine;
import org.drools.ide.common.client.modeldriven.brl.BaseSingleFieldConstraint;
import org.drools.ide.common.client.modeldriven.dt52.ActionCol52;
import org.drools.ide.common.client.modeldriven.dt52.ActionInsertFactCol52;
import org.drools.ide.common.client.modeldriven.dt52.ActionSetFieldCol52;
import org.drools.ide.common.client.modeldriven.dt52.AttributeCol52;
import org.drools.ide.common.client.modeldriven.dt52.ConditionCol52;
import org.drools.ide.common.client.modeldriven.dt52.DTCellValue52;
import org.drools.ide.common.client.modeldriven.dt52.DTColumnConfig52;
import org.drools.ide.common.client.modeldriven.dt52.DescriptionCol52;
import org.drools.ide.common.client.modeldriven.dt52.GuidedDecisionTable52;
import org.drools.ide.common.client.modeldriven.dt52.MetadataCol52;
import org.drools.ide.common.client.modeldriven.dt52.Pattern52;
import org.drools.ide.common.client.modeldriven.dt52.RowNumberCol52;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.ui.Composite;
/**
* An abstract Decision Table and the necessary boiler-plate to convert from
* DTColumnConfig objects to the DynamicData related classes used by the
* DecoratedGridWidget
*/
public abstract class AbstractDecisionTableWidget extends Composite
implements
HasRows,
HasColumns<DTColumnConfig52>,
HasSystemControlledColumns {
// Decision Table data
protected GuidedDecisionTable52 model;
protected DecoratedGridWidget<DTColumnConfig52> widget;
protected SuggestionCompletionEngine sce;
protected DecisionTableCellFactory cellFactory;
protected DecisionTableCellValueFactory cellValueFactory;
protected DecisionTableControlsWidget dtableCtrls;
/**
* Constructor
*
* @param sce
*/
public AbstractDecisionTableWidget(DecisionTableControlsWidget dtableCtrls,
SuggestionCompletionEngine sce) {
if ( dtableCtrls == null ) {
throw new IllegalArgumentException( "dtableControls cannot be null" );
}
if ( sce == null ) {
throw new IllegalArgumentException( "sce cannot be null" );
}
this.sce = sce;
this.dtableCtrls = dtableCtrls;
this.dtableCtrls.setDecisionTableWidget( this );
}
/**
* Add a column to the table, at the appropriate position determined by the
* column subclass: RowNumberCol, Metadata columns, Attribute columns,
* Condition columns and lastly Action columns. Condition Ccolumns are
* further grouped by Pattern.
*
* @param modelColumn
* The Decision Table column to insert
*/
public void addColumn(DTColumnConfig52 modelColumn) {
if ( modelColumn == null ) {
throw new IllegalArgumentException(
"modelColumn cannot be null." );
}
addColumn( modelColumn,
true );
}
/**
* Append an empty row to the end of the table
*/
public void appendRow() {
insertRowBefore( null );
}
/**
* Delete the given column
*
* @param modelColumn
* The Decision Table column to delete
*/
public void deleteColumn(DTColumnConfig52 modelColumn) {
if ( modelColumn == null ) {
throw new IllegalArgumentException(
"modelColumn cannot be null." );
}
DynamicColumn<DTColumnConfig52> col = getDynamicColumn( modelColumn );
widget.deleteColumn( col );
}
/**
* Delete the given row
*
* @param The
* Decision Table row to delete
*/
public void deleteRow(DynamicDataRow row) {
if ( row == null ) {
throw new IllegalArgumentException( "row cannot be null" );
}
widget.deleteRow( row );
updateSystemControlledColumnValues();
redrawSystemControlledColumns();
}
/**
* Return the model
*
* @return The DecisionTable data model
*/
public GuidedDecisionTable52 getModel() {
return this.model;
}
/**
* Return the SCE associated with this Decision Table
*
* @return
*/
public SuggestionCompletionEngine getSCE() {
return this.sce;
}
/**
* Insert an empty row before the given row
*
* @param rowBefore
* The row before which the new (empty) row will be inserted. If
* this value is null the row will be appended to the end of the
* table
*/
public void insertRowBefore(DynamicDataRow rowBefore) {
List<CellValue< ? extends Comparable< ? >>> rowData = makeRowData();
widget.insertRowBefore( rowBefore,
rowData );
redrawSystemControlledColumns();
}
/**
* Mark a cell as containing the magical "otherwise" value. The magical
* "otherwise" value has the meaning of all values other than those
* explicitly defined for this column.
*/
public void makeOtherwiseCell() {
MergableGridWidget<DTColumnConfig52> grid = widget.getGridWidget();
List<CellValue< ? >> selections = grid.getSelectedCells();
CellValue< ? > cell = selections.get( 0 );
if ( canAcceptOtherwiseValues( cell ) ) {
//Set "otherwise" property on cell
for ( CellValue< ? > cv : selections ) {
cv.addState( CellState.OTHERWISE );
}
grid.update( null );
}
}
/**
* Force the system controlled columns to be redrawn
*/
public void redrawSystemControlledColumns() {
widget.redrawSystemControlledColumns();
}
/**
* Update the Decision Table model with the columns contained in the grid.
* The Decision Table controls indexing of new columns to preserve grouping
* of column types. If the order of columns is important to client-code this
* can be called to ensure columns within the model are synchronised with
* the Decision Table.
*/
public void scrapeColumns() {
RowNumberCol52 rnCol = null;
DescriptionCol52 descCol = null;
List<MetadataCol52> newMetaColumns = new ArrayList<MetadataCol52>();
List<AttributeCol52> newAttributeColumns = new ArrayList<AttributeCol52>();
List<Pattern52> newPatterns = new ArrayList<Pattern52>();
List<ActionCol52> newActionColumns = new ArrayList<ActionCol52>();
// Extract column information
for ( DynamicColumn<DTColumnConfig52> column : widget.getGridWidget().getColumns() ) {
DTColumnConfig52 modelCol = column.getModelColumn();
if ( modelCol instanceof RowNumberCol52 ) {
rnCol = (RowNumberCol52) modelCol;
rnCol.setWidth( column.getWidth() );
rnCol.setHideColumn( !column.isVisible() );
model.setRowNumberCol( rnCol );
} else if ( modelCol instanceof DescriptionCol52 ) {
descCol = (DescriptionCol52) modelCol;
descCol.setWidth( column.getWidth() );
descCol.setHideColumn( !column.isVisible() );
model.setDescriptionCol( descCol );
} else if ( modelCol instanceof MetadataCol52 ) {
MetadataCol52 tc = (MetadataCol52) modelCol;
tc.setWidth( column.getWidth() );
tc.setHideColumn( !column.isVisible() );
newMetaColumns.add( tc );
} else if ( modelCol instanceof AttributeCol52 ) {
AttributeCol52 tc = (AttributeCol52) modelCol;
tc.setWidth( column.getWidth() );
tc.setHideColumn( !column.isVisible() );
newAttributeColumns.add( tc );
} else if ( modelCol instanceof ConditionCol52 ) {
ConditionCol52 tc = (ConditionCol52) modelCol;
tc.setWidth( column.getWidth() );
tc.setHideColumn( !column.isVisible() );
Pattern52 p = model.getPattern( tc );
Pattern52 newPattern = getExistingNewPattern( newPatterns,
p );
if ( newPattern == null ) {
newPattern = clonePatternExcludingConditions( p );
newPatterns.add( newPattern );
}
newPattern.getConditions().add( tc );
} else if ( modelCol instanceof ActionCol52 ) {
ActionCol52 tc = (ActionCol52) modelCol;
tc.setWidth( column.getWidth() );
tc.setHideColumn( !column.isVisible() );
newActionColumns.add( tc );
}
}
model.setMetadataCols( newMetaColumns );
model.setAttributeCols( newAttributeColumns );
model.setConditionPatterns( newPatterns );
model.setActionCols( newActionColumns );
}
private Pattern52 clonePatternExcludingConditions(Pattern52 p) {
Pattern52 newPattern = new Pattern52();
newPattern.setBoundName( p.getBoundName() );
newPattern.setEntryPointName( p.getEntryPointName() );
newPattern.setFactType( p.getFactType() );
newPattern.setNegated( p.isNegated() );
newPattern.setWindow( p.getWindow() );
return newPattern;
}
private Pattern52 getExistingNewPattern(List<Pattern52> newPatterns,
Pattern52 pattern) {
for ( Pattern52 p : newPatterns ) {
if ( p.getBoundName().equals( pattern.getBoundName() ) ) {
return p;
}
}
return null;
}
/**
* Update the Decision Table model with the data contained in the grid. The
* Decision Table does not synchronise model data with UI data during user
* interaction with the UI. Consequentially this should be called to refresh
* the Model with the UI when needed.
*/
public void scrapeData() {
// Copy data
final DynamicData data = widget.getGridWidget().getData().getFlattenedData();
final List<DynamicColumn<DTColumnConfig52>> columns = widget.getGridWidget().getColumns();
final int GRID_ROWS = data.size();
List<List<DTCellValue52>> grid = new ArrayList<List<DTCellValue52>>();
for ( int iRow = 0; iRow < GRID_ROWS; iRow++ ) {
DynamicDataRow dataRow = data.get( iRow );
List<DTCellValue52> row = new ArrayList<DTCellValue52>();
for ( int iCol = 0; iCol < columns.size(); iCol++ ) {
//Values put back into the Model are type-safe
CellValue< ? > cv = dataRow.get( iCol );
DTColumnConfig52 column = columns.get( iCol ).getModelColumn();
DTCellValue52 dcv = cellValueFactory.convertToDTModelCell( column,
cv );
dcv.setOtherwise( cv.isOtherwise() );
row.add( dcv );
}
grid.add( row );
}
this.model.setData( grid );
}
public void setColumnVisibility(DTColumnConfig52 modelColumn,
boolean isVisible) {
if ( modelColumn == null ) {
throw new IllegalArgumentException( "modelColumn cannot be null" );
}
DynamicColumn<DTColumnConfig52> col = getDynamicColumn( modelColumn );
widget.setColumnVisibility( col.getColumnIndex(),
isVisible );
}
/**
* Set the Decision Table's data. This removes all existing columns from the
* Decision Table and re-creates them based upon the provided data.
*
* @param data
*/
public void setModel(GuidedDecisionTable52 model) {
if ( model == null ) {
throw new IllegalArgumentException( "model cannot be null" );
}
this.model = model;
this.cellFactory = new DecisionTableCellFactory( sce,
widget.getGridWidget(),
this.model );
this.cellValueFactory = new DecisionTableCellValueFactory( sce,
this.model );
//Date converter is injected so a GWT compatible one can be used here and another in testing
DecisionTableCellValueFactory.injectDateConvertor( GWTDateConverter.getInstance() );
//Setup command to recalculate System Controlled values when rows are added\deleted
widget.getGridWidget().getData().setOnRowChangeCommand( new Command() {
public void execute() {
updateSystemControlledColumnValues();
}
} );
widget.getGridWidget().getData().clear();
widget.getGridWidget().getColumns().clear();
// Dummy rows because the underlying DecoratedGridWidget expects there
// to be enough rows to receive the columns data
final DynamicData data = widget.getGridWidget().getData();
for ( int iRow = 0; iRow < model.getData().size(); iRow++ ) {
data.addRow();
}
// Static columns, Row#
int colIndex = 0;
DTColumnConfig52 colStatic;
DynamicColumn<DTColumnConfig52> columnStatic;
colStatic = model.getRowNumberCol();
columnStatic = new DynamicColumn<DTColumnConfig52>( colStatic,
cellFactory.getCell( colStatic ),
colIndex,
true,
false );
columnStatic.setWidth( 24 );
widget.appendColumn( columnStatic,
makeColumnData( colStatic,
colIndex++ ),
false );
// Static columns, Description
colStatic = model.getDescriptionCol();
columnStatic = new DynamicColumn<DTColumnConfig52>( colStatic,
cellFactory.getCell( colStatic ),
colIndex );
widget.appendColumn( columnStatic,
makeColumnData( colStatic,
colIndex++ ),
false );
// Initialise CellTable's Metadata columns
for ( MetadataCol52 col : model.getMetadataCols() ) {
DynamicColumn<DTColumnConfig52> column = new DynamicColumn<DTColumnConfig52>( col,
cellFactory.getCell( col ),
colIndex );
column.setVisible( !col.isHideColumn() );
widget.appendColumn( column,
makeColumnData( col,
colIndex++ ),
false );
}
// Initialise CellTable's Attribute columns
for ( AttributeCol52 col : model.getAttributeCols() ) {
DynamicColumn<DTColumnConfig52> column = new DynamicColumn<DTColumnConfig52>( col,
cellFactory.getCell( col ),
colIndex );
column.setVisible( !col.isHideColumn() );
column.setSystemControlled( col.isUseRowNumber() );
column.setSortable( !col.isUseRowNumber() );
widget.appendColumn( column,
makeColumnData( col,
colIndex++ ),
false );
}
// Initialise CellTable's Condition columns
for ( Pattern52 p : model.getConditionPatterns() ) {
for ( ConditionCol52 col : p.getConditions() ) {
DynamicColumn<DTColumnConfig52> column = new DynamicColumn<DTColumnConfig52>( col,
cellFactory.getCell( col ),
colIndex );
column.setVisible( !col.isHideColumn() );
widget.appendColumn( column,
makeColumnData( col,
colIndex++ ),
false );
//Ensure field data-type is set (field did not exist before 5.2)
ConditionCol52 cc = (ConditionCol52) col;
cc.setFieldType( sce.getFieldType( p.getFactType(),
cc.getFactField() ) );
}
}
// Initialise CellTable's Action columns
for ( ActionCol52 col : model.getActionCols() ) {
DynamicColumn<DTColumnConfig52> column = new DynamicColumn<DTColumnConfig52>( col,
cellFactory.getCell( col ),
colIndex );
column.setVisible( !col.isHideColumn() );
widget.appendColumn( column,
makeColumnData( col,
colIndex++ ),
false );
}
// Ensure System Controlled values are correctly initialised
updateSystemControlledColumnValues();
// Schedule redraw of grid after sizes of child Elements have been set
Scheduler.get().scheduleFinally( new ScheduledCommand() {
public void execute() {
// Draw header first as the size of child Elements depends upon it
widget.getHeaderWidget().redraw();
widget.getSidebarWidget().redraw();
widget.getGridWidget().redraw();
}
} );
}
/**
* Ensure the wrapped DecoratedGridWidget's size is set too
*/
@Override
public void setPixelSize(int width,
int height) {
if ( width < 0 ) {
throw new IllegalArgumentException( "width cannot be less than zero" );
}
if ( height < 0 ) {
throw new IllegalArgumentException( "height cannot be less than zero" );
}
super.setPixelSize( width,
height );
widget.setPixelSize( width,
height );
}
/**
* Update an ActionSetFieldCol column
*
* @param origCol
* The existing column in the grid
* @param editColumn
* A copy (not clone) of the original column containing the
* modified values
*/
public void updateColumn(final ActionInsertFactCol52 origColumn,
final ActionInsertFactCol52 editColumn) {
if ( origColumn == null ) {
throw new IllegalArgumentException( "origColumn cannot be null" );
}
if ( editColumn == null ) {
throw new IllegalArgumentException( "editColumn cannot be null" );
}
boolean bRedrawColumn = false;
boolean bRedrawHeader = false;
DynamicColumn<DTColumnConfig52> column = getDynamicColumn( origColumn );
// Update column's visibility
if ( origColumn.isHideColumn() != editColumn.isHideColumn() ) {
setColumnVisibility( origColumn,
!editColumn.isHideColumn() );
}
// Change in column's binding forces an update and redraw if FactType or
// FactField are different; otherwise only need to update and redraw if
// the FactType or FieldType have changed
if ( !isEqualOrNull( origColumn.getBoundName(),
editColumn.getBoundName() ) ) {
if ( !isEqualOrNull( origColumn.getFactType(),
editColumn.getFactType() )
|| !isEqualOrNull( origColumn.getFactField(),
editColumn.getFactField() ) ) {
bRedrawColumn = true;
updateCellsForDataType( editColumn,
column );
}
} else if ( !isEqualOrNull( origColumn.getFactType(),
editColumn.getFactType() )
|| !isEqualOrNull( origColumn.getFactField(),
editColumn.getFactField() ) ) {
bRedrawColumn = true;
updateCellsForDataType( editColumn,
column );
}
// Update column's cell content if the Optional Value list has changed
if ( !isEqualOrNull( origColumn.getValueList(),
editColumn.getValueList() ) ) {
bRedrawColumn = updateCellsForOptionValueList( editColumn,
column );
}
// Update column header in Header Widget
if ( !origColumn.getHeader().equals( editColumn.getHeader() ) ) {
bRedrawHeader = true;
}
// Copy new values into original column definition
populateModelColumn( origColumn,
editColumn );
if ( bRedrawColumn ) {
int maxColumnIndex = widget.getGridWidget().getColumns().size() - 1;
widget.getGridWidget().redrawColumns( column.getColumnIndex(),
maxColumnIndex );
}
if ( bRedrawHeader ) {
// Schedule redraw event after column has been redrawn
Scheduler.get().scheduleFinally( new ScheduledCommand() {
public void execute() {
widget.getHeaderWidget().redraw();
}
} );
}
}
/**
* Update an ActionSetFieldCol column
*
* @param origCol
* The existing column in the grid
* @param editColumn
* A copy (not clone) of the original column containing the
* modified values
*/
public void updateColumn(final ActionSetFieldCol52 origColumn,
final ActionSetFieldCol52 editColumn) {
if ( origColumn == null ) {
throw new IllegalArgumentException( "origColumn cannot be null" );
}
if ( editColumn == null ) {
throw new IllegalArgumentException( "editColumn cannot be null" );
}
boolean bRedrawColumn = false;
boolean bRedrawHeader = false;
DynamicColumn<DTColumnConfig52> column = getDynamicColumn( origColumn );
// Update column's visibility
if ( origColumn.isHideColumn() != editColumn.isHideColumn() ) {
setColumnVisibility( origColumn,
!editColumn.isHideColumn() );
}
// Change in column's binding forces an update and redraw if FactField
// is different; otherwise only need to update and redraw if the
// FieldType has changed
if ( !isEqualOrNull( origColumn.getBoundName(),
editColumn.getBoundName() ) ) {
if ( !isEqualOrNull( origColumn.getFactField(),
editColumn.getFactField() ) ) {
bRedrawColumn = true;
updateCellsForDataType( editColumn,
column );
}
} else if ( !isEqualOrNull( origColumn.getFactField(),
editColumn.getFactField() ) ) {
bRedrawColumn = true;
updateCellsForDataType( editColumn,
column );
}
// Update column's cell content if the Optional Value list has changed
if ( !isEqualOrNull( origColumn.getValueList(),
editColumn.getValueList() ) ) {
bRedrawColumn = updateCellsForOptionValueList( editColumn,
column );
}
// Update column header in Header Widget
if ( !origColumn.getHeader().equals( editColumn.getHeader() ) ) {
bRedrawHeader = true;
}
// Copy new values into original column definition
populateModelColumn( origColumn,
editColumn );
if ( bRedrawColumn ) {
int maxColumnIndex = widget.getGridWidget().getColumns().size() - 1;
widget.getGridWidget().redrawColumns( column.getColumnIndex(),
maxColumnIndex );
}
if ( bRedrawHeader ) {
// Schedule redraw event after column has been redrawn
Scheduler.get().scheduleFinally( new ScheduledCommand() {
public void execute() {
widget.getHeaderWidget().redraw();
}
} );
}
}
/**
* Update a Condition column
*
* @param origPattern
* The existing pattern to which the column related
* @param origCol
* The existing column in the grid
* @param editPattern
* The new pattern to which the column relates
* @param editColumn
* A copy of the original column containing the modified values
*/
public void updateColumn(final Pattern52 origPattern,
final ConditionCol52 origColumn,
final Pattern52 editPattern,
final ConditionCol52 editColumn) {
if ( origPattern == null ) {
throw new IllegalArgumentException( "origPattern cannot be null" );
}
if ( origColumn == null ) {
throw new IllegalArgumentException( "origColumn cannot be null" );
}
if ( editPattern == null ) {
throw new IllegalArgumentException( "editPattern cannot be null" );
}
if ( editColumn == null ) {
throw new IllegalArgumentException( "editColumn cannot be null" );
}
boolean bRedrawColumn = false;
boolean bRedrawHeader = false;
DynamicColumn<DTColumnConfig52> column = getDynamicColumn( origColumn );
// Update column's visibility
if ( origColumn.isHideColumn() != editColumn.isHideColumn() ) {
setColumnVisibility( origColumn,
!editColumn.isHideColumn() );
}
// Change in operator
if ( !isEqualOrNull( origColumn.getOperator(),
editColumn.getOperator() ) ) {
bRedrawHeader = true;
//Clear otherwise if column cannot accept them
if ( !canAcceptOtherwiseValues( editColumn ) ) {
removeOtherwiseStates( column );
bRedrawColumn = true;
}
}
if ( !isEqualOrNull( origPattern.getBoundName(),
editPattern.getBoundName() ) ) {
// Change in bound name requires column to be repositioned
bRedrawHeader = true;
addColumn( editColumn,
false );
DynamicColumn<DTColumnConfig52> origCol = getDynamicColumn( origColumn );
DynamicColumn<DTColumnConfig52> editCol = getDynamicColumn( editColumn );
int origColIndex = widget.getGridWidget().getColumns().indexOf( origCol );
int editColIndex = widget.getGridWidget().getColumns().indexOf( editCol );
// If the FactType, FieldType and ConstraintValueType are unchanged
// we can copy cell values from the old column into the new
if ( isEqualOrNull( origPattern.getFactType(),
editPattern.getFactType() )
&& isEqualOrNull( origColumn.getFactField(),
editColumn.getFactField() )
&& origColumn.getConstraintValueType() == editColumn.getConstraintValueType() ) {
final DynamicData data = widget.getGridWidget().getData();
for ( int iRow = 0; iRow < data.size(); iRow++ ) {
DynamicDataRow row = data.get( iRow );
CellValue< ? > oldCell = row.get( origColIndex );
CellValue< ? > newCell = row.get( editColIndex );
newCell.setValue( oldCell.getValue() );
}
}
// Delete old column and redraw
widget.deleteColumn( origCol );
editColIndex = Math.min( widget.getGridWidget().getColumns().size() - 1,
editColIndex );
if ( editColIndex > origColIndex ) {
int temp = origColIndex;
origColIndex = editColIndex;
editColIndex = temp;
}
widget.getGridWidget().redrawColumns( editColIndex,
origColIndex );
} else if ( !isEqualOrNull( origPattern.getFactType(),
editPattern.getFactType() )
|| !isEqualOrNull( origColumn.getFactField(),
editColumn.getFactField() )
|| !isEqualOrNull( origColumn.getFieldType(),
editColumn.getFieldType() )
|| origColumn.getConstraintValueType() != editColumn.getConstraintValueType() ) {
// Update column's Cell type
bRedrawColumn = true;
updateCellsForDataType( editColumn,
column );
}
// Update column's cell content if the Optional Value list has changed
if ( !isEqualOrNull( origColumn.getValueList(),
editColumn.getValueList() ) ) {
bRedrawColumn = updateCellsForOptionValueList( editColumn,
column );
}
// Update column header in Header Widget
if ( !origColumn.getHeader().equals( editColumn.getHeader() ) ) {
bRedrawHeader = true;
}
// Update column field in Header Widget
if ( !origColumn.getFactField().equals( editColumn.getFactField() ) ) {
bRedrawHeader = true;
}
// Copy new values into original column definition
populateModelColumn( origColumn,
editColumn );
if ( bRedrawColumn ) {
int maxColumnIndex = widget.getGridWidget().getColumns().size() - 1;
widget.getGridWidget().redrawColumns( column.getColumnIndex(),
maxColumnIndex );
}
if ( bRedrawHeader ) {
// Schedule redraw event after column has been redrawn
Scheduler.get().scheduleFinally( new ScheduledCommand() {
public void execute() {
widget.getHeaderWidget().redraw();
}
} );
}
}
public void updateSystemControlledColumnValues() {
final DynamicData data = widget.getGridWidget().getData();
final List<DynamicColumn<DTColumnConfig52>> columns = widget.getGridWidget().getColumns();
for ( DynamicColumn<DTColumnConfig52> col : columns ) {
DTColumnConfig52 modelColumn = col.getModelColumn();
if ( modelColumn instanceof RowNumberCol52 ) {
updateRowNumberColumnValues( data,
col.getColumnIndex() );
} else if ( modelColumn instanceof AttributeCol52 ) {
// Update Salience values
AttributeCol52 attrCol = (AttributeCol52) modelColumn;
if ( attrCol.getAttribute().equals( RuleAttributeWidget.SALIENCE_ATTR ) ) {
if ( attrCol.isUseRowNumber() ) {
updateSalienceColumnValues( data,
col.getColumnIndex(),
attrCol.isReverseOrder() );
}
// Ensure Salience cells are rendered with the correct Cell
col.setCell( cellFactory.getCell( attrCol ) );
col.setSystemControlled( attrCol.isUseRowNumber() );
col.setSortable( !attrCol.isUseRowNumber() );
}
}
}
}
// Add column to table with optional redraw
private void addColumn(DTColumnConfig52 modelColumn,
boolean bRedraw) {
int index = 0;
if ( modelColumn instanceof MetadataCol52 ) {
index = findMetadataColumnIndex();
} else if ( modelColumn instanceof AttributeCol52 ) {
index = findAttributeColumnIndex();
} else if ( modelColumn instanceof ConditionCol52 ) {
index = findConditionColumnIndex( (ConditionCol52) modelColumn );
} else if ( modelColumn instanceof ActionCol52 ) {
index = findActionColumnIndex();
}
insertColumnBefore( modelColumn,
index,
bRedraw );
}
/**
* Check whether the given column can accept "otherwise" values
*
* @param column
* @return true if the Column can accept "otherwise" values
*/
private boolean canAcceptOtherwiseValues(DTColumnConfig52 column) {
//Check the column type is correct
if ( !(column instanceof ConditionCol52) ) {
return false;
}
ConditionCol52 cc = (ConditionCol52) column;
//Check column contains literal values and uses the equals operator
if ( cc.getConstraintValueType() != BaseSingleFieldConstraint.TYPE_LITERAL ) {
return false;
}
//Check operator is supported
if ( cc.getOperator().equals( "==" ) ) {
return true;
}
if ( cc.getOperator().equals( "!=" ) ) {
return true;
}
return false;
}
// Find the right-most index for an Action column
private int findActionColumnIndex() {
int index = widget.getGridWidget().getColumns().size() - 1;
return index;
}
// Find the right-most index for a Attribute column
private int findAttributeColumnIndex() {
int index = 0;
List<DynamicColumn<DTColumnConfig52>> columns = widget.getGridWidget().getColumns();
for ( int iCol = 0; iCol < columns.size(); iCol++ ) {
DynamicColumn<DTColumnConfig52> column = columns.get( iCol );
DTColumnConfig52 modelColumn = column.getModelColumn();
if ( modelColumn instanceof RowNumberCol52 ) {
index = iCol;
} else if ( modelColumn instanceof DescriptionCol52 ) {
index = iCol;
} else if ( modelColumn instanceof MetadataCol52 ) {
index = iCol;
} else if ( modelColumn instanceof AttributeCol52 ) {
index = iCol;
}
}
return index;
}
// Find the right-most index for a Condition column
private int findConditionColumnIndex(ConditionCol52 col) {
int index = 0;
boolean bMatched = false;
List<DynamicColumn<DTColumnConfig52>> columns = widget.getGridWidget().getColumns();
for ( int iCol = 0; iCol < columns.size(); iCol++ ) {
DynamicColumn<DTColumnConfig52> column = columns.get( iCol );
DTColumnConfig52 modelColumn = column.getModelColumn();
if ( modelColumn instanceof RowNumberCol52 ) {
index = iCol;
} else if ( modelColumn instanceof DescriptionCol52 ) {
index = iCol;
} else if ( modelColumn instanceof MetadataCol52 ) {
index = iCol;
} else if ( modelColumn instanceof AttributeCol52 ) {
index = iCol;
} else if ( modelColumn instanceof ConditionCol52 ) {
if ( isEquivalentConditionColumn( (ConditionCol52) modelColumn,
col ) ) {
index = iCol;
bMatched = true;
} else if ( !bMatched ) {
index = iCol;
}
}
}
return index;
}
// Find the right-most index for a Metadata column
private int findMetadataColumnIndex() {
int index = 0;
List<DynamicColumn<DTColumnConfig52>> columns = widget.getGridWidget().getColumns();
for ( int iCol = 0; iCol < columns.size(); iCol++ ) {
DynamicColumn<DTColumnConfig52> column = columns.get( iCol );
DTColumnConfig52 modelColumn = column.getModelColumn();
if ( modelColumn instanceof RowNumberCol52 ) {
index = iCol;
} else if ( modelColumn instanceof DescriptionCol52 ) {
index = iCol;
} else if ( modelColumn instanceof MetadataCol52 ) {
index = iCol;
}
}
return index;
}
// Retrieves the DynamicColumn relating to the Model column or null if it
// cannot be found
private DynamicColumn<DTColumnConfig52> getDynamicColumn(DTColumnConfig52 modelCol) {
DynamicColumn<DTColumnConfig52> column = null;
List<DynamicColumn<DTColumnConfig52>> columns = widget.getGridWidget().getColumns();
for ( DynamicColumn<DTColumnConfig52> dc : columns ) {
if ( dc.getModelColumn().equals( modelCol ) ) {
column = dc;
break;
}
}
return column;
}
// Insert a new model column at the specified index
private void insertColumnBefore(DTColumnConfig52 modelColumn,
int index,
boolean bRedraw) {
// Create new column for grid
DynamicColumn<DTColumnConfig52> column = new DynamicColumn<DTColumnConfig52>( modelColumn,
cellFactory.getCell( modelColumn ),
index );
column.setVisible( !modelColumn.isHideColumn() );
DynamicColumn<DTColumnConfig52> columnBefore = widget.getGridWidget().getColumns().get( index );
// Create column data
DynamicData data = widget.getGridWidget().getData();
List<CellValue< ? extends Comparable< ? >>> columnData = new ArrayList<CellValue< ? extends Comparable< ? >>>();
for ( int iRow = 0; iRow < data.size(); iRow++ ) {
DTCellValue52 dcv = new DTCellValue52( modelColumn.getDefaultValue() );
CellValue< ? > cell = cellValueFactory.makeCellValue( modelColumn,
iRow,
index,
dcv );
columnData.add( cell );
}
// Add column and data to grid
widget.insertColumnBefore( columnBefore,
column,
columnData,
bRedraw );
}
// Check whether two Strings are equal or both null
private boolean isEqualOrNull(String s1,
String s2) {
if ( s1 == null
&& s2 == null ) {
return true;
} else if ( s1 != null
&& s2 != null
&& s1.equals( s2 ) ) {
return true;
}
return false;
}
// Check whether two ConditionCols are equivalent
private boolean isEquivalentConditionColumn(ConditionCol52 c1,
ConditionCol52 c2) {
Pattern52 c1Pattern = model.getPattern( c1 );
Pattern52 c2Pattern = model.getPattern( c2 );
if ( isEqualOrNull( c1Pattern.getFactType(),
c2Pattern.getFactType() )
&& isEqualOrNull( c1Pattern.getBoundName(),
c2Pattern.getBoundName() ) ) {
return true;
}
return false;
}
// Make a row of data for insertion into a DecoratedGridWidget
private List<CellValue< ? extends Comparable< ? >>> makeColumnData(DTColumnConfig52 column,
int colIndex) {
int dataSize = model.getData().size();
List<CellValue< ? extends Comparable< ? >>> columnData = new ArrayList<CellValue< ? extends Comparable< ? >>>();
for ( int iRow = 0; iRow < dataSize; iRow++ ) {
List<DTCellValue52> row = model.getData().get( iRow );
DTCellValue52 dcv = row.get( colIndex );
CellValue< ? extends Comparable< ? >> cv = cellValueFactory.makeCellValue( column,
iRow,
colIndex,
dcv );
columnData.add( cv );
}
return columnData;
}
// Construct a new row for insertion into a DecoratedGridWidget
private List<CellValue< ? extends Comparable< ? >>> makeRowData() {
List<CellValue< ? extends Comparable< ? >>> rowData = new ArrayList<CellValue< ? extends Comparable< ? >>>();
List<DynamicColumn<DTColumnConfig52>> columns = widget.getGridWidget().getColumns();
for ( int iCol = 0; iCol < columns.size(); iCol++ ) {
DTColumnConfig52 col = columns.get( iCol ).getModelColumn();
DTCellValue52 dcv = new DTCellValue52( col.getDefaultValue() );
CellValue< ? extends Comparable< ? >> cv = cellValueFactory.makeCellValue( col,
0,
iCol,
dcv );
rowData.add( cv );
}
return rowData;
}
// Copy values from one (transient) model column into another
private void populateModelColumn(final ActionInsertFactCol52 col,
final ActionInsertFactCol52 editingCol) {
col.setBoundName( editingCol.getBoundName() );
col.setType( editingCol.getType() );
col.setFactField( editingCol.getFactField() );
col.setHeader( editingCol.getHeader() );
col.setValueList( editingCol.getValueList() );
col.setDefaultValue( editingCol.getDefaultValue() );
col.setHideColumn( editingCol.isHideColumn() );
col.setFactType( editingCol.getFactType() );
col.setInsertLogical( editingCol.isInsertLogical() );
}
// Copy values from one (transient) model column into another
private void populateModelColumn(final ActionSetFieldCol52 col,
final ActionSetFieldCol52 editingCol) {
col.setBoundName( editingCol.getBoundName() );
col.setType( editingCol.getType() );
col.setFactField( editingCol.getFactField() );
col.setHeader( editingCol.getHeader() );
col.setValueList( editingCol.getValueList() );
col.setDefaultValue( editingCol.getDefaultValue() );
col.setHideColumn( editingCol.isHideColumn() );
col.setUpdate( editingCol.isUpdate() );
}
// Copy values from one (transient) model column into another
private void populateModelColumn(final ConditionCol52 col,
final ConditionCol52 editingCol) {
col.setConstraintValueType( editingCol.getConstraintValueType() );
col.setFactField( editingCol.getFactField() );
col.setFieldType( editingCol.getFieldType() );
col.setHeader( editingCol.getHeader() );
col.setOperator( editingCol.getOperator() );
col.setValueList( editingCol.getValueList() );
col.setDefaultValue( editingCol.getDefaultValue() );
col.setHideColumn( editingCol.isHideColumn() );
col.setParameters( editingCol.getParameters() );
}
//Remove Otherwise state from column cells
private void removeOtherwiseStates(final DynamicColumn<DTColumnConfig52> column) {
//Grouping needs to be removed
if ( widget.getGridWidget().getData().isMerged() ) {
widget.getGridWidget().toggleMerging();
}
DynamicData data = widget.getGridWidget().getData();
for ( int iRow = 0; iRow < data.size(); iRow++ ) {
DynamicDataRow row = data.get( iRow );
CellValue< ? > cv = row.get( column.getColumnIndex() );
cv.removeState( CellState.OTHERWISE );
}
}
// Ensure the Column cell type and corresponding values are correct
private void updateCellsForDataType(final DTColumnConfig52 editColumn,
final DynamicColumn<DTColumnConfig52> column) {
//Grouping needs to be removed
if ( widget.getGridWidget().getData().isMerged() ) {
widget.getGridWidget().toggleMerging();
}
DynamicData data = widget.getGridWidget().getData();
column.setCell( cellFactory.getCell( editColumn ) );
for ( int iRow = 0; iRow < data.size(); iRow++ ) {
DynamicDataRow row = data.get( iRow );
row.set( column.getColumnIndex(),
cellValueFactory.makeCellValue( editColumn,
iRow,
column.getColumnIndex() ) );
}
}
// Ensure the values in a column are within the Value List
private boolean updateCellsForOptionValueList(final DTColumnConfig52 editColumn,
final DynamicColumn<DTColumnConfig52> column) {
boolean bRedrawRequired = false;
DynamicData data = widget.getGridWidget().getData();
List<String> vals = Arrays.asList( model.getValueList( editColumn,
sce ) );
column.setCell( cellFactory.getCell( editColumn ) );
int iCol = column.getColumnIndex();
for ( int iRow = 0; iRow < data.size(); iRow++ ) {
DynamicDataRow row = data.get( iRow );
if ( !vals.contains( row.get( iCol ).getValue() ) ) {
row.get( iCol ).setValue( null );
bRedrawRequired = true;
}
}
return bRedrawRequired;
}
// Update Row Number column values
private void updateRowNumberColumnValues(DynamicData data,
int iCol) {
int iRowNum = 1;
for ( int iRow = 0; iRow < data.size(); iRow++ ) {
DynamicDataRow row = data.get( iRow );
if ( row instanceof GroupedDynamicDataRow ) {
GroupedDynamicDataRow groupedRow = (GroupedDynamicDataRow) row;
//Setting value on a GroupedCellValue causes all children to assume the same value
groupedRow.get( iCol ).setValue( new BigDecimal( iRowNum ) );
for ( int iGroupedRow = 0; iGroupedRow < groupedRow.getChildRows().size(); iGroupedRow++ ) {
groupedRow.getChildRows().get( iGroupedRow ).get( iCol ).setValue( new BigDecimal( iRowNum ) );
iRowNum++;
}
} else {
row.get( iCol ).setValue( new BigDecimal( iRowNum ) );
iRowNum++;
}
}
}
// Update Salience column values
private void updateSalienceColumnValues(DynamicData data,
int iCol,
boolean isReverseOrder) {
if ( !isReverseOrder ) {
updateRowNumberColumnValues( data,
iCol );
} else {
//Get total row count
int rowCount = 0;
for ( int iRow = 0; iRow < data.size(); iRow++ ) {
DynamicDataRow row = data.get( iRow );
if ( row instanceof GroupedDynamicDataRow ) {
GroupedDynamicDataRow groupedRow = (GroupedDynamicDataRow) row;
rowCount = rowCount + groupedRow.getChildRows().size();
} else {
rowCount++;
}
}
int iRowNum = 0;
for ( int iRow = 0; iRow < data.size(); iRow++ ) {
DynamicDataRow row = data.get( iRow );
if ( row instanceof GroupedDynamicDataRow ) {
GroupedDynamicDataRow groupedRow = (GroupedDynamicDataRow) row;
//Setting value on a GroupedCellValue causes all children to assume the same value
groupedRow.get( iCol ).setValue( new BigDecimal( rowCount - iRowNum ) );
for ( int iGroupedRow = 0; iGroupedRow < groupedRow.getChildRows().size(); iGroupedRow++ ) {
groupedRow.getChildRows().get( iGroupedRow ).get( iCol ).setValue( new BigDecimal( rowCount - iRowNum ) );
iRowNum++;
}
} else {
row.get( iCol ).setValue( new BigDecimal( rowCount - iRowNum ) );
iRowNum++;
}
}
}
}
/**
* Check whether the given Cell can accept "otherwise" values
*
* @param cell
* @return true if the Cell can accept "otherwise" values
*/
protected boolean canAcceptOtherwiseValues(CellValue< ? > cell) {
Coordinate c = cell.getCoordinate();
MergableGridWidget<DTColumnConfig52> grid = widget.getGridWidget();
DynamicColumn<DTColumnConfig52> column = grid.getColumns().get( c.getCol() );
return canAcceptOtherwiseValues( column.getModelColumn() );
}
}