/* * 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.activity; import com.google.gwt.activity.shared.AbstractActivity; import com.google.gwt.event.shared.EventBus; import com.google.gwt.place.shared.Place; import com.google.gwt.place.shared.PlaceController; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.AcceptsOneWidget; import com.google.gwt.user.client.ui.MenuItem; import edu.oswego.csc480_hci521_2013.client.AppPlaceHistoryMapper; import edu.oswego.csc480_hci521_2013.client.Entry; import edu.oswego.csc480_hci521_2013.client.events.RFGenerateEvent; import edu.oswego.csc480_hci521_2013.client.events.RFGenerateEventHandler; import edu.oswego.csc480_hci521_2013.client.events.TreeVisEvent; import edu.oswego.csc480_hci521_2013.client.events.TreeVisEventHandler; import edu.oswego.csc480_hci521_2013.client.place.ConfusionMatrixPlace; import edu.oswego.csc480_hci521_2013.client.place.DoublePanelPlace; import edu.oswego.csc480_hci521_2013.client.place.DataTablePlace; import edu.oswego.csc480_hci521_2013.client.place.TreeVisPlace; import edu.oswego.csc480_hci521_2013.client.presenters.ConfusionMatrixPresenterImpl; import edu.oswego.csc480_hci521_2013.client.presenters.DataPanelPresenterImpl; import edu.oswego.csc480_hci521_2013.client.presenters.DoublePanelPresenter; import edu.oswego.csc480_hci521_2013.client.presenters.TabPanelPresenter; import edu.oswego.csc480_hci521_2013.client.presenters.TreePanelPresenterImpl; import edu.oswego.csc480_hci521_2013.client.services.H2OServiceAsync; import edu.oswego.csc480_hci521_2013.client.ui.ConfusionMatrixViewImpl; import edu.oswego.csc480_hci521_2013.client.ui.DataPanelViewImpl; import edu.oswego.csc480_hci521_2013.client.ui.DoublePanelView; import edu.oswego.csc480_hci521_2013.client.ui.TabLabelView; import edu.oswego.csc480_hci521_2013.client.ui.TabLabelViewImpl; import edu.oswego.csc480_hci521_2013.shared.h2o.json.Inspect; import edu.oswego.csc480_hci521_2013.client.ui.TreePanelViewImpl; import edu.oswego.csc480_hci521_2013.shared.h2o.json.RF; import edu.oswego.csc480_hci521_2013.shared.h2o.json.RFTreeView; import edu.oswego.csc480_hci521_2013.shared.h2o.urlbuilders.InspectBuilder; import edu.oswego.csc480_hci521_2013.shared.h2o.urlbuilders.RFTreeViewBuilder; import edu.oswego.csc480_hci521_2013.shared.h2o.json.RFView; import edu.oswego.csc480_hci521_2013.shared.h2o.json.StoreView; import edu.oswego.csc480_hci521_2013.shared.h2o.urlbuilders.StoreViewBuilder; import edu.oswego.csc480_hci521_2013.shared.h2o.urlbuilders.RFBuilder; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import com.google.gwt.regexp.shared.*; public class DoublePanelActivity extends AbstractActivity implements DoublePanelPresenter { static final Logger logger = Logger.getLogger(DoublePanelActivity.class.getName()); private DoublePanelView view; private PlaceController places; private EventBus eventBus; private H2OServiceAsync service; private TabManager dataTabs = new TabManager(); private TabManager visTabs = new TabManager(); public DoublePanelActivity(DoublePanelView view, PlaceController places, EventBus eventBus, H2OServiceAsync service) { // FIXME: this constructor should go away... this(null, view, places, service); } public DoublePanelActivity(DoublePanelPlace place, DoublePanelView view, PlaceController places, H2OServiceAsync service) { // TODO: handle the place, it will carry args for what we should display. this.view = view; this.places = places; this.service = service; } @Override public void start(AcceptsOneWidget containerWidget, EventBus eventBus) { this.eventBus = eventBus; containerWidget.setWidget(view); bind(eventBus); loadParsedDataMenu(); logger.log(Level.INFO, "DoublePanelActivity started"); } private void bind(EventBus eventBus) { eventBus.addHandler(TreeVisEvent.TYPE, new TreeVisEventHandler() { @Override public void onViewData(TreeVisEvent e) { addVisTab(e.getData().getDataKey(), e.getData().getModelKey(), e.getIndex()); } }); eventBus.addHandler(RFGenerateEvent.TYPE, new RFGenerateEventHandler() { @Override public void onStart(RFGenerateEvent e) { logger.log(Level.INFO, "Adding confusion matrix..."); addConfusionMatrixTab(e.getData(),e.getBuilder()); } }); } private void loadParsedDataMenu() { service.getDataStores(new StoreViewBuilder() .setFilter(".hex").setView(1024), new AsyncCallback<StoreView>() { @Override public void onFailure(Throwable caught) { // FIXME: we need some sort of general error handler logger.log(Level.SEVERE, caught.toString()); } @Override public void onSuccess(StoreView result) { for (StoreView.Row row : result.getKeys()) { // NOTE: there is no way to know from this if it is parsed or not, // but the naming convention is that parsed data ends in .hex // we could possibly do an inspect call on each piece to // check if it is parsed or not... // TODO: we should check if there are more items still available. if (row.getKey().endsWith(".hex")) { String key = row.getKey(); view.addMenuItem(new MenuItem(key, false, getMenuCommand(key))); } } } }); } @Override public void goTo(Place place) { this.places.goTo(place); } @Override public void addDataTab(final String datakey) { logger.log(Level.INFO, "Creating new data tab: " + datakey); service.getData(new InspectBuilder(datakey), new AsyncCallback<Inspect>() { @Override public void onFailure(Throwable caught) { logger.log(Level.INFO, "Failure adding data tab."); logger.log(Level.SEVERE, caught.toString()); // FIXME: do a message box or something... } @Override public void onSuccess(Inspect result) { logger.log(Level.INFO, "Building data tab: " + datakey); DataPanelPresenterImpl presenter = new DataPanelPresenterImpl( service, new DataPanelViewImpl(), eventBus, datakey, result); TabLabelView label = new TabLabelViewImpl(); label.setLabel(datakey); label.setPresenter(DoublePanelActivity.this); view.addDataTab(presenter.getView(), label); dataTabs.addTab(label, presenter); } }); } @Override public void addVisTab(final String datakey, final String modelkey, final int tree) { service.getTreeView( new RFTreeViewBuilder(datakey, modelkey).setTreeNumber(tree), new AsyncCallback<RFTreeView>() { @Override public void onFailure(Throwable thrwbl) { logger.log(Level.SEVERE, thrwbl.toString()); // FIXME: do a message box or something... } @Override public void onSuccess(RFTreeView treeview) { TreePanelPresenterImpl presenter = new TreePanelPresenterImpl( new TreePanelViewImpl(treeview, datakey, modelkey, tree), treeview, datakey, modelkey, tree); logger.log(Level.INFO, treeview.toString()); TabLabelView label = new TabLabelViewImpl(); //label.setLabel(datakey + "<br>" + modelkey + "<br>tree " + (tree + 1)); label.setLabel("Tree " + (tree + 1) +"<br>"+parseDatakey(datakey)); label.setPresenter(DoublePanelActivity.this); view.addVisTab(presenter.getView(), label); visTabs.addTab(label, presenter); } }); } private String parseDatakey(String dataKey) { String result = dataKey; RegExp regex = RegExp.compile("([^\\\\/:*?\"<>|\r\n]+$)"); MatchResult matcher = regex.exec(dataKey); if (regex.test(dataKey)) { result = matcher.getGroup(1); } return result; } @Override public void addConfusionMatrixTab(RF rf, RFBuilder b) { ConfusionMatrixViewImpl matrixView = new ConfusionMatrixViewImpl(); matrixView.setResponseVariable(b.getResponseVariable()); ConfusionMatrixPresenterImpl presenter = new ConfusionMatrixPresenterImpl(matrixView, eventBus, rf,b); //String title = "Confusion Matrix<br>" + rf.getDataKey() + "<br>" + rf.getModelKey(); String title = "Confusion Matrix<br>" + parseDatakey(rf.getDataKey()); TabLabelView label = new TabLabelViewImpl(); label.setLabel(title); label.setPresenter(this); view.addVisTab(presenter.getView(), label); visTabs.addTab(label, presenter); } public void addConfusionMatrixTab(RF rf, RFView rfview, RFBuilder b) { ConfusionMatrixPresenterImpl presenter = new ConfusionMatrixPresenterImpl( new ConfusionMatrixViewImpl(), eventBus, rf, b); presenter.setData(rfview); presenter.getView().forestFinish(rfview.getNtree()); //String title = "Confusion Matrix<br>" + rf.getDataKey() + "<br>" + rf.getModelKey(); String title = "Confusion Matrix<br>" + parseDatakey(rf.getDataKey()); TabLabelView label = new TabLabelViewImpl(); label.setLabel(title); label.setPresenter(this); view.addVisTab(presenter.getView(), label); visTabs.addTab(label, presenter); } private Command getMenuCommand(final String value) { return new Command() { @Override public void execute() { logger.log(Level.INFO, "Adding dataset: " + value); addDataTab(value); } }; } private void popoutConfusionMatrixTab(ConfusionMatrixPlace place, int id) { // FIXME: this needs to be injected... AppPlaceHistoryMapper historyMapper = Entry.getPlaceHistoryMapper(); String token = historyMapper.getToken(place); String url = Window.Location.createUrlBuilder().setHash(token).buildString(); int width = Window.getClientWidth() / 2; int height = Window.getClientHeight() / 2; String features = "width=" + width + ",height=" + height + ",menubar=0,location=0,toolbar=0,status=0"; ConfusionMatrixActivity.openPanel(this, url, "_blank", features, Integer.toString(id)); } private void popoutTreeVisTab(TreeVisPlace place, int id) { // FIXME: this needs to be injected... AppPlaceHistoryMapper historyMapper = Entry.getPlaceHistoryMapper(); String token = historyMapper.getToken(place); String url = Window.Location.createUrlBuilder().setHash(token).buildString(); int width = Window.getClientWidth() / 2; int height = Window.getClientHeight() / 2; String features = "width=" + width + ",height=" + height + ",menubar=0,location=0,toolbar=0,status=0"; TreeVisActivity.openPanel(this, url, "_blank", features, Integer.toString(id)); } private void popoutDataTab(DataTablePlace place, int id) { logger.log(Level.INFO, "Popping data panel: " + place.getDataKey()); // FIXME: this needs to be injected... AppPlaceHistoryMapper historyMapper = Entry.getPlaceHistoryMapper(); String token = historyMapper.getToken(place); String url = Window.Location.createUrlBuilder().setHash(token).buildString(); int width = Window.getClientWidth() / 2; int height = Window.getClientHeight() / 2; String features = "width=" + width + ",height=" + height + ",menubar=0,location=0,toolbar=0,status=0"; DataPanelActivity.openPanel(this, url, "_blank", features, Integer.toString(id)); } public void popinDataPanel(String id) { logger.log(Level.INFO, "Adding data panel back in!"); TabLabelView tab = dataTabs.unpopTab(Integer.parseInt(id)); TabPanelPresenter p = dataTabs.getPresenter(tab); // FIXME: reusing presenters/view does not work yet... //p.added(); dataTabs.deleteTab(tab); addDataTab(((DataPanelPresenterImpl) p).getDataKey()); } public void popinVisPanel(String id) { logger.log(Level.INFO, "Adding vis panel back in!"); TabLabelView tab = visTabs.unpopTab(Integer.parseInt(id)); TabPanelPresenter p = visTabs.getPresenter(tab); // FIXME: reusing presenters/view does not work yet... //p.added(); visTabs.deleteTab(tab); if (p instanceof ConfusionMatrixPresenterImpl) { ConfusionMatrixPresenterImpl cp = (ConfusionMatrixPresenterImpl) p; addConfusionMatrixTab(cp.getRandomForest(), cp.getData(), cp.getBuilder()); } else { TreePanelPresenterImpl tp = (TreePanelPresenterImpl) p; addVisTab(tp.getDatakey(), tp.getModelkey(), tp.getTreeIndex()); } } @Override public void popout(TabLabelView tab) { if (dataTabs.hasTab(tab)) { int index = dataTabs.popTab(tab); view.removeDataTab(index); TabPanelPresenter p = dataTabs.getPresenter(tab); p.removed(); String datakey = ((DataPanelPresenterImpl) p).getDataKey(); DataTablePlace place = new DataTablePlace(); place.setDataKey(datakey); popoutDataTab(place, tab.hashCode()); } else if (visTabs.hasTab(tab)) { int index = visTabs.popTab(tab); view.removeVisTab(index); TabPanelPresenter p = visTabs.getPresenter(tab); p.removed(); if (p instanceof ConfusionMatrixPresenterImpl) { ConfusionMatrixPresenterImpl cp = (ConfusionMatrixPresenterImpl) p; ConfusionMatrixPlace place = new ConfusionMatrixPlace(); place.setRandomForest(cp.getRandomForest()); popoutConfusionMatrixTab(place, tab.hashCode()); } else { TreePanelPresenterImpl tp = (TreePanelPresenterImpl) p; TreeVisPlace place = new TreeVisPlace(); place.setDataKey(tp.getDatakey()); place.setModelKey(tp.getModelkey()); place.setTree(tp.getTreeIndex()); popoutTreeVisTab(place, tab.hashCode()); } } else { logger.log(Level.SEVERE, "Unknown tab!"); } } @Override public void close(TabLabelView tab) { if (dataTabs.hasTab(tab)) { int index = dataTabs.deleteTab(tab); view.removeDataTab(index); TabPanelPresenter p = dataTabs.getPresenter(tab); p.removed(); } else if (visTabs.hasTab(tab)) { int index = visTabs.deleteTab(tab); view.removeVisTab(index); TabPanelPresenter p = visTabs.getPresenter(tab); p.removed(); } else { logger.log(Level.SEVERE, "Unknown tab!"); } } private static class TabManager { List<TabLabelView> tabList = new ArrayList<TabLabelView>(); Map<TabLabelView, TabPanelPresenter> panels = new HashMap<TabLabelView, TabPanelPresenter>(); Map<Integer, TabLabelView> popped = new HashMap<Integer, TabLabelView>(); boolean hasTab(TabLabelView tab) { return panels.containsKey(tab); } TabPanelPresenter getPresenter(TabLabelView tab) { return panels.get(tab); } void addTab(TabLabelView tab, TabPanelPresenter presenter) { panels.put(tab, presenter); tabList.add(tab); } int popTab(TabLabelView tab) { int index = tabList.indexOf(tab); tabList.remove(tab); popped.put(tab.hashCode(), tab); return index; } TabLabelView unpopTab(Integer id) { TabLabelView t = popped.remove(id); tabList.add(t); return t; } int deleteTab(TabLabelView tab) { int index = tabList.indexOf(tab); tabList.remove(tab); panels.remove(tab); return index; } } }