Package com.extjs.gxt.ui.client.store

Source Code of com.extjs.gxt.ui.client.store.TreeStore

/*
* Sencha GXT 2.3.1 - Sencha for GWT
* Copyright(c) 2007-2013, Sencha, Inc.
* licensing@sencha.com
*
* http://www.sencha.com/products/gxt/license/
*/
package com.extjs.gxt.ui.client.store;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.extjs.gxt.ui.client.Style.SortDir;
import com.extjs.gxt.ui.client.core.FastMap;
import com.extjs.gxt.ui.client.data.BaseTreeModel;
import com.extjs.gxt.ui.client.data.ChangeEvent;
import com.extjs.gxt.ui.client.data.ChangeEventSource;
import com.extjs.gxt.ui.client.data.ListLoadConfig;
import com.extjs.gxt.ui.client.data.LoadEvent;
import com.extjs.gxt.ui.client.data.Loader;
import com.extjs.gxt.ui.client.data.ModelData;
import com.extjs.gxt.ui.client.data.RemoteSortTreeLoader;
import com.extjs.gxt.ui.client.data.SortInfo;
import com.extjs.gxt.ui.client.data.TreeLoadEvent;
import com.extjs.gxt.ui.client.data.TreeLoader;
import com.extjs.gxt.ui.client.data.TreeModel;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.event.LoadListener;
import com.extjs.gxt.ui.client.util.Util;

/**
* A store for hierarchical data.
*
* <p/>
* The parent child relationships are handled internally by the store. It is
* important to note that the store does not use the the parent and children of
* any TreeModel instances added to the store.
*
* <p/>
* It is important to note the sorting behavior when working with TreeStore.
* When a sorter is set, it is applied to all existing models in the cache and
* the Sort event is fired. At this point, the sorter is enabled and active.
*
* <p/>
* Remote sorting is not supported with TreeStore.
*
* <dl>
* <dt><b>Events:</b></dt>
* <dd><b>Store.BeforeDataChanged</b> : TreeStoreEvent(store)<br>
* <div>Fires before the store's data is changed. Apply applies when a store is
* bound to a loader.</div>
* <ul>
* <li>store : this</li>
* </ul>
* </dd>
*
* <dd><b>Store.DataChange</b> : TreeStoreEvent(store)<br>
* <div>Fires when the data cache has changed, and a widget which is using this
* Store as a Model cache should refresh its view.</div>
* <ul>
* <li>store : this</li>
* </ul>
* </dd>
*
* <dd><b>Store.Filter</b> : TreeStoreEvent(store)<br>
* <div>Fires when filters are applied and removed from the store.</div>
* <ul>
* <li>store : this</li>
* </ul>
* </dd>
*
* <dd><b>Store.Add</b> : TreeStoreEvent(store, parent, child)<br>
* <div>Fires when models have been added to the store.</div>
* <ul>
* <li>store : this</li>
* <li>parent : the parent</li>
* <li>children : this list of model(s) added</li>
* <li>index : the insert index</li>
* </ul>
* </dd>
*
* <dd><b>Store.Remove</b> : TreeStoreEvent(store, parent, child)<br>
* <div>Fires when a model has been removed from the store.</div>
* <ul>
* <li>store : this</li>
* <li>parent : the parent</li>
* <li>child : the removed child</li>
* <li>children : all the children (deep) of the removed item</li>
* </ul>
* </dd>
*
* <dd><b>Store.Update</b> : TreeStoreEvent(store, model, record)<br>
* <div>Fires when a model has been updated via its record.</div>
* <ul>
* <li>store : this</li>
* <li>model : the model that was updated</li>
* <li>record : the record that was updated</li>
* <li>operation : the update operation being performed.</li>
* </ul>
* </dd>
*
* <dd><b>Store.Clear</b> : TreeStoreEvent(store)<br>
* <div>Fires when the data cache has been cleared.</div>
* <ul>
* <li>store : this</li>
* </ul>
* </dd>
*
* <dd><b>Store.Sort</b> : TreeStoreEvent(store)<br>
* <div>Fires after a sorter is applied to the store.</div>
* <ul>
* <li>store : this</li>
* </ul>
* </dd>
*
* </dl>
*/
public class TreeStore<M extends ModelData> extends Store<M> {

