/*
* 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.modeldriven.ui;
import java.util.ArrayList;
import java.util.List;
import org.drools.guvnor.client.util.GWTDateConverter;
import org.drools.guvnor.client.widgets.decoratedgrid.CellValue;
import org.drools.guvnor.client.widgets.decoratedgrid.DecoratedGridHeaderWidget;
import org.drools.guvnor.client.widgets.decoratedgrid.DecoratedGridSidebarWidget;
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.VerticalDecoratedGridSidebarWidget;
import org.drools.guvnor.client.widgets.decoratedgrid.VerticalDecoratedGridWidget;
import org.drools.guvnor.client.widgets.decoratedgrid.data.DynamicData;
import org.drools.guvnor.client.widgets.decoratedgrid.data.DynamicDataRow;
import org.drools.ide.common.client.modeldriven.SuggestionCompletionEngine;
import org.drools.ide.common.client.modeldriven.dt.TemplateModel;
import org.drools.ide.common.client.modeldriven.dt.TemplateModel.InterpolationVariable;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.user.client.ui.Composite;
/**
* A table in which Template data can be edited
*/
public class TemplateDataTableWidget extends Composite
implements
HasRows,
HasColumns<TemplateDataColumn> {
// Decision Table data
protected DecoratedGridWidget<TemplateDataColumn> widget;
protected TemplateDataCellFactory cellFactory;
protected TemplateDataCellValueFactory cellValueFactory;
protected SuggestionCompletionEngine sce;
/**
* Constructor
*/
public TemplateDataTableWidget(SuggestionCompletionEngine sce) {
if ( sce == null ) {
throw new IllegalArgumentException( "sce cannot be null" );
}
this.sce = sce;
// Construct the widget from which we're composed
widget = new VerticalDecoratedGridWidget<TemplateDataColumn>();
DecoratedGridHeaderWidget<TemplateDataColumn> header = new TemplateDataHeaderWidget( widget );
DecoratedGridSidebarWidget<TemplateDataColumn> sidebar = new VerticalDecoratedGridSidebarWidget<TemplateDataColumn>( widget,
this );
widget.setHeaderWidget( header );
widget.setSidebarWidget( sidebar );
this.cellFactory = new TemplateDataCellFactory( sce,
widget.getGridWidget() );
this.cellValueFactory = new TemplateDataCellValueFactory( sce );
//Date converter is injected so a GWT compatible one can be used here and another in testing
TemplateDataCellValueFactory.injectDateConvertor( GWTDateConverter.getInstance() );
initWidget( widget );
}
/**
* Add a column to the end of the table
*/
public void addColumn(TemplateDataColumn modelColumn) {
if ( modelColumn == null ) {
throw new IllegalArgumentException(
"modelColumn cannot be null." );
}
addColumn( modelColumn,
true );
}
/**
* Append a row to the end of the table
*/
public void appendRow() {
List<CellValue< ? extends Comparable< ? >>> rowData = makeRowData();
widget.insertRowBefore( null,
rowData );
}
/**
* Delete a column
*/
public void deleteColumn(TemplateDataColumn modelColumn) {
if ( modelColumn == null ) {
throw new IllegalArgumentException(
"modelColumn cannot be null." );
}
DynamicColumn<TemplateDataColumn> col = getDynamicColumn( modelColumn );
widget.deleteColumn( col );
}
/**
* Delete a row
*/
public void deleteRow(DynamicDataRow row) {
if ( row == null ) {
throw new IllegalArgumentException( "row cannot be null" );
}
widget.deleteRow( row );
}
/**
* Insert a row before that provided
*
* @param rowBefore
* the row before which the new row should be inserted
*/
public void insertRowBefore(DynamicDataRow rowBefore) {
if ( rowBefore == null ) {
throw new IllegalArgumentException( "rowBefore cannot be null" );
}
List<CellValue< ? extends Comparable< ? >>> rowData = makeRowData();
widget.insertRowBefore( rowBefore,
rowData );
}
public void scrapeData(TemplateModel model) {
model.clearRows();
final DynamicData data = widget.getGridWidget().getData().getFlattenedData();
final List<DynamicColumn<TemplateDataColumn>> columns = widget.getGridWidget().getColumns();
int columnCount = columns.size();
for ( DynamicDataRow row : data ) {
String[] rowData = new String[columnCount];
for ( int iCol = 0; iCol < columnCount; iCol++ ) {
CellValue< ? > cv = row.get( iCol );
DynamicColumn<TemplateDataColumn> column = columns.get( iCol );
String serialisedValue = cellValueFactory.convertValueToString( column.getModelColumn(),
cv );
rowData[iCol] = serialisedValue;
}
model.addRow( rowData );
}
}
/**
* Set column visibility
*/
public void setColumnVisibility(TemplateDataColumn modelColumn,
boolean isVisible) {
if ( modelColumn == null ) {
throw new IllegalArgumentException( "modelColumn cannot be null" );
}
DynamicColumn<TemplateDataColumn> col = getDynamicColumn( modelColumn );
widget.setColumnVisibility( col.getColumnIndex(),
isVisible );
}
/**
* Set the model to render in the table
*
* @param model
*/
public void setModel(TemplateModel model) {
if ( model == null ) {
throw new IllegalArgumentException( "model cannot be null" );
}
//Get interpolation variables
InterpolationVariable[] vars = model.getInterpolationVariablesList();
if ( vars.length == 0 ) {
return;
}
//Add corresponding columns to table
for ( InterpolationVariable var : vars ) {
addColumn( new TemplateDataColumn( var.getVarName(),
var.getDataType(),
var.getFactType(),
var.getFactField() ),
false );
}
//Set row data
String[][] data = model.getTableAsArray();
final List<DynamicColumn<TemplateDataColumn>> columns = widget.getGridWidget().getColumns();
for ( int iRow = 0; iRow < data.length; iRow++ ) {
List<CellValue< ? extends Comparable< ? >>> row = new ArrayList<CellValue< ? extends Comparable< ? >>>();
String[] rowData = data[iRow];
for ( int iCol = 0; iCol < columns.size(); iCol++ ) {
TemplateDataColumn col = columns.get( iCol ).getModelColumn();
//Underlying Template model uses empty Strings as null values; which is quite different in the MergedGrid world
String initialValue = rowData[iCol];
if ( initialValue != null && initialValue.equals( "" ) ) {
initialValue = null;
}
CellValue< ? extends Comparable< ? >> cv = cellValueFactory.makeCellValue( col,
iRow,
iCol,
initialValue );
row.add( cv );
}
widget.insertRowBefore( null,
row );
}
// Draw header first as the size of child Elements depends upon it
widget.getHeaderWidget().redraw();
// Schedule redraw of grid after sizes of child Elements have been set
Scheduler.get().scheduleDeferred( new ScheduledCommand() {
public void execute() {
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 );
}
// Add column to table with optional redraw
private void addColumn(TemplateDataColumn modelColumn,
boolean bRedraw) {
int index = widget.getGridWidget().getColumns().size();
insertColumnBefore( modelColumn,
index,
bRedraw );
}
// Retrieves the DynamicColumn relating to the Model column or null if it
// cannot be found
private DynamicColumn<TemplateDataColumn> getDynamicColumn(TemplateDataColumn modelCol) {
DynamicColumn<TemplateDataColumn> column = null;
List<DynamicColumn<TemplateDataColumn>> columns = widget.getGridWidget().getColumns();
for ( DynamicColumn<TemplateDataColumn> dc : columns ) {
if ( dc.getModelColumn().equals( modelCol ) ) {
column = dc;
break;
}
}
return column;
}
// Insert a new model column at the specified index
private void insertColumnBefore(TemplateDataColumn modelColumn,
int index,
boolean bRedraw) {
// Create new column for grid
DynamicColumn<TemplateDataColumn> column = new DynamicColumn<TemplateDataColumn>( modelColumn,
cellFactory.getCell( modelColumn ),
index );
column.setVisible( true );
// Create column data
List<CellValue< ? extends Comparable< ? >>> columnData = makeColumnData( modelColumn,
index );
// Add column and data to grid
if ( index < widget.getGridWidget().getColumns().size() ) {
DynamicColumn<TemplateDataColumn> columnBefore = widget.getGridWidget().getColumns().get( index );
widget.insertColumnBefore( columnBefore,
column,
columnData,
bRedraw );
} else {
widget.appendColumn( column,
columnData,
bRedraw );
}
}
// Make a row of data for insertion into a DecoratedGridWidget
private List<CellValue< ? extends Comparable< ? >>> makeColumnData(TemplateDataColumn column,
int colIndex) {
int dataSize = this.widget.getGridWidget().getData().size();
List<CellValue< ? extends Comparable< ? >>> columnData = new ArrayList<CellValue< ? extends Comparable< ? >>>();
for ( int iRow = 0; iRow < dataSize; iRow++ ) {
CellValue< ? extends Comparable< ? >> cv = cellValueFactory.makeCellValue( column,
iRow,
colIndex );
columnData.add( cv );
}
return columnData;
}
// Construct a new row for insertion into a DecoratedGridWidget
private List<CellValue< ? extends Comparable< ? >>> makeRowData() {
List<CellValue< ? extends Comparable< ? >>> row = new ArrayList<CellValue< ? extends Comparable< ? >>>();
List<DynamicColumn<TemplateDataColumn>> columns = widget.getGridWidget().getColumns();
for ( int iCol = 0; iCol < columns.size(); iCol++ ) {
TemplateDataColumn col = columns.get( iCol ).getModelColumn();
CellValue< ? extends Comparable< ? >> cv = cellValueFactory.makeCellValue( col,
0,
iCol );
row.add( cv );
}
return row;
}
}