/* * Copyright 2013 State University of New York at Oswego * * 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 edu.oswego.csc480_hci521_2013.client.ui; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import com.google.gwt.core.client.GWT; import com.google.gwt.event.dom.client.ChangeEvent; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.resources.client.CssResource; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.uibinder.client.UiHandler; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.DoubleBox; import com.google.gwt.user.client.ui.FlexTable; import com.google.gwt.user.client.ui.IntegerBox; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.ListBox; import com.google.gwt.user.client.ui.PopupPanel; import com.google.gwt.user.client.ui.ScrollPanel; import com.google.gwt.user.client.ui.Widget; import com.google.gwt.user.client.ui.HorizontalPanel; import edu.oswego.csc480_hci521_2013.client.presenters.RfParametersPresenter; import edu.oswego.csc480_hci521_2013.shared.h2o.json.ColumnEnumValues; import edu.oswego.csc480_hci521_2013.shared.h2o.json.Inspect.Column; import edu.oswego.csc480_hci521_2013.shared.h2o.urlbuilders.ColumnEnumValuesBuilder; import edu.oswego.csc480_hci521_2013.shared.h2o.urlbuilders.RFBuilder; import java.util.ArrayList; import java.util.HashMap; /** * @author Michael Hayes * TODO: Need better way to handle other default value such as number of trees. * TODO: Input sanity checks such as numTrees is an integer. */ public class RfParametersViewImpl extends PopupPanel implements RfParametersPresenter.View { static final Logger logger = Logger.getLogger(RfParametersPresenter.View.class.getName()); interface Style extends CssResource { String error(); } interface Binder extends UiBinder<Widget, RfParametersViewImpl> {} private static Binder uiBinder = GWT.create(Binder.class); private RfParametersPresenter presenter; private List<String> columnHeaders; //Headers of the data columns from the data source. private Column[] columns; //Column definitions from the data source; @UiField ListBox classVars; @UiField IntegerBox numTrees; @UiField ListBox ignoreCols; @UiField Button submit; @UiField Button cancel; @UiField Label errorLabel; @UiField ScrollPanel classWeightsScrollPanel; @UiField FlexTable classWeights; public RfParametersViewImpl() { setWidget(uiBinder.createAndBindUi(this)); } @Override public void buildUi() { numTrees.setText("50"); } //Called when classVars selection is changed. @UiHandler("classVars") public void onChange(ChangeEvent event){ int selectedIndex = classVars.getSelectedIndex(); String selectedName = classVars.getValue(selectedIndex); setIgnoreColumns(selectedName); setClassWeights(selectedName); } @UiHandler("submit") public void onSubmitClick(ClickEvent event){ RFBuilder builder = new RFBuilder(presenter.getDataKey()); //TODO: Should probably alert the user instead of defaulting to 50. if(numTrees == null || numTrees.getValue() == null || numTrees.getValue() <= 0) builder.setNtree(50); else builder.setNtree(numTrees.getValue()); int classVarSelected = classVars.getSelectedIndex(); String classVarVal = classVars.getValue(classVarSelected); builder.setResponseVariable(classVarVal); for(int i = 0; i < ignoreCols.getItemCount(); i++){ if(ignoreCols.isItemSelected(i)){ Integer ignoreThis = Integer.valueOf(ignoreCols.getValue(i)); builder.setIgnore(ignoreThis); builder.storeIgnore(ignoreCols.getItemText(i)); } } //Set class weights into builder HashMap<String, Double> values = new HashMap<String,Double>(); for(int row = 0; row < classWeights.getRowCount(); row++){ String label = classWeights.getText(row, 0); DoubleBox value = (DoubleBox) classWeights.getWidget(row,1); values.put(label,value.getValue()); }; builder.setClassWeights(values); presenter.fireRFParameterEvent(builder); //this.hide(); } @UiHandler("cancel") public void onCancelClick(ClickEvent event){ this.hide(); } @Override public void setHeaders(List<String> headers){ this.columnHeaders = headers; //Only add a selectable header if it is an int or enum column. //If it is an int, must be >=2 and <= 254 for(int i = 0 ; i < columns.length ; i++){ if((columns[i].getType().equals("int") && columns[i].getMin() >= 2 && columns[i].getMax() <= 254) || ( columns[i].getType().equals("enum") && columns[i].getEnumDomainSize() >= 2 && columns[i].getEnumDomainSize() <= 254)) { classVars.addItem(columns[i].getName()); } } //Select the first valid response column //Setup the ignore columns //Setup the class weights. for(int i = 0; i < columns.length; i++){ if((columns[i].getType().equals("int") && columns[i].getMin() >= 2 && columns[i].getMax() <= 254) || ( columns[i].getType().equals("enum") && columns[i].getEnumDomainSize() >= 2 && columns[i].getEnumDomainSize() <= 254)) { setClassWeights(columns[i].getName()); setIgnoreColumns(columns[i].getName()); break; } } classVars.setItemSelected(0,true); } //Set the column definition info. //Calls setHeaders(...) @Override public void setColumnInfo(Column[] cols){ this.columns = cols; List<String> headers = new ArrayList<String>(); for(int i = 0 ; i < columns.length ; i++){ headers.add(columns[i].getName()); } setHeaders(headers); } //Setup the class weights selections corresponding with the selected //response variable. public void setClassWeights(String selectedVariableName){ Column selected = null; int columnNumber = 0; for(Column col : columns){ if(col.getName().equals(selectedVariableName)){ selected = col; break; } columnNumber++; } if(selected != null){ classWeights = new FlexTable(); classWeightsScrollPanel.clear(); classWeightsScrollPanel.add(classWeights); classWeights.setText(0,0,"Class"); classWeights.setText(0,1,"Weight"); ColumnEnumValuesBuilder builder; builder = new ColumnEnumValuesBuilder(presenter.getDataKey(), columnNumber); //Call the GWT RPC service to get the column values. presenter.getH2OService().getColumnEnumValues(builder, new AsyncCallback<ColumnEnumValues>() { @Override public void onFailure(Throwable thrwbl) { logger.log(Level.SEVERE, thrwbl.toString()); setError(thrwbl.getMessage()); } @Override public void onSuccess(final ColumnEnumValues vals) { String[] values = vals.getValues(); for(int i = 0; i < values.length; i++){ classWeights.setText(i, 0, values[i]); DoubleBox inputBox = new DoubleBox(); inputBox.setValue(1.0); inputBox.setWidth("50px"); classWeights.setWidget(i, 1, inputBox); } } } ); } else { throw new NullPointerException("Could not find selected classification variable column."); } } //Set the available ignore columns to everything excepted the selected class var public void setIgnoreColumns(String selected){ ignoreCols.clear(); //for(String column : columnHeaders){ for(int i = 0; i < columnHeaders.size(); i++){ String column = columnHeaders.get(i); if(!column.equals(selected)) ignoreCols.addItem(column, Integer.toString(i)); } ignoreCols.setVisibleItemCount(columnHeaders.size()); } @Override public void showPopUp(){ final PopupPanel me = this; this.setPopupPositionAndShow(new PopupPanel.PositionCallback() { public void setPosition(int offsetWidth, int offsetHeight){ int left = 100; int top = 140; me.setPopupPosition(left, top); } }); } @Override public void hidePopup(){ this.hide(); } @Override public void setError(String error){ errorLabel.setText(error); } @Override public void setPresenter(RfParametersPresenter presenter) { this.presenter = presenter; } @Override public Widget asWidget() { return this; } }