  protected TreeLoader<M> loader;
  protected Map<String, TreeModel> modelFastMap;
  protected Map<M, TreeModel> modelMap;
  protected BaseTreeModel rootWrapper = new BaseTreeModel();

  protected Map<String, M> wrapperMap = new FastMap<M>();

  private int counter = 0;
  private Boolean useKeyProvider = null;

  /**
   * Creates a new tree store.
   */
  public TreeStore() {
    super();
  }

  /**
   * Creates a new tree store.
   *
   * @param loader the tree loader
   */
  public TreeStore(TreeLoader<M> loader) {
    this.loader = loader;
    loader.addLoadListener(new LoadListener() {

      public void loaderBeforeLoad(LoadEvent le) {
        onBeforeLoad(le);
      }

      public void loaderLoad(LoadEvent le) {
        onLoad((TreeLoadEvent) le);
      }

      public void loaderLoadException(LoadEvent le) {
        onLoadException(le);
      }

    });
  }

  /**
   * Adds the models to the root of the store and fires the <i>Add</i> event.
   *
   * @param models the models to be added
   * @param addChildren true to recursively add all children
   */
  public void add(List<M> models, boolean addChildren) {
    insert(models, rootWrapper.getChildCount(), addChildren);
  }

  /**
   * Adds the items to the store and fires the <i>Add</i> event.
   *
   * @param item the item to add
   * @param addChildren true to recursively add all children
   */
  @SuppressWarnings("unchecked")
  public void add(M item, boolean addChildren) {
    add(Util.createList(item), addChildren);
  }

  /**
   * Adds the models to the given parent and fires the <i>Add</i> event.
   *
   * @param parent the parent
   * @param children the children
   * @param addChildren true to recursively add all children
   */
  public void add(M parent, List<M> children, boolean addChildren) {
    insert(parent, children, getChildCount(parent), addChildren);
  }

  /**
   * Adds the child to the parent and fires the <i>Add</i> event.
   *
   * @param parent the parent item
   * @param item the child item
   * @param addChildren true to recursively add all children
   */
  public void add(M parent, M item, boolean addChildren) {
    insert(parent, item, getChildCount(parent), addChildren);
  }

  @Override
  public void applyFilters(String property) {
    filterProperty = property;
    filtersEnabled = true;

    filterTreeWrap(rootWrapper);

    fireEvent(Filter, createStoreEvent());
  }

  @Override
  public void clearFilters() {
    if (isFiltered()) {
      filtersEnabled = false;
      snapshot = null;
      for (M m : all) {
        TreeModel wrap = findWrapper(m);
        wrap.remove("filtered");
      }
      fireEvent(Filter, createStoreEvent());
    }
  }

  /**
   * Returns all the stores items. The items are not returned in any order.
   *
   * @return the items
   */
  public List<M> getAllItems() {
    return all;
  }

  /**
   * Returns the root level child.
   *
   * @param index the index
   * @return the child
   */
  public M getChild(int index) {
    return getFilteredChildren(rootWrapper).get(index);
  }

  /**
   * Returns the child at the given index.
   *
   * @param parent the parent model or null if parent is root
   * @param index the index
   * @return the child of the parent at the given index
   */
  public M getChild(M parent, int index) {
    if (parent == null) {
      return getFilteredChildren(rootWrapper).get(index);
    }
    TreeModel p = findWrapper(parent);
    if (p != null) {
      return getFilteredChildren(p).get(index);
    }
    return null;
  }

  /**
   * Returns the root level child count.
   *
   * @return the child count
   */
  public int getChildCount() {
    return getRootItems().size();
  }

  /**
   * Returns the child count for the parent.
   *
   * @param parent the parent
   * @return the child count or -1 if parent not found in the store
   */
  public int getChildCount(M parent) {
    if (parent == null) {
      return getChildCount();
    } else {
      TreeModel p = findWrapper(parent);
      if (p != null) {
        return getFilteredChildren(p).size();
      }
      return -1;
    }
  }

  /**
   * Returns the children of the parent.
   *
   * @param parent the parent
   * @return the children or null if parent not found in the store
   */
  public List<M> getChildren(M parent) {
    return getChildren(parent, false);
  }

