teichmann@5861: /* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde teichmann@5861: * Software engineering by Intevation GmbH teichmann@5861: * teichmann@5861: * This file is Free Software under the GNU AGPL (>=v3) teichmann@5861: * and comes with ABSOLUTELY NO WARRANTY! Check out the teichmann@5861: * documentation coming with Dive4Elements River for details. teichmann@5861: */ teichmann@5861: teichmann@5835: package org.dive4elements.river.client.client.ui; sascha@848: sascha@848: import com.google.gwt.core.client.GWT; sascha@848: import com.google.gwt.user.client.rpc.AsyncCallback; sascha@848: christian@4131: import com.smartgwt.client.types.SelectionStyle; christian@4131: import com.smartgwt.client.types.TreeModelType; sascha@848: import com.smartgwt.client.util.SC; sascha@848: import com.smartgwt.client.widgets.Button; christian@4131: import com.smartgwt.client.widgets.events.ClickEvent; christian@4131: import com.smartgwt.client.widgets.events.ClickHandler; christian@4131: import com.smartgwt.client.widgets.grid.HoverCustomizer; christian@4131: import com.smartgwt.client.widgets.grid.ListGridRecord; christian@4131: import com.smartgwt.client.widgets.grid.events.RecordDoubleClickEvent; christian@4131: import com.smartgwt.client.widgets.grid.events.RecordDoubleClickHandler; christian@4131: import com.smartgwt.client.widgets.layout.VLayout; sascha@848: import com.smartgwt.client.widgets.tree.Tree; sascha@848: import com.smartgwt.client.widgets.tree.TreeGrid; sascha@848: import com.smartgwt.client.widgets.tree.TreeNode; sascha@848: teichmann@5835: import org.dive4elements.river.client.client.Config; teichmann@5835: import org.dive4elements.river.client.client.FLYSConstants; teichmann@5835: import org.dive4elements.river.client.client.event.DatacageDoubleClickHandler; teichmann@5835: import org.dive4elements.river.client.client.event.DatacageHandler; teichmann@5835: import org.dive4elements.river.client.client.services.MetaDataService; teichmann@5835: import org.dive4elements.river.client.client.services.MetaDataServiceAsync; teichmann@5835: import org.dive4elements.river.client.client.ui.ScreenLock; teichmann@5835: import org.dive4elements.river.client.shared.model.Artifact; teichmann@5835: import org.dive4elements.river.client.shared.model.AttrList; teichmann@5835: import org.dive4elements.river.client.shared.model.DataCageNode; teichmann@5835: import org.dive4elements.river.client.shared.model.DataCageTree; teichmann@5835: import org.dive4elements.river.client.shared.model.ToLoad; teichmann@5835: import org.dive4elements.river.client.shared.model.User; sascha@848: sascha@848: import java.util.ArrayList; sascha@848: import java.util.List; sascha@1325: import java.util.MissingResourceException; sascha@848: import java.util.Stack; sascha@848: felix@897: // TODO: refactor, extract ~DataCageGrid felix@1283: /** felix@1283: * Display tree of, for example, previous calculations and allows felix@1283: * selection in order to access/clone these. felix@1283: */ sascha@848: public class DatacageWidget sascha@848: extends VLayout sascha@848: { sascha@1325: public static final int MAX_OPEN = 30; sascha@1325: sascha@848: protected MetaDataServiceAsync metaDataService = sascha@848: GWT.create(MetaDataService.class); sascha@848: sascha@848: protected FLYSConstants messages = sascha@848: GWT.create(FLYSConstants.class); sascha@848: sascha@848: protected Artifact artifact; sascha@848: protected User user; sascha@848: protected String outs; ingo@916: protected String parameters; sascha@848: sascha@848: protected TreeGrid treeGrid; sascha@848: protected Tree tree; sascha@848: sascha@848: protected ToLoad toLoad; sascha@848: ingo@1267: protected List handlers; ingo@1267: protected List doubleHandlers; sascha@848: felix@5488: /** Layout to show spinning wheel of joy. */ felix@5488: protected VLayout lockScreen; felix@5488: felix@868: sascha@848: public DatacageWidget() { ingo@1267: handlers = new ArrayList(); ingo@1267: doubleHandlers = new ArrayList(); sascha@848: } sascha@848: felix@868: sascha@848: public DatacageWidget(Artifact artifact, User user) { sascha@848: this(artifact, user, null); sascha@848: } sascha@848: felix@897: public DatacageWidget(Artifact artifact, User user, String outs) { felix@897: this(artifact, user, outs, true); felix@897: } felix@868: ingo@916: public DatacageWidget( ingo@916: Artifact artifact, ingo@916: User user, ingo@916: String outs, ingo@916: boolean showButton ingo@916: ) { ingo@916: this(artifact, user, outs, null, showButton); ingo@916: } ingo@916: ingo@916: ingo@916: public DatacageWidget( ingo@916: Artifact artifact, ingo@916: User user, ingo@916: String outs, ingo@916: String parameters, ingo@916: boolean showButton ingo@916: ) { sascha@848: this(); sascha@848: ingo@916: this.artifact = artifact; ingo@916: this.user = user; ingo@916: this.outs = outs; ingo@916: this.parameters = parameters; sascha@848: sascha@848: toLoad = new ToLoad(); sascha@848: sascha@848: setWidth100(); sascha@848: sascha@848: tree = new Tree(); sascha@1325: tree.setModelType(TreeModelType.CHILDREN); sascha@848: tree.setNameProperty("name"); sascha@848: tree.setIdField("id"); sascha@1325: tree.setChildrenProperty("children-nodes"); sascha@1325: tree.setShowRoot(false); sascha@848: sascha@848: treeGrid = new TreeGrid(); sascha@848: treeGrid.setLoadDataOnDemand(false); sascha@848: treeGrid.setWidth100(); sascha@848: treeGrid.setHeight100(); sascha@848: treeGrid.setShowRoot(false); raimund@1619: treeGrid.setNodeIcon("[SKIN]/../blank.gif"); sascha@1325: treeGrid.setShowConnectors(true); ingo@2435: treeGrid.setLoadingMessage(messages.databasket_loading()); ingo@2435: treeGrid.setEmptyMessage(messages.databasket_loading()); ingo@2435: treeGrid.setLoadingDataMessage(messages.databasket_loading()); sascha@848: felix@3475: treeGrid.setHoverMoveWithMouse(true); felix@3475: treeGrid.setCanHover(true); felix@3475: treeGrid.setShowHover(true); felix@3475: treeGrid.setHoverOpacity(75); aheinecke@5626: treeGrid.setHoverWidth(120); felix@3475: felix@3475: treeGrid.setHoverCustomizer(new HoverCustomizer() { felix@3475: @Override felix@3475: public String hoverHTML(Object value, felix@3475: ListGridRecord record, felix@3475: int rowNum, felix@3475: int colNum felix@3475: ) { felix@3475: if(record instanceof TreeNode) { felix@3475: TreeNode hoveredTreeNode = (TreeNode)record; felix@3475: String info = hoveredTreeNode.getAttribute("info"); felix@3475: if (info == null) { felix@3475: info = hoveredTreeNode.getName(); felix@3475: } felix@3475: return info; felix@3475: } felix@3475: else { felix@3475: return "";// should not happen felix@3475: } felix@3475: } felix@3475: }); felix@3475: sascha@848: treeGrid.addRecordDoubleClickHandler(new RecordDoubleClickHandler() { sascha@848: @Override sascha@848: public void onRecordDoubleClick(RecordDoubleClickEvent event) { sascha@848: doubleClickedOnTree(event); sascha@848: } sascha@848: }); sascha@848: sascha@848: addMember(treeGrid); sascha@848: felix@897: if (showButton) { felix@897: addMember(createPlusButton()); felix@897: } sascha@848: sascha@848: triggerTreeBuilding(); sascha@848: } sascha@848: felix@5488: public void lockUI() { felix@5488: lockScreen = ScreenLock.lockUI(this, lockScreen); felix@5488: } felix@5488: felix@5488: /** Enable input, remove grey, remove spinning wheel of joy. */ felix@5488: public void unlockUI() { felix@5488: ScreenLock.unlockUI(this, lockScreen); felix@5488: } felix@897: felix@897: /** felix@897: * @param handler Handler to be added (notified on add-action). felix@897: */ felix@897: public DatacageWidget(Artifact artifact, User user, String outs, felix@897: DatacageHandler handler) { felix@897: this(artifact, user, outs); felix@897: this.addDatacageHandler(handler); felix@897: } felix@897: felix@897: ingo@916: public DatacageWidget( ingo@916: Artifact artifact, ingo@916: User user, ingo@916: String outs, ingo@916: DatacageHandler handler, ingo@916: String parameters ingo@916: ) { ingo@916: this(artifact, user, outs, handler); ingo@916: this.parameters = parameters; ingo@916: } ingo@916: ingo@916: felix@1283: /** felix@1283: * Sets whether more than one item can be selected. felix@1283: * @param multi if true, allow mutliple selections. felix@1283: */ ingo@1268: public void setIsMutliSelectable(boolean multi) { ingo@1268: if (multi) { ingo@1268: treeGrid.setSelectionType(SelectionStyle.MULTIPLE); ingo@1268: } ingo@1268: else { ingo@1268: treeGrid.setSelectionType(SelectionStyle.SINGLE); ingo@1268: } ingo@1268: } ingo@1268: ingo@1268: felix@897: /** felix@897: * @param handler Handler to be added (notified on add-action). felix@897: */ sascha@848: public void addDatacageHandler(DatacageHandler handler) { ingo@884: if (!handlers.contains(handler)) { sascha@848: handlers.add(handler); sascha@848: } sascha@848: } sascha@848: felix@897: felix@897: /** ingo@1267: * @param h Handler to be added (notified on Double click on node). ingo@1267: */ ingo@1267: public void addDatacageDoubleClickHandler(DatacageDoubleClickHandler h) { ingo@1267: if (!doubleHandlers.contains(h)) { ingo@1267: doubleHandlers.add(h); ingo@1267: } ingo@1267: } ingo@1267: ingo@1267: ingo@1267: /** felix@897: * @param handler Handler to remove from list. felix@897: */ sascha@848: public void removeDatacageHandler(DatacageHandler handler) { sascha@848: handlers.remove(handler); sascha@848: } sascha@848: felix@897: sascha@848: public ToLoad getToLoad() { sascha@848: return toLoad; sascha@848: } sascha@848: felix@897: felix@897: public ToLoad getSelection() { felix@897: // Reset content of toLoads. felix@897: toLoad = new ToLoad(); felix@897: sascha@848: if (treeGrid == null) { felix@897: return toLoad; sascha@848: } sascha@848: christian@4131: ListGridRecord [] selection = treeGrid.getSelectedRecords(); sascha@848: sascha@848: if (selection != null) { sascha@848: for (ListGridRecord record: selection) { sascha@848: if (record instanceof TreeNode) { sascha@848: collectToLoads((TreeNode)record); sascha@848: } sascha@848: } sascha@848: } sascha@848: felix@897: return toLoad; felix@897: } felix@897: felix@897: felix@897: /** felix@1283: * Returns the titles of selected items (if any). felix@1283: */ felix@1283: public String[] getSelectionTitles() { felix@1283: if (treeGrid == null) { felix@1283: return new String[] {}; felix@1283: } felix@1283: christian@4131: ListGridRecord [] selection = treeGrid.getSelectedRecords(); felix@1283: felix@1283: if (selection == null) { felix@1283: return new String[] {}; felix@1283: } felix@1283: felix@1283: List titleList = new ArrayList(); felix@1283: for (ListGridRecord record: selection) { felix@1283: if (record instanceof TreeNode) { felix@1283: titleList.add(((TreeNode)record).getAttribute("name")); felix@1283: } felix@1283: } felix@1283: felix@1283: return titleList.toArray(new String[titleList.size()]); felix@1283: } felix@1283: felix@1283: felix@1283: /** felix@897: * Callback for add-button. felix@897: * Fires to load for every selected element and handler. felix@897: */ felix@897: public void plusClicked() { felix@897: if (!getSelection().isEmpty()) { sascha@848: fireToLoad(); sascha@848: } sascha@848: } sascha@848: felix@897: felix@897: protected Button createPlusButton() { sascha@1325: Button plusBtn = new Button(messages.datacageAdd()); felix@897: plusBtn.addClickHandler(new ClickHandler() { felix@897: @Override felix@897: public void onClick(ClickEvent event) { felix@897: plusClicked(); felix@897: } felix@897: }); felix@897: return plusBtn; felix@897: } felix@897: felix@897: sascha@848: protected void fireToLoad() { sascha@848: for (DatacageHandler handler: handlers) { sascha@848: handler.toLoad(toLoad); sascha@848: } sascha@848: } sascha@848: felix@897: felix@1333: /** Notify DatacageDoubleClickHandlers that a doubleclick happened. */ ingo@1267: protected void fireOnDoubleClick() { ingo@1267: for (DatacageDoubleClickHandler handler: doubleHandlers) { ingo@1267: handler.onDoubleClick(toLoad); ingo@1267: } ingo@1267: } ingo@1267: ingo@1267: sascha@848: protected void doubleClickedOnTree(RecordDoubleClickEvent event) { sascha@848: TreeNode node = (TreeNode)event.getRecord(); sascha@848: collectToLoads(node); ingo@1267: fireOnDoubleClick(); sascha@848: } sascha@848: felix@897: felix@1349: /** felix@1349: * Adds to toLoad, from info in node. felix@1349: * Afterwards, add all children of node to stack to parse (next time felix@1349: * collectToLoads is called). felix@1349: */ sascha@848: protected void collectToLoads(TreeNode node) { sascha@848: Stack stack = new Stack(); sascha@848: sascha@848: stack.push(node); sascha@848: sascha@848: while (!stack.isEmpty()) { sascha@848: node = stack.pop(); sascha@848: String factory = node.getAttribute("factory"); sascha@848: if (factory != null) { // we need at least a factory sascha@848: String artifact = node.getAttribute("artifact-id"); sascha@848: String out = node.getAttribute("out"); ingo@892: String name = node.getAttribute("facet"); sascha@848: String ids = node.getAttribute("ids"); bjoern@4500: String displayname = node.getAttribute("name"); felix@1349: String debugAttributeValues = ""; felix@1349: for (String attr: node.getAttributes()) { felix@1349: debugAttributeValues += ("[" + attr +": " felix@1349: + node.getAttributeAsString(attr) + "] "); felix@1349: } felix@1349: GWT.log("DatacageWidget.collectToLoad, attributes are " felix@1349: + debugAttributeValues); sascha@848: felix@1352: toLoad.add(artifact, felix@1352: factory, felix@1352: out, felix@1352: name, felix@1352: ids, bjoern@4500: displayname); sascha@848: } sascha@848: TreeNode [] children = tree.getChildren(node); sascha@848: if (children != null) { sascha@848: for (TreeNode child: children) { sascha@848: stack.push(child); sascha@848: } sascha@848: } sascha@848: } sascha@848: } sascha@848: sascha@848: felix@3475: /** Get meta-data and populate tree with it. */ sascha@848: protected void triggerTreeBuilding() { sascha@848: Config config = Config.getInstance(); sascha@848: String locale = config.getLocale(); sascha@848: sascha@848: String artifactId = artifact.getUuid(); felix@868: String userId = (user != null) ? user.identifier() : null; sascha@848: felix@5488: lockUI(); felix@5488: sascha@848: metaDataService.getMetaData( raimund@1425: locale, sascha@848: artifactId, sascha@848: userId, sascha@848: outs, ingo@916: parameters, sascha@848: new AsyncCallback() { christian@4131: @Override sascha@848: public void onFailure(Throwable caught) { sascha@848: GWT.log("Could not load meta data."); sascha@848: SC.warn(caught.getMessage()); felix@5488: unlockUI(); sascha@848: } sascha@848: christian@4131: @Override sascha@848: public void onSuccess(DataCageTree dcTree) { sascha@848: GWT.log("Successfully loaded meta data."); sascha@1325: IdGenerator idGenerator = new IdGenerator(); sascha@1325: DataCageNode dcRoot = dcTree.getRoot(); sascha@1325: TreeNode root = buildRecursiveChildren( sascha@1325: dcRoot, idGenerator); sascha@1325: tree.setRoot(root); raimund@2478: raimund@2478: TreeNode[] nodes = tree.getChildren(root); aheinecke@5462: for (TreeNode node: nodes) { aheinecke@5462: if (node.getAttribute("factory") == null && aheinecke@5462: !tree.hasChildren(node)) { aheinecke@5462: node.setIsFolder(true); raimund@2478: } raimund@2478: } raimund@2478: sascha@1325: if (idGenerator.current() < MAX_OPEN) { sascha@1325: tree.openAll(); sascha@1325: } sascha@848: treeGrid.setData(tree); felix@5488: unlockUI(); sascha@848: } sascha@848: }); sascha@848: } sascha@848: sascha@1325: private static final class IdGenerator { sascha@848: protected int current; sascha@848: sascha@848: public IdGenerator() { sascha@848: } sascha@848: sascha@1325: public int next() { sascha@1325: return current++; sascha@848: } sascha@848: sascha@1325: public int current() { sascha@1325: return current; sascha@848: } sascha@848: } // class IdGenerator sascha@848: sascha@1325: private String i18n(String s) { sascha@1325: if (!(s.startsWith("${") && s.endsWith("}"))) { sascha@1325: return s; sascha@1325: } sascha@1325: sascha@1325: s = s.substring(2, s.length()-1); sascha@1325: sascha@1325: try { sascha@1325: return messages.getString(s); sascha@1325: } sascha@1325: catch (MissingResourceException mre) { sascha@1325: GWT.log("cannot find i18n for + '" + s + "'"); sascha@1325: return s; sascha@1325: } sascha@1325: } sascha@1325: sascha@1325: protected TreeNode buildRecursiveChildren( sascha@2905: DataCageNode node, sascha@1325: IdGenerator idGenerator sascha@848: ) { sascha@848: TreeNode tn = new TreeNode(); sascha@1325: tn.setAttribute("id", idGenerator.next()); sascha@1325: sascha@1325: List children = node.getChildren(); sascha@1325: sascha@1325: if (children != null) { sascha@1325: TreeNode [] tns = new TreeNode[children.size()]; sascha@1325: for (int i = 0; i < tns.length; ++i) { sascha@1325: DataCageNode child = children.get(i); sascha@1325: tns[i] = buildRecursiveChildren(child, idGenerator); sascha@1325: } sascha@1325: tn.setAttribute("children-nodes", tns); sascha@1325: } sascha@1325: sascha@1325: tn.setAttribute("name", i18n(node.getDescription())); ingo@892: tn.setAttribute("facet", node.getName()); sascha@1325: sascha@848: AttrList attrs = node.getAttributes(); sascha@848: if (attrs != null) { sascha@848: for (int i = 0, N = attrs.size(); i < N; ++i) { sascha@848: String key = attrs.getKey(i); sascha@848: String value = attrs.getValue(i); sascha@848: tn.setAttribute(key, value); sascha@848: } sascha@848: } sascha@848: sascha@1325: return tn; sascha@848: } sascha@848: } sascha@848: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :