/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package com.eas.grid.cells; import java.util.HashSet; import java.util.List; import java.util.Set; import com.eas.grid.processing.TreeDataProvider; import com.google.gwt.cell.client.Cell; import com.google.gwt.cell.client.ValueUpdater; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.BrowserEvents; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.dom.client.Style; import com.google.gwt.safecss.shared.SafeStyles; import com.google.gwt.safecss.shared.SafeStylesBuilder; import com.google.gwt.safehtml.client.SafeHtmlTemplates; import com.google.gwt.safehtml.shared.SafeHtml; import com.google.gwt.safehtml.shared.SafeHtmlBuilder; /** * * @author mg * @param <T> * @param <C> */ public class TreeExpandableCell<T, C> extends DivDecoratorCell<C> { public interface Template extends SafeHtmlTemplates { @SafeHtmlTemplates.Template("<div class='{0}' style='{1}'><div style='height:100%'>{2}</div></div>") SafeHtml outerDiv(String aClasses, SafeStyles aStyle, SafeHtml cellContents); } public static int DEAFAULT_INDENT = 24; private static final Template template = GWT.create(Template.class); protected int indent; protected TreeDataProvider<T> treeProvider; protected boolean visible = true; public TreeExpandableCell(Cell<C> aCell) { this(aCell, null, DEAFAULT_INDENT); } public TreeExpandableCell(Cell<C> aCell, int aIndent) { this(aCell, null, aIndent); } public TreeExpandableCell(Cell<C> aCell, TreeDataProvider<T> aTreeProvider, int aIndent) { super(aCell); indent = aIndent; treeProvider = aTreeProvider; } public TreeDataProvider<T> getDataProvider() { return treeProvider; } public void setDataProvider(TreeDataProvider<T> aValue) { treeProvider = aValue; } public boolean isVisible() { return visible; } public void setVisible(boolean aValue) { visible = aValue; } @Override public void render(Context context, C value, SafeHtmlBuilder sb) { if (treeProvider != null) { SafeHtmlBuilder cellBuilder = new SafeHtmlBuilder(); cell.render(context, value, cellBuilder); int deepness = getDeepness(context); int outerDivPadding = indent * deepness; SafeStylesBuilder styles = new SafeStylesBuilder(); if (deepness > 0) { styles.paddingLeft(outerDivPadding, Style.Unit.PX); } styles.position(Style.Position.RELATIVE).height(100, Style.Unit.PCT).toSafeStyles(); sb.append(template.outerDiv(outerDivClasses(context), styles.toSafeStyles(), cellBuilder.toSafeHtml())); } else { cell.render(context, value, sb); } } @Override public Set<String> getConsumedEvents() { if (visible) { if (treeProvider != null) { Set<String> consumed = new HashSet<>(); consumed.addAll(cell.getConsumedEvents()); consumed.add(BrowserEvents.MOUSEDOWN); return consumed; } else { return cell.getConsumedEvents(); } } else { return null; } } @Override public void onBrowserEvent(Context context, Element parent, C value, NativeEvent event, ValueUpdater<C> valueUpdater) { if (treeProvider != null) { super.onBrowserEvent(context, parent, value, event, valueUpdater); } else { cell.onBrowserEvent(context, parent, value, event, valueUpdater); } } @Override protected Element getCellParent(Element parent) { if (treeProvider != null) { return super.getCellParent(parent); } else { return parent; } } @Override protected int outerDivPadding(Cell.Context aContext) { return indent * (getDeepness(aContext) + 1); } @Override protected String outerDivClasses(Cell.Context aContext) { return isExpandable(aContext) ? (isExpanded(aContext) ? "treegrid-expanded-cell" : "treegrid-collapased-cell") : ""; } protected boolean isExpanded(Cell.Context aContext) { T element = treeProvider.getList().get(aContext.getIndex()); return treeProvider.isExpanded(element); } protected boolean isExpandable(Cell.Context aContext) { T element = treeProvider.getList().get(aContext.getIndex()); return !treeProvider.getTree().isLeaf(element); } /** * * @param aContext * @return Deepness value, 0 based. 0 means that an element is on the top * level (e.g. element is root of a forest). */ protected int getDeepness(Cell.Context aContext) { T element = treeProvider.getList().get(aContext.getIndex()); List<T> path = treeProvider.buildPathTo(element); return path != null && !path.isEmpty() ? path.size() - 1 : 0; } @Override protected void onNonCellBrowserEvent(Cell.Context context, Element parent, C value, NativeEvent event, ValueUpdater<C> valueUpdater) { if (treeProvider != null) { if (BrowserEvents.MOUSEDOWN.equals(event.getType())) { T toBeToggled = treeProvider.getList().get(context.getIndex()); treeProvider.getList().set(context.getIndex(), toBeToggled); if (isExpanded(context)) { treeProvider.collapse(toBeToggled); } else { treeProvider.expand(toBeToggled); } } else if (cell.getConsumedEvents().contains(event.getType())) { cell.onBrowserEvent(context, getCellParent(parent), value, event, valueUpdater); } } } }