  /**
   * Returns the children of the parent.
   *
   * @param parent the parent
   * @param deep true to return all children recursively
   * @return the children or null if parent not found in the store
   */
  public List<M> getChildren(M parent, boolean deep) {
    TreeModel p = findWrapper(parent);
    if (p != null) {
      if (deep) {
        List<M> temp = new ArrayList<M>();
        List<M> children = getFilteredChildren(p);
        for (M child : children) {
          temp.add(child);
          temp.addAll(getChildren(child, true));
        }
        return temp;
      } else {
        return getFilteredChildren(p);
      }
    }
    return null;
  }

  /**
   * Returns the depth of the item.
   *
   * @param item the item
   * @return the item's depth
   */
  public int getDepth(M item) {
    int depth = 0;
    while (item != null) {
      depth++;
      item = getParent(item);
    }
    return depth;
  }

  /**
   * Returns the fist child of the parent.
   *
   * @param parent the parent
   * @return the first child or null if no children
   */
  public M getFirstChild(M parent) {
    List<M> children = parent == null ? getRootItems() : getChildren(parent);
    if (children != null && children.size() > 0) {
      return children.get(0);
    }
    return null;
  }

  /**
   * Returns the last child of the parent.
   *
   * @param parent the parent
   * @return the last child of null if no children
   */
  public M getLastChild(M parent) {
    List<M> children = parent == null ? getRootItems() : getChildren(parent);
    if (children != null && children.size() > 0) {
      return children.get(children.size() - 1);
    }
    return null;
  }

  /**
   * Returns the store's loader.
   *
   * @return the loader
   */
  public TreeLoader<M> getLoader() {
    return loader;
  }

  /**
   * Returns the parent-child relationships for the given model. The actual
   * model can be retrieved in each TreeModel's "model" property using the
   * {@link TreeStoreModel#getModel()} method. The children of each tree model
   * contains tree model instances which wrap the actual child model.
   *
   * @param model the model
   * @return the model and it's children
   */
  public TreeStoreModel getModelState(M model) {
    TreeStoreModel tm = new TreeStoreModel(model);
    int count = getChildCount(model);
    for (int i = 0; i < count; i++) {
      tm.add(getModelState(getChild(model, i)));
    }
    return tm;
  }

  /**
   * Returns the next sibling of the model.
   *
   * @param item the model
   * @return the next sibling or null
   */
  public M getNextSibling(M item) {
    M parent = getParent(item);
    List<M> children = parent == null ? getRootItems() : getChildren(parent);
    int index = children.indexOf(item);
    if (children.size() > (index + 1)) {
      return children.get(index + 1);
    }
    return null;
  }

  /**
   * Returns the parent of the item.
   *
   * @param item the item
   * @return the item's parent
   */
  public M getParent(M item) {
    TreeModel child = findWrapper(item);
    if (child != null) {
      TreeModel p = child.getParent();
      if (p != null) {
        return unwrap(p);
      }
    }
    return null;
  }

  /**
   * Returns the item's previous sibling.
   *
   * @param item the item
   * @return the previous sibling
   */
  public M getPreviousSibling(M item) {
    M parent = getParent(item);
    List<M> children = parent == null ? getRootItems() : getChildren(parent);
    int index = children.indexOf(item);
    if (index > 0) {
      return children.get(index - 1);
    }
    return null;
  }

  /**
   * Returns the root level items.
   *
   * @return the items
   */
  public List<M> getRootItems() {
    return unwrapChildren(rootWrapper);
  }

  /**
   * Returns the current sort state of this store.
   *
   * @return the sort state
   */
  public SortInfo getSortState() {
    return sortInfo;
  }

  /**
   * Returns true if the given parent model has any children.
   *
   * @param parent the parent model
   * @return true if the given parent model has any children
   */
  public boolean hasChildren(M parent) {
    if (parent == null) {
      return rootWrapper.getChildCount() > 0;
    } else {
      TreeModel p = findWrapper(parent);
      if (p != null) {
        for (ModelData child : p.getChildren()) {
          if (!isFiltered((TreeModel) child)) {
            return true;
          }
        }
      }

    }
    return false;
  }

