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

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

/*
* Ext GWT - Ext for GWT
* Copyright(c) 2007, 2008, Ext JS, LLC.
* licensing@extjs.com
*
* http://extjs.com/license
*/
package com.extjs.gxt.ui.client.store;

import java.util.ArrayList;
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.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.LoadEvent;
import com.extjs.gxt.ui.client.data.ModelData;
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.LoadListener;
import com.extjs.gxt.ui.client.util.Util;

/**
* A store for hierarchical data.
*
* <p/> The parent child relationshiops 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. All sorter will be applied to all inserts into the store.
*
* <p/> Remote sorting is not supported with TreeStore.
*
* <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 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>
*
* </dt>
*/
public class TreeStore<M extends ModelData> extends Store<M> {

  protected Map<M, TreeModel> modelMap = new HashMap<M, TreeModel>();
  protected Map<TreeModel, M> wrapperMap = new HashMap<TreeModel, M>();
  protected BaseTreeModel rootWrapper = new BaseTreeModel();

  protected TreeLoader loader;

  public TreeStore() {
    super();
  }

  public TreeStore(TreeLoader 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 recursivly 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 recursivly add all children
   */
  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 recursivly 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 recursivly add all children
   */
  public void add(M parent, M item, boolean addChildren) {
    insert(parent, item, getChildCount(parent), addChildren);
  }

  /**
   * 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) {
    TreeModel child = rootWrapper.getChild(index);
    if (child != null) {
      return unwrap(child);
    }
    return null;
  }

  /**
   * Returns the child at the given index.
   *
   * @param parent the parent model
   * @param index the index
   * @return the child of the parent at the given index
   */
  public M getChild(M parent, int index) {
    TreeModel p = findWrapper(parent);

    if (p != null) {
      TreeModel child = p.getChild(index);
      if (child != null) {
        return unwrap(child);
      }
    }
    return null;
  }

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

  /**
   * 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) {
    TreeModel p = findWrapper(parent);
    if (p != null) {
      return p.getChildCount();
    }
    return -1;
  }

  /**
   * Returns the children of the parent.
   *
   * @param parent the children
   * @return the children or null if parent not found in stote
   */
  public List<M> getChildren(M parent) {
    TreeModel p = findWrapper(parent);
    if (p != null) {
      return unwrapChildren(p);
    }
    return null;
  }

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

  /**
   * 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 root level items.
   *
   * @return the items
   */
  public List<M> getRootItems() {
    return unwrapChildren(rootWrapper);
  }

  /**
   * 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 recursivly 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 recursivly add all children
   */
  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 recursivly 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 recursivly add all children
   */
  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.
   *
   * @param model the item to be removed
   */
  public void remove(M model) {
    remove(rootWrapper, findWrapper(model), false);
  }

  /**
   * 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 usen when sorting items in the store.
   *
   * @param info the sort info
   */
  public void setSortInfo(SortInfo info) {
    this.sortInfo = info;
  }

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

  @Override
  protected void applySort(boolean supressEvent) {
    for (TreeModel wrapper : wrapperMap.keySet()) {
      List<TreeModel> children = wrapper.getChildren();
      if (children.size() > 0) {
        applySort(children);
      }
    }
    if (supressEvent) {
      fireEvent(Sort, createStoreEvent());
    }
  }

  protected void applySort(List<TreeModel> list) {
    if (storeSorter != null) {
      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 createStoreEvent() {
    return new TreeStoreEvent(this);
  }

  protected TreeModel findWrapper(M item) {
    return modelMap.get(item);
  }

  protected void onBeforeLoad(LoadEvent le) {
    fireEvent(BeforeDataChanged, createStoreEvent());
  }

  protected void onLoad(TreeLoadEvent le) {
    if (le.parent == null) {
      removeAll(true);
      List<TreeModel> insert = new ArrayList<TreeModel>();
      for (M model : (List<M>) le.data) {
        insert.add(wrap(model));
      }
      doInsert(rootWrapper, insert, 0, false, true);
      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.data;
        for (M model : list) {
          insert.add(wrap(model));
        }
        doInsert(wrapper, insert, 0, false, true);
        TreeStoreEvent evt = new TreeStoreEvent(this);
        evt.parent = le.parent;
        evt.children = unwrapChildren(wrapper);
        fireEvent(DataChanged, evt);
      }
    }
  }

  protected void onLoadException(LoadEvent le) {
    throw new RuntimeException(le.exception);
  }

  @Override
  protected void onModelChange(ChangeEvent ce) {
    super.onModelChange(ce);
    switch (ce.type) {
      case ChangeEventSource.Add: {
        if (ce.source == ce.parent) {
          M parent = (M) ce.parent;
          M child = (M) ce.item;
          add(parent, child, false);
        }
        break;
      }
      case ChangeEventSource.Remove: {
        if (ce.source == ce.parent) {
          M parent = (M) ce.parent;
          M child = (M) ce.item;
          remove(parent, child);
        }

        break;
      }
    }

  }

  protected List<M> unwrap(List<TreeModel> models) {
    List<M> children = new ArrayList<M>();
    for (TreeModel child : models) {
      children.add(unwrap(child));
    }
    return children;
  }

  protected M unwrap(TreeModel wrapper) {
    return wrapperMap.get(wrapper);
  }

  protected List<M> unwrapChildren(TreeModel parent) {
    return unwrap(parent.getChildren());
  }

  protected TreeModel wrap(M model) {
    TreeModel wrapper = new BaseTreeModel();
    modelMap.put(model, wrapper);
    wrapperMap.put(wrapper, model);
    return wrapper;
  }

  private void doInsert(TreeModel parent, List<TreeModel> children, int index, boolean addChildren,
      boolean supressEvent) {
    if (parent != null && children != null) {
      M modelParent = unwrap(parent);
      for (int i = children.size() - 1; i >= 0; i--) {
        parent.insert(children.get(i), index);
        M m = unwrap(children.get(i));
        all.add(m);
        registerModel(m);
      }
      if (storeSorter != null) {
        applySort(parent.getChildren());
      }

      if (!supressEvent) {
        if (storeSorter != null) {
          for (TreeModel child : children) {
            TreeStoreEvent evt = createStoreEvent();;
            evt.parent = modelParent;
            evt.index = parent.indexOf(child);
            evt.children = Util.createList(unwrap(child));
            fireEvent(Add, evt);
          }
        } else {
          TreeStoreEvent evt = createStoreEvent();;
          evt.parent = modelParent;
          evt.children = unwrap(children);
          evt.index = index;
          fireEvent(Add, evt);
        }
      }

      if (addChildren) {
        for (TreeModel sub : children) {
          M model = unwrap(sub);
          if (model instanceof TreeModel) {
            TreeModel treeSub = (TreeModel) model;
            List<TreeModel> insert = new ArrayList<TreeModel>();
            List<M> c = treeSub.getChildren();
            for (M m : c) {
              insert.add(wrap(m));
            }
            doInsert(sub, insert, getChildCount(model), true, false);
            update(model);
          }
        }
      }
    }
  }

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

  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);
        modelMap.remove(c);
        unregisterModel(c);
        wrapperMap.remove(findWrapper(c));
      }
      all.remove(model);
      wrapperMap.remove(child);
      modelMap.remove(model);
      unregisterModel(model);
      if (!supressEvent) {
        TreeStoreEvent evt = new TreeStoreEvent(this);
        evt.parent = unwrap(parent);
        evt.child = model;
        evt.children = children;
        evt.index = index;
        fireEvent(Remove, evt);
      }
    }
  }

  private void removeAll(boolean supressEvent) {
    all.clear();
    modified.clear();
    modelMap.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.