/* * Copyright 2010 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; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import org.drools.guvnor.client.common.DirtyableHorizontalPane; import org.drools.guvnor.client.common.ErrorPopup; import org.drools.guvnor.client.common.FormStylePopup; import org.drools.guvnor.client.common.ImageButton; import org.drools.guvnor.client.common.InfoPopup; import org.drools.guvnor.client.common.PrettyFormLayout; import org.drools.guvnor.client.common.SmallLabel; import org.drools.guvnor.client.common.ValueChanged; import org.drools.guvnor.client.messages.Constants; import org.drools.guvnor.client.modeldriven.ui.DatePickerTextBox; import org.drools.guvnor.client.modeldriven.ui.RuleAttributeWidget; import org.drools.guvnor.client.packages.SuggestionCompletionCache; import org.drools.guvnor.client.resources.Images; import org.drools.guvnor.client.rpc.RuleAsset; import org.drools.guvnor.client.ruleeditor.EditorWidget; import org.drools.guvnor.client.ruleeditor.RuleViewer; import org.drools.guvnor.client.ruleeditor.SaveEventListener; import org.drools.guvnor.client.util.AddButton; import org.drools.guvnor.client.util.DecoratedDisclosurePanel; import org.drools.guvnor.client.util.Format; import org.drools.guvnor.client.util.NumbericFilterKeyPressHandler; import org.drools.ide.common.client.modeldriven.SuggestionCompletionEngine; import org.drools.ide.common.client.modeldriven.brl.BaseSingleFieldConstraint; import org.drools.ide.common.client.modeldriven.dt.ActionCol; import org.drools.ide.common.client.modeldriven.dt.ActionInsertFactCol; import org.drools.ide.common.client.modeldriven.dt.ActionSetFieldCol; import org.drools.ide.common.client.modeldriven.dt.AttributeCol; import org.drools.ide.common.client.modeldriven.dt.ConditionCol; import org.drools.ide.common.client.modeldriven.dt.DTColumnConfig; import org.drools.ide.common.client.modeldriven.dt.GuidedDecisionTable; import org.drools.ide.common.client.modeldriven.dt.MetadataCol; import org.drools.ide.common.client.modeldriven.ui.ConstraintValueEditorHelper; import com.google.gwt.core.client.GWT; import com.google.gwt.event.dom.client.ChangeEvent; import com.google.gwt.event.dom.client.ChangeHandler; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.event.dom.client.KeyUpEvent; import com.google.gwt.event.dom.client.KeyUpHandler; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.CheckBox; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.Image; import com.google.gwt.user.client.ui.ListBox; import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; import com.gwtext.client.core.EventObject; import com.gwtext.client.core.SortDir; import com.gwtext.client.data.ArrayReader; import com.gwtext.client.data.FieldDef; import com.gwtext.client.data.GroupingStore; import com.gwtext.client.data.IntegerFieldDef; import com.gwtext.client.data.MemoryProxy; import com.gwtext.client.data.Record; import com.gwtext.client.data.RecordDef; import com.gwtext.client.data.SortState; import com.gwtext.client.data.Store; import com.gwtext.client.data.StringFieldDef; import com.gwtext.client.widgets.Panel; import com.gwtext.client.widgets.ToolbarMenuButton; import com.gwtext.client.widgets.Window; import com.gwtext.client.widgets.form.FieldSet; import com.gwtext.client.widgets.grid.BaseColumnConfig; import com.gwtext.client.widgets.grid.CellMetadata; import com.gwtext.client.widgets.grid.ColumnConfig; import com.gwtext.client.widgets.grid.ColumnModel; import com.gwtext.client.widgets.grid.GridPanel; import com.gwtext.client.widgets.grid.GroupingView; import com.gwtext.client.widgets.grid.Renderer; import com.gwtext.client.widgets.grid.event.ColumnModelListenerAdapter; import com.gwtext.client.widgets.grid.event.GridCellListenerAdapter; import com.gwtext.client.widgets.grid.event.GridColumnListener; import com.gwtext.client.widgets.grid.event.GridColumnListenerAdapter; import com.gwtext.client.widgets.menu.BaseItem; import com.gwtext.client.widgets.menu.Item; import com.gwtext.client.widgets.menu.Menu; import com.gwtext.client.widgets.menu.event.BaseItemListenerAdapter; /** * This is the new guided decision table editor for the web. * @author Michael Neale */ public class GuidedDecisionTableWidget extends Composite implements SaveEventListener, EditorWidget { private Constants constants = GWT.create( Constants.class ); private static Images images = GWT.create( Images.class ); private GuidedDecisionTable guidedDecisionTable; private VerticalPanel layout; private PrettyFormLayout configureColumnsNote; private GridPanel grid; private FieldDef[] fds; private VerticalPanel attributeConfigWidget; private VerticalPanel conditionsConfigWidget; private String packageName; private VerticalPanel actionsConfigWidget; private Map<String, DTColumnConfig> colMap; private SuggestionCompletionEngine sce; private GroupingStore store; private RecordDef recordDef; private GroupingsPanel groupingsPanel = null; public GuidedDecisionTableWidget(RuleAsset asset, RuleViewer viewer) { this( asset ); } public GuidedDecisionTableWidget(RuleAsset asset) { this.guidedDecisionTable = (GuidedDecisionTable) asset.content; this.packageName = asset.metaData.packageName; this.guidedDecisionTable.setTableName( asset.metaData.name ); layout = new VerticalPanel(); DecoratedDisclosurePanel disclosurePanel = new DecoratedDisclosurePanel( constants.DecisionTable() ); disclosurePanel.setWidth( "100%" ); disclosurePanel.setTitle( constants.DecisionTable() ); VerticalPanel config = new VerticalPanel(); disclosurePanel.add( config ); FieldSet conditions = new FieldSet( constants.ConditionColumns() ); conditions.setCollapsible( true ); conditions.add( getConditions() ); config.add( conditions ); FieldSet actions = new FieldSet( constants.ActionColumns() ); actions.setCollapsible( true ); actions.add( getActions() ); config.add( actions ); FieldSet grouping = new FieldSet( constants.options() ); grouping.setCollapsible( true ); grouping.setCollapsed( true ); grouping.add( getGrouping() ); grouping.add( getAttributes() ); config.add( grouping ); layout.add( disclosurePanel ); VerticalPanel buttonPanel = new VerticalPanel(); buttonPanel.add( getToolbarMenuButton() ); layout.add( buttonPanel ); configureColumnsNote = new PrettyFormLayout(); configureColumnsNote.startSection(); configureColumnsNote.addRow( new HTML( "<img src='" + new Image( images.information() ).getUrl() + "'/> " + constants.ConfigureColumnsNote() ) ); configureColumnsNote.endSection(); configureColumnsNote.setVisible( false ); layout.add( configureColumnsNote ); refreshGrid(); initWidget( layout ); } private Widget getGrouping() { this.groupingsPanel = new GroupingsPanel( guidedDecisionTable, new Command() { public void execute() { scrapeData( -1 ); refreshGrid(); } } ); return groupingsPanel; } private Widget getActions() { actionsConfigWidget = new VerticalPanel(); refreshActionsWidget(); return actionsConfigWidget; } private void refreshActionsWidget() { this.actionsConfigWidget.clear(); for ( ActionCol c : guidedDecisionTable.getActionCols() ) { HorizontalPanel hp = new HorizontalPanel(); hp.add( removeAction( c ) ); hp.add( editAction( c ) ); hp.add( new SmallLabel( c.getHeader() ) ); actionsConfigWidget.add( hp ); } actionsConfigWidget.add( newAction() ); } private Widget editAction(final ActionCol c) { return new ImageButton( images.edit(), constants.EditThisActionColumnConfiguration(), new ClickHandler() { public void onClick(ClickEvent w) { if ( c instanceof ActionSetFieldCol ) { ActionSetFieldCol asf = (ActionSetFieldCol) c; ActionSetColumn ed = new ActionSetColumn( getSCE(), guidedDecisionTable, new Command() { public void execute() { scrapeData( -1 ); refreshGrid(); refreshActionsWidget(); refreshGroupingsPanel(); } }, asf, false ); ed.show(); } else if ( c instanceof ActionInsertFactCol ) { ActionInsertFactCol asf = (ActionInsertFactCol) c; ActionInsertColumn ed = new ActionInsertColumn( getSCE(), guidedDecisionTable, new Command() { public void execute() { scrapeData( -1 ); refreshGrid(); refreshActionsWidget(); refreshGroupingsPanel(); } }, asf, false ); ed.show(); } } } ); } private Widget newAction() { AddButton addButton = new AddButton(); addButton.setText( constants.NewColumn() ); addButton.setTitle( constants.CreateANewActionColumn() ); addButton.addClickHandler( new ClickHandler() { //NON-NLS public void onClick(ClickEvent w) { final FormStylePopup pop = new FormStylePopup(); pop.setModal( false ); final ListBox choice = new ListBox(); choice.addItem( constants.SetTheValueOfAField(), "set" ); choice.addItem( constants.SetTheValueOfAFieldOnANewFact(), "insert" ); Button ok = new Button( "OK" ); ok.addClickHandler( new ClickHandler() { public void onClick(ClickEvent w) { String s = choice.getValue( choice.getSelectedIndex() ); if ( s.equals( "set" ) ) { showSet(); } else if ( s.equals( "insert" ) ) { showInsert(); } pop.hide(); } private void showInsert() { ActionInsertColumn ins = new ActionInsertColumn( getSCE(), guidedDecisionTable, new Command() { public void execute() { newActionAdded(); } }, new ActionInsertFactCol(), true ); ins.show(); } private void showSet() { ActionSetColumn set = new ActionSetColumn( getSCE(), guidedDecisionTable, new Command() { public void execute() { newActionAdded(); } }, new ActionSetFieldCol(), true ); set.show(); } private void newActionAdded() { //want to add in a blank row into the data scrapeData( guidedDecisionTable.getMetadataCols().size() + guidedDecisionTable.getAttributeCols().size() + guidedDecisionTable.getConditionCols().size() + guidedDecisionTable.getActionCols().size() + 1 ); refreshGrid(); refreshActionsWidget(); } } ); pop.addAttribute( constants.TypeOfActionColumn(), choice ); pop.addAttribute( "", ok ); pop.show(); } } ); return addButton; } private Widget removeAction(final ActionCol c) { Image del = new ImageButton( images.deleteItemSmall(), constants.RemoveThisActionColumn(), new ClickHandler() { public void onClick(ClickEvent w) { String cm = Format.format( constants.DeleteActionColumnWarning(), c.getHeader() ); if ( com.google.gwt.user.client.Window.confirm( cm ) ) { guidedDecisionTable.getActionCols().remove( c ); removeField( c.getHeader() ); scrapeData( -1 ); refreshGrid(); refreshActionsWidget(); } } } ); return del; } private Widget getConditions() { conditionsConfigWidget = new VerticalPanel(); refreshConditionsWidget(); return conditionsConfigWidget; } private void refreshConditionsWidget() { this.conditionsConfigWidget.clear(); for ( int i = 0; i < guidedDecisionTable.getConditionCols().size(); i++ ) { ConditionCol c = guidedDecisionTable.getConditionCols().get( i ); HorizontalPanel hp = new HorizontalPanel(); hp.add( removeCondition( c ) ); hp.add( editCondition( c ) ); hp.add( new SmallLabel( c.getHeader() ) ); conditionsConfigWidget.add( hp ); } conditionsConfigWidget.add( newCondition() ); } private Widget newCondition() { final ConditionCol newCol = new ConditionCol(); newCol.setConstraintValueType( BaseSingleFieldConstraint.TYPE_LITERAL ); AddButton addButton = new AddButton(); addButton.setText( constants.NewColumn() ); addButton.setTitle( constants.AddANewConditionColumn() ); addButton.addClickHandler( new ClickHandler() { //NON-NLS public void onClick(ClickEvent w) { GuidedDTColumnConfig dialog = new GuidedDTColumnConfig( getSCE(), guidedDecisionTable, new Command() { public void execute() { //want to add in a blank row into the data scrapeData( guidedDecisionTable.getMetadataCols().size() + guidedDecisionTable.getAttributeCols().size() + guidedDecisionTable.getConditionCols().size() + 1 ); refreshGrid(); refreshConditionsWidget(); refreshGroupingsPanel(); } }, newCol, true ); dialog.show(); } } ); return addButton; } private Widget editCondition(final ConditionCol c) { return new ImageButton( images.edit(), constants.EditThisColumnsConfiguration(), new ClickHandler() { public void onClick(ClickEvent w) { GuidedDTColumnConfig dialog = new GuidedDTColumnConfig( getSCE(), guidedDecisionTable, new Command() { public void execute() { scrapeData( -1 ); refreshGrid(); refreshConditionsWidget(); } }, c, false ); dialog.show(); } } ); } private SuggestionCompletionEngine getSCE() { if ( sce == null ) { this.sce = SuggestionCompletionCache.getInstance().getEngineFromCache( this.packageName ); } return sce; } private Widget removeCondition(final ConditionCol c) { Image del = new ImageButton( images.deleteItemSmall(), constants.RemoveThisConditionColumn(), new ClickHandler() { public void onClick(ClickEvent w) { String cm = Format.format( constants.DeleteConditionColumnWarning(), c.getHeader() ); if ( com.google.gwt.user.client.Window.confirm( cm ) ) { guidedDecisionTable.getConditionCols().remove( c ); removeField( c.getHeader() ); scrapeData( -1 ); refreshGrid(); refreshConditionsWidget(); } } } ); return del; } private Widget getAttributes() { attributeConfigWidget = new VerticalPanel(); refreshAttributeWidget(); return attributeConfigWidget; } private void refreshAttributeWidget() { this.attributeConfigWidget.clear(); attributeConfigWidget.add( newAttr() ); if ( guidedDecisionTable.getMetadataCols().size() > 0 ) { HorizontalPanel hp = new HorizontalPanel(); hp.add( new HTML( "  " ) ); //NON-NLS hp.add( new SmallLabel( constants.Metadata() ) ); attributeConfigWidget.add( hp ); } for ( MetadataCol at : guidedDecisionTable.getMetadataCols() ) { HorizontalPanel hp = new HorizontalPanel(); hp.add( new HTML( "    " ) ); //NON-NLS hp.add( removeMeta( at ) ); hp.add( new SmallLabel( at.attr ) ); attributeConfigWidget.add( hp ); } if ( guidedDecisionTable.getAttributeCols().size() > 0 ) { HorizontalPanel hp = new HorizontalPanel(); hp.add( new HTML( "  " ) ); //NON-NLS hp.add( new SmallLabel( constants.Attributes() ) ); attributeConfigWidget.add( hp ); } for ( AttributeCol atc : guidedDecisionTable.getAttributeCols() ) { final AttributeCol at = atc; HorizontalPanel hp = new HorizontalPanel(); hp.add( new SmallLabel( at.attr ) ); hp.add( removeAttr( at ) ); final TextBox defaultValue = new TextBox(); defaultValue.setText( at.getDefaultValue() ); defaultValue.addChangeHandler( new ChangeHandler() { public void onChange(ChangeEvent event) { at.setDefaultValue( defaultValue.getText() ); } } ); if ( at.attr.equals( RuleAttributeWidget.SALIENCE_ATTR ) ) { hp.add( new HTML( "  " ) ); final CheckBox useRowNumber = new CheckBox(); useRowNumber.setValue( at.isUseRowNumber() ); useRowNumber.addClickHandler( new ClickHandler() { public void onClick(ClickEvent sender) { at.setUseRowNumber( useRowNumber.isEnabled() ); } } ); hp.add( useRowNumber ); hp.add( new SmallLabel( constants.UseRowNumber() ) ); hp.add( new SmallLabel( "(" ) ); final CheckBox reverseOrder = new CheckBox(); reverseOrder.setValue( at.isReverseOrder() ); reverseOrder.addClickHandler( new ClickHandler() { public void onClick(ClickEvent sender) { at.setReverseOrder( reverseOrder.isEnabled() ); } } ); hp.add( reverseOrder ); hp.add( new SmallLabel( constants.ReverseOrder() ) ); hp.add( new SmallLabel( ")" ) ); } hp.add( new HTML( "    " ) ); //NON-NLS hp.add( new SmallLabel( constants.DefaultValue() ) ); hp.add( defaultValue ); final CheckBox hide = new CheckBox(); hide.setValue( at.isHideColumn() ); hide.addClickHandler( new ClickHandler() { public void onClick(ClickEvent sender) { at.setHideColumn( hide.isEnabled() ); } } ); hp.add( hide ); hp.add( new SmallLabel( constants.HideThisColumn() ) ); attributeConfigWidget.add( hp ); } } private Widget newAttr() { ImageButton but = new ImageButton( images.newItem(), constants.AddANewAttributeMetadata(), new ClickHandler() { public void onClick(ClickEvent w) { //show choice of attributes final FormStylePopup pop = new FormStylePopup( images.config(), constants.AddAnOptionToTheRule() ); final ListBox list = RuleAttributeWidget.getAttributeList(); final Image addbutton = new ImageButton( images.newItem() ); final TextBox box = new TextBox(); box.setVisibleLength( 15 ); list.setSelectedIndex( 0 ); list.addChangeHandler( new ChangeHandler() { public void onChange(ChangeEvent event) { AttributeCol attr = new AttributeCol(); attr.attr = list.getItemText( list.getSelectedIndex() ); guidedDecisionTable.getAttributeCols().add( attr ); scrapeData( guidedDecisionTable.getMetadataCols().size() + guidedDecisionTable.getAttributeCols().size() + 1 ); refreshGrid(); refreshAttributeWidget(); pop.hide(); } } ); addbutton.setTitle( constants.AddMetadataToTheRule() ); addbutton.addClickHandler( new ClickHandler() { public void onClick(ClickEvent w) { MetadataCol met = new MetadataCol(); met.attr = box.getText(); guidedDecisionTable.getMetadataCols().add( met ); scrapeData( guidedDecisionTable.getMetadataCols().size() + 1 ); refreshGrid(); refreshAttributeWidget(); pop.hide(); } } ); DirtyableHorizontalPane horiz = new DirtyableHorizontalPane(); horiz.add( box ); horiz.add( addbutton ); pop.addAttribute( constants.Metadata1(), horiz ); pop.addAttribute( constants.Attribute(), list ); pop.show(); } } ); HorizontalPanel h = new HorizontalPanel(); h.add( new SmallLabel( constants.AddAttributeMetadata() ) ); h.add( but ); return h; } private Widget removeAttr(final AttributeCol at) { Image del = new ImageButton( images.deleteItemSmall(), constants.RemoveThisAttribute(), new ClickHandler() { public void onClick(ClickEvent w) { String ms = Format.format( constants.DeleteActionColumnWarning(), at.attr ); if ( com.google.gwt.user.client.Window.confirm( ms ) ) { guidedDecisionTable.getAttributeCols().remove( at ); removeField( at.attr ); scrapeData( -1 ); refreshGrid(); refreshAttributeWidget(); } } } ); return del; } private Widget removeMeta(final MetadataCol md) { Image del = new ImageButton( images.deleteItemSmall(), constants.RemoveThisMetadata(), new ClickHandler() { public void onClick(ClickEvent w) { String ms = Format.format( constants.DeleteActionColumnWarning(), md.attr ); if ( com.google.gwt.user.client.Window.confirm( ms ) ) { guidedDecisionTable.getMetadataCols().remove( md ); removeField( md.attr ); scrapeData( -1 ); refreshGrid(); refreshAttributeWidget(); } } } ); return del; } /** * Here we read the record data from the grid into the data in the model. * if we have an insertCol - then a new empty column of data will be added in that * row position. */ private void scrapeData(int insertCol) { Record[] recs = grid.getStore().getRecords(); guidedDecisionTable.setData( new String[recs.length][] ); for ( int i = 0; i < recs.length; i++ ) { Record r = recs[i]; if ( insertCol == -1 ) { String[] row = new String[fds.length]; guidedDecisionTable.getData()[i] = row; for ( int j = 0; j < fds.length; j++ ) { row[j] = r.getAsString( fds[j].getName() ); } } else { String[] row = new String[fds.length + 1]; guidedDecisionTable.getData()[i] = row; for ( int j = 0; j < fds.length; j++ ) { if ( j < insertCol ) { row[j] = r.getAsString( fds[j].getName() ); } else if ( j >= insertCol ) { row[j + 1] = r.getAsString( fds[j].getName() ); } } } } } /** * removes the field from the field def. * @param headerName */ private void removeField(String headerName) { FieldDef[] fds_ = new FieldDef[fds.length - 1]; int new_i = 0; for ( int i = 0; i < fds.length; i++ ) { FieldDef fd = fds[i]; if ( !fd.getName().equals( headerName ) ) { fds_[new_i] = fd; new_i++; } } this.fds = fds_; refreshGroupingsPanel(); } private void refreshGroupingsPanel() { if ( groupingsPanel != null ) { groupingsPanel.refresh(); } } private void refreshGrid() { configureColumnsNote.setVisible( guidedDecisionTable.getActionCols().size() == 0 && guidedDecisionTable.getConditionCols().size() == 0 && guidedDecisionTable.getActionCols().size() == 0 ); if ( layout.getWidgetIndex( grid ) >= 0 ) { layout.remove( grid ); } grid = doGrid(); layout.add( grid ); } private GridPanel doGrid() { fds = new FieldDef[guidedDecisionTable.getMetadataCols().size() + guidedDecisionTable.getAttributeCols().size() + guidedDecisionTable.getActionCols().size() + guidedDecisionTable.getConditionCols().size() + 2]; //its +2 as we have counter and description data colMap = new HashMap<String, DTColumnConfig>(); fds[0] = new IntegerFieldDef( "num" ); //NON-NLS fds[1] = new StringFieldDef( "desc" ); //NON-NLS int colCount = 0; BaseColumnConfig[] cols = new BaseColumnConfig[fds.length]; //its +1 as we have the separator -> thing. cols[0] = new ColumnConfig() { { setDataIndex( "num" ); //NON-NLS setWidth( 60 ); setSortable( false ); setHeader( "Row Number" ); setRenderer( new Renderer() { public String render(Object value, CellMetadata cellMetadata, Record record, int rowIndex, int colNum, Store store) { return "<span class='x-grid3-cell-inner x-grid3-td-numberer'>" + (rowIndex + 1) + "</span>"; //NON-NLS } } ); } }; colCount++; cols[1] = new ColumnConfig() { { setDataIndex( "desc" ); //NON-NLS setSortable( true ); setHeader( constants.Description() ); if ( guidedDecisionTable.getDescriptionWidth() != -1 ) { setWidth( guidedDecisionTable.getDescriptionWidth() ); } } }; colCount++; //now to metadata for ( int i = 0; i < guidedDecisionTable.getMetadataCols().size(); i++ ) { final MetadataCol attr = guidedDecisionTable.getMetadataCols().get( i ); fds[colCount] = new StringFieldDef( attr.attr ); cols[colCount] = new ColumnConfig() { { setHeader( attr.attr ); setDataIndex( attr.attr ); setSortable( true ); if ( attr.getWidth() != -1 ) { setWidth( attr.getWidth() ); } if ( attr.isHideColumn() ) { setHidden( true ); } } }; colMap.put( attr.attr, attr ); colCount++; } //now to attributes for ( int i = 0; i < guidedDecisionTable.getAttributeCols().size(); i++ ) { final AttributeCol attr = guidedDecisionTable.getAttributeCols().get( i ); fds[colCount] = new StringFieldDef( attr.attr ); cols[colCount] = new ColumnConfig() { { setHeader( attr.attr ); setDataIndex( attr.attr ); setSortable( true ); if ( attr.getWidth() != -1 ) { setWidth( attr.getWidth() ); } if ( attr.isHideColumn() ) { setHidden( true ); } } }; colMap.put( attr.attr, attr ); colCount++; } //do all the condition cols for ( int i = 0; i < guidedDecisionTable.getConditionCols().size(); i++ ) { //here we could also deal with numeric type? final ConditionCol c = guidedDecisionTable.getConditionCols().get( i ); fds[colCount] = new StringFieldDef( c.getHeader() ); cols[colCount] = new ColumnConfig() { { setHeader( c.getHeader() ); setDataIndex( c.getHeader() ); setSortable( true ); if ( c.getWidth() != -1 ) { setWidth( c.getWidth() ); } if ( c.isHideColumn() ) { setHidden( true ); } } }; colMap.put( c.getHeader(), c ); colCount++; } for ( int i = 0; i < guidedDecisionTable.getActionCols().size(); i++ ) { //here we could also deal with numeric type? final ActionCol c = guidedDecisionTable.getActionCols().get( i ); fds[colCount] = new StringFieldDef( c.getHeader() ); cols[colCount] = new ColumnConfig() { { setHeader( c.getHeader() ); setDataIndex( c.getHeader() ); //and here we do the appropriate editor setSortable( true ); if ( c.getWidth() != -1 ) { setWidth( c.getWidth() ); } if ( c.isHideColumn() ) { setHidden( true ); } } }; colMap.put( c.getHeader(), c ); colCount++; } recordDef = new RecordDef( fds ); ArrayReader reader = new ArrayReader( recordDef ); MemoryProxy proxy = new MemoryProxy( guidedDecisionTable.getData() ); ColumnModel cm = new ColumnModel( cols ); store = new GroupingStore(); store.setReader( reader ); store.setDataProxy( proxy ); store.setSortInfo( new SortState( "num", SortDir.ASC ) ); //NON-NLS if ( this.guidedDecisionTable.getGroupField() != null ) { store.setGroupField( guidedDecisionTable.getGroupField() ); } cm.addListener( new ColumnModelListenerAdapter() { public void onHiddenChange(ColumnModel cm, int colIndex, boolean hidden) { final String dta = cm.getDataIndex( colIndex ); if ( colMap.containsKey( dta ) ) { DTColumnConfig col = colMap.get( dta ); col.setHideColumn( hidden ); } } } ); store.load(); final GridPanel grid = new GridPanel( store, cm ); grid.setStripeRows( true ); grid.addGridColumnListener( new GridColumnListener() { public void onColumnMove(GridPanel grid, int oldIndex, int newIndex) { if ( DecisionTableHandler.validateMove( guidedDecisionTable, oldIndex, newIndex ) ) { // Save any changes to the dt.data. scrapeData( -1 ); DecisionTableHandler.moveColumn( guidedDecisionTable, oldIndex, newIndex ); grid = doGrid(); } else { // Refresh undoes the move. refreshGrid(); ErrorPopup.showMessage( constants.CanNotMoveColumnsFromOneTypeGroupToAnother() ); } } public void onColumnResize(GridPanel grid, int colIndex, int newSize) { // Nothing } } ); GroupingView gv = new GroupingView(); //to stretch it out gv.setForceFit( true ); gv.setGroupTextTpl( "{text} ({[values.rs.length]} {[values.rs.length > 1 ? \"" //NON-NLS + constants.Items() + "\" : \"" + constants.Item() + "\"]})" ); grid.setView( gv ); grid.setStore( store ); int width = 900; if ( cm.getColumnCount() > 10 ) { width = 900 + (90 * (cm.getColumnCount() - 10)); } grid.setWidth( width ); grid.setHeight( 500 ); //Add the cell listener for when the user wants to edit. grid.addGridCellListener( new GridCellListenerAdapter() { public void onCellDblClick(GridPanel grid, int rowIndex, int colIndex, EventObject e) { final String dataIdx = grid.getColumnModel().getDataIndex( colIndex ); final Record r = store.getAt( rowIndex ); String val = r.getAsString( dataIdx ); DTColumnConfig colConf = colMap.get( dataIdx ); String[] vals = guidedDecisionTable.getValueList( colConf, getSCE() ); if ( vals.length == 0 ) { showTextEditor( e, dataIdx, r, val, colConf ); } else { showDropDownEditor( e, dataIdx, r, val, vals ); } } } ); //remember any size changes grid.addGridColumnListener( new GridColumnListenerAdapter() { public void onColumnResize(GridPanel grid, int colIndex, int newSize) { final String dta = grid.getColumnModel().getDataIndex( colIndex ); if ( dta.equals( "desc" ) ) { //NON-NLS guidedDecisionTable.setDescriptionWidth( newSize ); } else { if ( colMap.containsKey( dta ) ) { DTColumnConfig col = colMap.get( dta ); col.setWidth( newSize ); } } } } ); return grid; } private ToolbarMenuButton getToolbarMenuButton() { Menu menu = new Menu(); menu.addItem( new Item( constants.AddRow(), new BaseItemListenerAdapter() { public void onClick(BaseItem item, EventObject e) { Record r = recordDef.createRecord( new Object[recordDef.getFields().length] ); r.set( "num", store.getRecords().length + 1 ); //NON-NLS store.add( r ); renumberSalience( store.getRecords() ); } } ) ); menu.addItem( new Item( constants.AddRowBeforeSelectedRow(), new BaseItemListenerAdapter() { public void onClick(BaseItem item, EventObject e) { Record[] selectedRows = grid.getSelectionModel().getSelections(); if ( selectedRows.length == 1 ) { int selected = selectedRows[0].getAsInteger( "num" ); Record newRecord = recordDef.createRecord( new Object[recordDef.getFields().length] ); Record[] records = store.getRecords(); for ( int i = 0; i < records.length; i++ ) { Record temp = records[i]; int num = temp.getAsInteger( "num" ); if ( num == selected ) { newRecord.set( "num", num ); //NON-NLS temp.set( "num", num + 1 ); //NON-NLS store.addSorted( newRecord ); } else if ( num > selected ) { temp.set( "num", num + 1 ); //NON-NLS } } renumberSalience( store.getRecords() ); } else { ErrorPopup.showMessage( constants.PleaseSelectARow() ); } } } ) ); menu.addItem( new Item( constants.RemoveSelectedRowS(), new BaseItemListenerAdapter() { public void onClick(BaseItem item, EventObject e) { Record[] selected = grid.getSelectionModel().getSelections(); if ( com.google.gwt.user.client.Window.confirm( constants.AreYouSureYouWantToDeleteTheSelectedRowS() ) ) { for ( int i = 0; i < selected.length; i++ ) { store.remove( selected[i] ); } renumber( store.getRecords() ); renumberSalience( store.getRecords() ); } } } ) ); menu.addItem( new Item( constants.CopySelectedRowS(), new BaseItemListenerAdapter() { public void onClick(BaseItem item, EventObject e) { Record[] selected = grid.getSelectionModel().getSelections(); for ( int i = 0; i < selected.length; i++ ) { Record r = recordDef.createRecord( new Object[recordDef.getFields().length] ); Record orig = selected[i]; for ( int j = 0; j < fds.length; j++ ) { r.set( fds[j].getName(), orig.getAsString( fds[j].getName() ) ); } store.add( r ); } renumber( store.getRecords() ); renumberSalience( store.getRecords() ); } } ) ); ToolbarMenuButton tbb = new ToolbarMenuButton( constants.Modify(), menu ); return tbb; } /** * Show a drop down editor, obviously. */ private void showDropDownEditor(EventObject e, final String dataIdx, final Record r, String val, String[] vals) { final Window w = new Window(); w.setWidth( 200 ); w.setPlain( true ); w.setBodyBorder( false ); w.setAutoDestroy( true ); w.setTitle( dataIdx ); final ListBox drop = new ListBox(); for ( int i = 0; i < vals.length; i++ ) { String v = vals[i].trim(); if ( v.indexOf( '=' ) > 0 ) { String[] splut = ConstraintValueEditorHelper.splitValue( v ); drop.addItem( splut[1], splut[0] ); if ( splut[0].equals( val ) ) { drop.setSelectedIndex( i ); } } else { drop.addItem( v, v ); if ( v.equals( val ) ) { drop.setSelectedIndex( i ); } } } drop.addKeyUpHandler( new KeyUpHandler() { public void onKeyUp(KeyUpEvent event) { if ( event.getNativeKeyCode() == KeyCodes.KEY_ENTER ) { r.set( dataIdx, drop.getValue( drop.getSelectedIndex() ) ); w.destroy(); } } } ); Panel p = new Panel(); p.add( drop ); w.add( p ); w.setBorder( false ); Button ok = new Button( constants.OK() ); ok.addClickHandler( new ClickHandler() { public void onClick(ClickEvent wg) { r.set( dataIdx, drop.getValue( drop.getSelectedIndex() ) ); w.destroy(); } } ); p.add( ok ); w.setPosition( e.getPageX(), e.getPageY() ); w.show(); } private void renumber(Record[] rs) { for ( int i = 0; i < rs.length; i++ ) { rs[i].set( "num", "" + (i + 1) ); //NON-NLS } } private void renumberSalience(Record[] rs) { List<AttributeCol> attcols = guidedDecisionTable.getAttributeCols(); for ( AttributeCol ac : attcols ) { if ( ac.isUseRowNumber() ) { for ( int i = 0; i < rs.length; i++ ) { Record nextrecord = rs[i]; List<String> allFields = Arrays.asList( nextrecord.getFields() ); if ( allFields.contains( "salience" ) ) { if ( ac.isReverseOrder() ) { rs[i].set( "salience", "" + (rs.length - i) ); //NON-NLS } else { rs[i].set( "salience", "" + (i + 1) ); //NON-NLS } } } } break; } } /** * Show a plain old text editor for a cell. */ private void showTextEditor(EventObject e, final String dta, final Record r, String val, DTColumnConfig colConf) { final Window w = new Window(); w.setWidth( 200 ); w.setAutoDestroy( true ); w.setPlain( true ); w.setBodyBorder( false ); w.setTitle( dta ); String typeDescription = guidedDecisionTable.getType( colConf, getSCE() ); Panel p = new Panel(); if ( typeDescription != null && typeDescription.equals( SuggestionCompletionEngine.TYPE_DATE ) ) { final DatePickerTextBox datePicker = new DatePickerTextBox( val ); String m = Format.format( ((Constants) GWT.create( Constants.class )).ValueFor0(), dta ); datePicker.setTitle( m ); datePicker.addValueChanged( new ValueChanged() { public void valueChanged(String newValue) { r.set( dta, newValue ); } } ); p.add( datePicker ); p.add( new InfoPopup( constants.CategoryParentRules(), Format.format( constants.FillInColumnWithValue(), typeDescription ) ) ); w.add( p ); w.setBorder( false ); Button ok = new Button( constants.OK() ); ok.addClickHandler( new ClickHandler() { public void onClick(ClickEvent arg0) { r.set( dta, datePicker.getDateString() ); w.destroy(); } } ); p.add( ok ); } else { final TextBox box = new TextBox(); box.setText( val ); box.addKeyUpHandler( new KeyUpHandler() { public void onKeyUp(KeyUpEvent event) { if ( event.getNativeKeyCode() == KeyCodes.KEY_ENTER ) { r.set( dta, box.getText() ); w.destroy(); } } } ); if ( guidedDecisionTable.isNumeric( colConf, getSCE() ) ) { box.addKeyPressHandler( new NumbericFilterKeyPressHandler( box ) ); } p.add( box ); if ( typeDescription != null ) { p.add( new InfoPopup( constants.CategoryParentRules(), Format.format( constants.FillInColumnWithValue(), typeDescription ) ) ); } w.add( p ); w.setBorder( false ); Button ok = new Button( constants.OK() ); ok.addClickHandler( new ClickHandler() { public void onClick(ClickEvent wg) { r.set( dta, box.getText() ); w.destroy(); } } ); p.add( ok ); } w.setPosition( e.getPageX(), e.getPageY() ); w.show(); } /** * Need to copy the data from the record store. */ public void onSave() { String[] fields = store.getFields(); for ( int i = 0; i < fields.length; i++ ) { System.out.print( fields[i] + " | " ); } this.scrapeData( -1 ); } public void onAfterSave() { //not needed. } }