  /**
   * Returns the item's index in it's parent including root level items.
   *
   * @param item the item
   * @return the index
   */
  public int indexOf(M item) {
    M parent = getParent(item);
    if (parent == null) {
      return getRootItems().indexOf(item);
    } else {
      return getChildren(parent).indexOf(item);
    }
  }

  /**
   * Inserts the models into the store and fires the <i>Add</i> event.
   *
   * @param models the models to insert
   * @param index the insert index
   * @param addChildren true to recursively add all children
   */
  public void insert(List<M> models, int index, boolean addChildren) {
    List<TreeModel> insert = new ArrayList<TreeModel>();
    for (M model : models) {
      insert.add(wrap(model));
    }
    doInsert(rootWrapper, insert, index, addChildren, false);
  }

  /**
   * Adds the item to the store and fires the <i>Add</i> event.
   *
   * @param item the item to insert
   * @param index the insert index
   * @param addChildren true to recursively add all children
   */
  @SuppressWarnings("unchecked")
  public void insert(M item, int index, boolean addChildren) {
    doInsert(rootWrapper, Util.createList(wrap(item)), index, addChildren, false);
  }

  /**
   * Inserts the children to the parent and fires the <i>Add</i> event.
   *
   * @param parent the parent
   * @param children the children
   * @param index the insert index
   * @param addChildren true to recursively add all children
   */
  public void insert(M parent, List<M> children, int index, boolean addChildren) {
    TreeModel wrapper = findWrapper(parent);
    if (wrapper != null) {
      List<TreeModel> insert = new ArrayList<TreeModel>();
      for (M model : children) {
        insert.add(wrap(model));
      }
      doInsert(wrapper, insert, index, addChildren, false);
    }
  }

  /**
   * Adds the child to the parent and fires the <i>Add</i> event.
   *
   * @param parent the parent model
   * @param model the child model
   * @param index the insert index
   * @param addChildren true to recursively add all children
   */
  @SuppressWarnings("unchecked")
  public void insert(M parent, M model, int index, boolean addChildren) {
    insert(parent, Util.createList(model), index, addChildren);
  }

  /**
   * Removes the model from the store and fires the <i>Remove</i> event. Works
   * with both regular and root nodes.
   *
   * @param model the item to be removed
   */
  public void remove(M model) {
    M parent = getParent(model);
    if (parent == null) {
      remove(rootWrapper, findWrapper(model), false);
    } else {
      remove(parent, model);
    }
  }

  /**
   * Removes the child from the parent and fires the <i>Remove</i> event.
   *
   * @param parent the parent model
   * @param child the child model
   */
  public void remove(M parent, M child) {
    TreeModel p = findWrapper(parent);
    TreeModel c = findWrapper(child);
    if (p != null && c != null) {
      remove(p, c, false);
    }
  }

  @Override
  public void removeAll() {
    removeAll(false);
  }

  /**
   * Removes all the parent's children.
   *
   * @param parent the parent
   */
  public void removeAll(M parent) {
    TreeModel p = findWrapper(parent);
    if (p != null) {
      List<M> children = getChildren(parent);
      for (M m : children) {
        TreeModel child = findWrapper(m);
        if (child != null) {
          remove(p, child, false);
        }
      }
    }
  }

  /**
   * Sets the current sort info used when sorting items in the store.
   *
   * @param info the sort info
   */
  public void setSortInfo(SortInfo info) {
    this.sortInfo = info;
  }

  @Override
  public void setStoreSorter(StoreSorter<M> storeSorter) {
    super.setStoreSorter(storeSorter);
    applySort(false);
  }

  /**
   * Sorts the store.
   *
   * @param field the field to sort by
   * @param sortDir the sort dir
   */
  @SuppressWarnings("rawtypes")
  public void sort(String field, SortDir sortDir) {
    final StoreEvent<M> event = createStoreEvent();
    event.setSortInfo(new SortInfo(field, sortDir));

    if (!fireEvent(BeforeSort, event)) {
      return;
    }
    SortInfo prev = new SortInfo(sortInfo.getSortField(), sortInfo.getSortDir());
    if (sortDir == null) {
      if (sortInfo.getSortField() != null && !sortInfo.getSortField().equals(field)) {
        sortInfo.setSortDir(SortDir.NONE);
      }
      switch (sortInfo.getSortDir()) {
        case ASC:
          sortDir = SortDir.DESC;
          break;
        case DESC:
        case NONE:
          sortDir = SortDir.ASC;
          break;
      }
    }

    sortInfo.setSortField(field);
    sortInfo.setSortDir(sortDir);

    if (loader != null && loader instanceof RemoteSortTreeLoader) {
      final RemoteSortTreeLoader treeLoader = (RemoteSortTreeLoader) loader;
      if (treeLoader.isRemoteSort()) {
        Listener<LoadEvent> l = new Listener<LoadEvent>() {
          public void handleEvent(LoadEvent le) {
            treeLoader.removeListener(Loader.Load, this);
            sortInfo = le.<ListLoadConfig> getConfig().getSortInfo();
            event.setSortInfo(sortInfo);
            fireEvent(Sort, createStoreEvent());
          }
        };
        treeLoader.addListener(Loader.Load, l);
        treeLoader.setSortDir(sortDir);
        treeLoader.setSortField(field);
        if (!treeLoader.load()) {
          treeLoader.removeListener(Loader.Load, l);
          sortInfo.setSortField(prev.getSortField());
          sortInfo.setSortDir(prev.getSortDir());
        }
        return;
      }
    }

    applySort(false);
    fireEvent(DataChanged, createStoreEvent());
  }

  @Override
  @SuppressWarnings({"unchecked", "rawtypes"})
  protected void applySort(boolean supressEvent) {
    List<TreeModel> children = (List) rootWrapper.getChildren();
    if (children.size() > 0) {
      applySort(children);
    }
    if (useKeyProvider != null) {
      Collection<TreeModel> collection = useKeyProvider ? modelFastMap.values() : modelMap.values();
      for (TreeModel wrapper : collection) {
        children = (List) wrapper.getChildren();
        if (children.size() > 0) {
          applySort(children);
        }
      }
    }
    if (!supressEvent) {
      StoreEvent<M> event = createStoreEvent();
      event.setSortInfo(sortInfo);
      fireEvent(Sort, event);
    }
  }

  @SuppressWarnings({"unchecked", "rawtypes"})
  protected void applySort(List<TreeModel> list) {
    storeSorter = storeSorter == null ? new StoreSorter() : storeSorter;
    Collections.sort(list, new Comparator<TreeModel>() {
      public int compare(TreeModel m1, TreeModel m2) {
        return storeSorter.compare(TreeStore.this, unwrap(m1), unwrap(m2), sortInfo.getSortField());
      }
    });
    if (sortInfo.getSortDir() == SortDir.DESC) {
      Collections.reverse(list);
    }
  }

  @Override
  protected TreeStoreEvent<M> createStoreEvent() {
    return new TreeStoreEvent<M>(this);
  }

  protected TreeModel findWrapper(M item) {
    if (item != null) {
      if (useKeyProvider != null) {
        if (useKeyProvider) {
          return modelFastMap.get(getKey(item));
        }
        return modelMap.get(item);
      }
    }
    return null;
  }

  protected void onBeforeLoad(LoadEvent le) {
    if (!le.isCancelled() && !fireEvent(BeforeDataChanged, createStoreEvent())) {
      le.setCancelled(true);
    }
  }

  @SuppressWarnings({"unchecked", "rawtypes"})
  protected void onLoad(TreeLoadEvent le) {
    if (le.parent == null) {
      removeAll(true);
      List<TreeModel> insert = new ArrayList<TreeModel>();
      for (M model : (List<M>) le.getData()) {
        insert.add(wrap(model));
      }
      Object obj = le.getConfig();
      if (obj != null && obj instanceof ListLoadConfig) {
        ListLoadConfig config = le.getConfig();
        if (config.getSortInfo().getSortField() != null) {
          sortInfo = config.getSortInfo();
        } else {
          sortInfo = new SortInfo();
        }
      }
      doInsert(rootWrapper, insert, 0, false, true);
      if (filtersEnabled) {
        filtersEnabled = false;
        applyFilters(filterProperty);
      } else {
        fireEvent(DataChanged, new TreeStoreEvent(this));
      }
    } else {
      TreeModel wrapper = findWrapper((M) le.parent);
      if (wrapper != null) {
        if (wrapper.getChildren().size() > 0) {
          removeAll((M) le.parent);
        }
        List<TreeModel> insert = new ArrayList<TreeModel>();
        List<M> list = (List<M>) le.getData();
        for (M model : list) {
          insert.add(wrap(model));
        }
        doInsert(wrapper, insert, 0, false, true);
        if (filtersEnabled) {
          filtersEnabled = false;
          applyFilters(filterProperty);
        } else {
          TreeStoreEvent evt = new TreeStoreEvent(this);
          evt.setParent(le.parent);
          evt.setChildren(unwrapChildren(wrapper));
          fireEvent(DataChanged, evt);
        }
      }
    }
  }

  protected void onLoadException(LoadEvent le) {

  }

  @SuppressWarnings("unchecked")
  @Override
  protected void onModelChange(ChangeEvent ce) {
    super.onModelChange(ce);
    switch (ce.getType()) {
      case ChangeEventSource.Add: {
        if (ce.getSource() == ce.getParent()) {
          M parent = (M) ce.getParent();
          M child = (M) ce.getItem();
          insert(parent, child, ce.getIndex(), false);
        }
        break;
      }
      case ChangeEventSource.Remove: {
        if (ce.getSource() == ce.getParent()) {
          M parent = (M) ce.getParent();
          M child = (M) ce.getItem();
          remove(parent, child);
        }
        break;
      }
    }
  }

  protected void swapModelInstance(M oldModel, M newModel) {
    super.swapModelInstance(oldModel, newModel);
    if (useKeyProvider != null) {
      TreeModel wrapper = null;
      if (useKeyProvider) {
        wrapper = modelFastMap.get(getKey(oldModel));
      } else {
        wrapper = modelMap.get(oldModel);
      }
      if (wrapper != null) {
        wrapperMap.put(wrapper.<String> get("id"), newModel);
        if (!useKeyProvider && modelMap != null) {
          modelMap.remove(oldModel);
          modelMap.put(newModel, wrapper);
        }
      }
    }
  }

  protected List<M> unwrap(List<TreeModel> models) {
    List<M> children = new ArrayList<M>();
    if (isFiltered()) {
      for (TreeModel child : models) {
        if (!"true".equals(child.get("filtered"))) {
          children.add(unwrap(child));
        }
      }
    } else {
      for (TreeModel child : models) {
        children.add(unwrap(child));
      }
    }

    return children;
  }

  protected M unwrap(TreeModel wrapper) {
    return wrapperMap.get(wrapper.<String> get("id"));
  }

  @SuppressWarnings({"unchecked", "rawtypes"})
  protected List<M> unwrapChildren(TreeModel parent) {
    return unwrap((List) parent.getChildren());
  }

  protected TreeModel wrap(M model) {
    if (useKeyProvider == null) {
      if (getKeyProvider() == null) {
        modelMap = new HashMap<M, TreeModel>();
        useKeyProvider = false;
      } else {
        modelFastMap = new FastMap<TreeModel>();
        useKeyProvider = true;
      }
    }
    TreeModel wrapper = new BaseTreeModel();
    wrapper.set("id", String.valueOf(counter++));
    if (useKeyProvider) {
      modelFastMap.put(getKey(model), wrapper);
    } else {
      modelMap.put(model, wrapper);
    }
    wrapperMap.put(wrapper.<String> get("id"), model);
    return wrapper;
  }

  @SuppressWarnings({"unchecked", "rawtypes"})
  private void doInsert(TreeModel parent, List<TreeModel> children, int index, boolean addChildren, boolean supressEvent) {
    if (parent != null && children != null && children.size() > 0) {
      M modelParent = unwrap(parent);
      for (int i = children.size() - 1; i >= 0; i--) {
        TreeModel child = children.get(i);
        parent.insert(child, index);
        M m = unwrap(child);
        all.add(m);
        registerModel(m);
        if (storeSorter != null) {
          applySort((List) parent.getChildren());
          if (!supressEvent) {
            TreeStoreEvent evt = createStoreEvent();;
            evt.setParent(modelParent);
            evt.setIndex(parent.indexOf(child));
            evt.setChildren(Arrays.asList(m));
            fireEvent(Add, evt);
          }
        }
      }

      if (!supressEvent && storeSorter == null) {
        TreeStoreEvent evt = createStoreEvent();;
        evt.setParent(modelParent);
        evt.setChildren(unwrap(children));
        evt.setIndex(index);
        fireEvent(Add, evt);
      }

      if (addChildren) {
        for (TreeModel sub : children) {
          M model = unwrap(sub);
          if (model instanceof TreeModel) {
            TreeModel treeSub = (TreeModel) model;

            List<M> c = (List) treeSub.getChildren();
            if (c.size() > 0) {
              List<TreeModel> insert = new ArrayList<TreeModel>();
              for (M m : c) {
                insert.add(wrap(m));
              }
              doInsert(sub, insert, getChildCount(model), true, supressEvent);

              update(model);
            }

          }
        }
      }
    }
  }

  private void filterTreeWrap(TreeModel wrap) {
    List<ModelData> children = wrap.getChildren();
    for (int i = 0, len = children.size(); i < len; i++) {
      TreeModel tm = (TreeModel) children.get(i);
      if (isOrDecendantSelected(tm, unwrap(tm))) {
        tm.set("filtered", "false");
      } else {
        tm.set("filtered", "true");
      }
      filterTreeWrap(tm);
    }
  }

  private void findChildren(M parent, List<M> children) {
    for (M child : getChildren(parent)) {
      children.add(child);
      findChildren(child, children);
    }
  }

  private List<M> getFilteredChildren(TreeModel wrap) {
    List<TreeModel> filtered = new ArrayList<TreeModel>();
    for (ModelData child : wrap.getChildren()) {
      if (!isFiltered((TreeModel) child)) {
        filtered.add((TreeModel) child);
      }
    }
    return unwrap(filtered);
  }

  private String getKey(M model) {
    return getKeyProvider().getKey(model);
  }

  private boolean isFiltered(TreeModel wrap) {
    return "true".equals(wrap.get("filtered"));
  }

  private boolean isOrDecendantSelected(TreeModel wrap, M model) {
    if (!isFiltered(model, filterProperty)) {
      return true;
    }
    List<ModelData> children = wrap.getChildren();
    for (int i = 0, len = children.size(); i < len; i++) {
      TreeModel tm = (TreeModel) children.get(i);
      boolean result = isOrDecendantSelected(tm, unwrap(tm));
      if (result) {
        return true;
      }
    }

    return false;
  }

  private void remove(TreeModel parent, TreeModel child, boolean supressEvent) {
    int index = parent.getChildren().indexOf(child);
    if (index != -1) {
      parent.remove(child);
      M model = unwrap(child);
      List<M> children = new ArrayList<M>();
      findChildren(model, children);

      for (M c : children) {
        all.remove(c);
        wrapperMap.remove(findWrapper(c).<String> get("id"));
        if (useKeyProvider) {
          modelFastMap.remove(getKey(c));
        } else {
          modelMap.remove(c);
        }
        modified.remove(recordMap.get(c));
        unregisterModel(c);
      }
      all.remove(model);
      wrapperMap.remove(child.<String> get("id"));
      if (useKeyProvider) {
        modelFastMap.remove(getKey(model));
      } else {
        modelMap.remove(model);
      }
      modified.remove(recordMap.get(model));
      unregisterModel(model);
      if (!supressEvent) {
        TreeStoreEvent<M> evt = new TreeStoreEvent<M>(this);
        evt.setParent(unwrap(parent));
        evt.setChild(model);
        evt.setChildren(children);
        evt.setIndex(index);
        fireEvent(Remove, evt);
      }
    }
  }

  private void removeAll(boolean supressEvent) {
    for (M m : all) {
      unregisterModel(m);
    }
    all.clear();
    modified.clear();
    recordMap.clear();
    if (modelMap != null) {
      modelMap.clear();
    } else if (modelFastMap != null) {
      modelFastMap.clear();
    }
    wrapperMap.clear();
    rootWrapper.removeAll();
    if (!supressEvent) {
      fireEvent(Clear, createStoreEvent());
    }
  }

}
TOP

Related Classes of com.extjs.gxt.ui.client.store.TreeStore

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.