All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.extjs.gxt.ui.client.widget.grid.LiveGridView Maven / Gradle / Ivy

There is a newer version: 2.3.1-gwt22
Show newest version
/*
 * Sencha GXT 2.3.1a - Sencha for GWT
 * Copyright(c) 2007-2013, Sencha, Inc.
 * [email protected]
 * 
 * http://www.sencha.com/products/gxt/license/
 */
 package com.extjs.gxt.ui.client.widget.grid;

import com.extjs.gxt.ui.client.GXT;
import com.extjs.gxt.ui.client.Style.SortDir;
import com.extjs.gxt.ui.client.core.El;
import com.extjs.gxt.ui.client.core.XDOM;
import com.extjs.gxt.ui.client.data.ModelData;
import com.extjs.gxt.ui.client.data.ModelKeyProvider;
import com.extjs.gxt.ui.client.data.PagingLoadResult;
import com.extjs.gxt.ui.client.data.PagingLoader;
import com.extjs.gxt.ui.client.event.BaseEvent;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.event.GridEvent;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.event.LiveGridEvent;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.store.Record;
import com.extjs.gxt.ui.client.store.StoreEvent;
import com.extjs.gxt.ui.client.store.StoreListener;
import com.extjs.gxt.ui.client.util.DelayedTask;
import com.google.gwt.dom.client.Element;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.Event;

/**
 * LiveGridView for displaying large amount of data. Data is loaded on demand as
 * the user scrolls the grid.
 */
@SuppressWarnings("deprecation")
public class LiveGridView extends GridView {

  protected El liveScroller;
  protected ListStore liveStore;
  protected int liveStoreOffset = 0;
  protected int totalCount = 0;
  protected int viewIndex;

  private int cacheSize = 200;
  private boolean ignoreScroll;
  private boolean isLoading;
  // to prevent flickering
  private boolean isMasked;
  private StoreListener liveStoreListener;
  private int loadDelay = 200;
  private PagingLoader> loader;
  private int loaderOffset;
  private DelayedTask loaderTask;
  private double prefetchFactor = .2;
  private int rowHeight = 20;
  private int viewIndexReload = -1;

  /**
   * Returns the numbers of rows that should be cached.
   * 
   * @return the cache size
   */
  public int getCacheSize() {
    int c = -1;
    if (grid.isViewReady()) {
      c = getVisibleRowCount();
    }
    return Math.max(c, cacheSize);
  }

  /**
   * Returns the amount of time before loading is done.
   * 
   * @return the load delay in milliseconds
   */
  public int getLoadDelay() {
    return loadDelay;
  }

  /**
   * Returns the prefetchFactor.
   * 
   * @return the prefetchFactor
   */
  public double getPrefetchFactor() {
    return prefetchFactor;
  }

  /**
   * Returns the height of one row.
   * 
   * @return the height of one row
   */
  public int getRowHeight() {
    return rowHeight;
  }

  public int getVisibleRowCount() {
    int rh = getCalculatedRowHeight();
    int visibleHeight = getLiveScrollerHeight();
    return (int) ((visibleHeight < 1) ? 0 : Math.floor((double) visibleHeight / rh));
  }

  @SuppressWarnings("rawtypes")
  @Override
  public void handleComponentEvent(GridEvent ge) {
    super.handleComponentEvent(ge);
    int type = ge.getEventTypeInt();
    Element target = ge.getTarget();
    if (!ignoreScroll && (type == Event.ONSCROLL && liveScroller.dom.isOrHasChild(target))
        || (type == Event.ONMOUSEWHEEL && mainBody.dom.isOrHasChild(target))) {
      ge.stopEvent();
      if (type == Event.ONMOUSEWHEEL) {
        int v = ge.getEvent().getMouseWheelVelocityY() * getCalculatedRowHeight();
        liveScroller.setScrollTop(liveScroller.getScrollTop() + v);
      } else {
        updateRows((int) Math.ceil((double) liveScroller.getScrollTop() / getCalculatedRowHeight()), false);
      }
    }
  }

  /**
   * Refreshed the view. Reloads the store based on the current settings
   */
  public void refresh() {
    maskView();
    loadLiveStore(liveStoreOffset);
  }

  @Override
  public void refresh(boolean headerToo) {
    super.refresh(headerToo);
    if (headerToo) {
      positionLiveScroller();
    }
    if (!preventScrollToTopOnRefresh) {
      // we scrolled to the top
      updateRows(0, false);
    }
  }

  @Override
  public void scrollToTop() {
    liveScroller.setScrollTop(0);
  }

  /**
   * Sets the amount of rows that should be cached (default to 200). The cache
   * size is the number of rows that are retrieved each time a data request is
   * made. The cache size should always be greater than the number of visible
   * rows of the grid. The number of visible rows will vary depending on the
   * grid height and the height of each row. If the set cache size is smaller
   * than the number of visible rows of the grid than it gets set to the number
   * of visible rows of the grid.
   * 
   * @param cacheSize the new cache size
   */
  public void setCacheSize(int cacheSize) {
    this.cacheSize = cacheSize;
  }

  /**
   * Sets the amount of time before loading is done (defaults to 200).
   * 
   * @param loadDelay the new load delay in milliseconds
   */
  public void setLoadDelay(int loadDelay) {
    this.loadDelay = loadDelay;
  }

  /**
   * Sets the pre-fetch factor (defaults to .2). The pre-fetch factor is used to
   * determine when new data should be fetched as the user scrolls the grid. The
   * factor is used with the cache size.
   * 
   * 

* For example, if the cache size is 1000 with a pre-fetch of .20, the grid * will request new data when the 800th (1000 * .20) row of the grid becomes * visible. * * @param prefetchFactor the pre-fetch factor */ public void setPrefetchFactor(double prefetchFactor) { this.prefetchFactor = prefetchFactor; } /** * Sets the height of one row (defaults to 20). LiveGridView will * only work with fixed row heights with all rows being the same height. * Changing this value will not physically resize the row heights, rather, the * specified height will be used internally for calculations. * * @param rowHeight the new row height. */ public void setRowHeight(int rowHeight) { this.rowHeight = rowHeight; } @Override protected void afterRender() { mainBody.setInnerHtml(renderRows(0, -1)); renderWidgets(0, -1); processRows(0, true); applyEmptyText(); refresh(); } @Override protected void calculateVBar(boolean force) { if (force) { layout(); } } @SuppressWarnings({"rawtypes", "unchecked"}) protected GridEvent createComponentEvent(Event event) { LiveGridEvent l = new LiveGridEvent(grid, event); l.setLiveStoreOffset(liveStoreOffset); l.setViewIndex(viewIndex); l.setTotalCount(totalCount); return l; } protected void doLoad() { loader.load(loaderOffset, getCacheSize()); } protected int getCalculatedRowHeight() { return rowHeight + borderWidth; } protected int getLiveScrollerHeight() { return liveScroller.getHeight(true); } protected int getLiveStoreCalculatedIndex(int index) { int calcIndex = index - (getCacheSize() / 2) + getVisibleRowCount(); calcIndex = Math.min(totalCount - getCacheSize(), calcIndex); calcIndex = Math.min(index, calcIndex); return Math.max(0, calcIndex); } @Override protected int getScrollAdjust() { return scrollOffset; } @SuppressWarnings({"unchecked", "rawtypes"}) protected void initData(ListStore ds, ColumnModel cm) { if (liveStoreListener == null) { liveStoreListener = new StoreListener() { public void storeDataChanged(StoreEvent se) { liveStoreOffset = loader.getOffset(); if (totalCount != loader.getTotalCount()) { totalCount = loader.getTotalCount(); int height = totalCount * getCalculatedRowHeight(); // 1000000 as browser maxheight hack int count = height / 1000000; int h = 0; StringBuilder sb = new StringBuilder(); if (count > 0) { h = height / count; for (int i = 0; i < count; i++) { sb.append("

 
"); } } int diff = height - count * h; if (diff != 0) { sb.append("
"); } liveScroller.setInnerHtml(sb.toString()); } if (totalCount > 0 && viewIndexReload != -1 && !isCached(viewIndexReload)) { loadLiveStore(getLiveStoreCalculatedIndex(viewIndexReload)); } else { viewIndexReload = -1; ignoreScroll = true; int scrollTop = liveScroller.getScrollTop(); liveScroller.setScrollTop(scrollTop - 1); liveScroller.setScrollTop(scrollTop); ignoreScroll = false; updateRows(viewIndex, true); isLoading = false; if (isMasked) { isMasked = false; scroller.unmask(); } } } public void storeUpdate(StoreEvent se) { LiveGridView.this.ds.update(se.getModel()); } }; } if (liveStore != null) { liveStore.removeStoreListener(liveStoreListener); } liveStore = ds; super.initData(new ListStore() { @Override public boolean equals(ModelData model1, ModelData model2) { return LiveGridView.this.liveStore.equals(model1, model2); } @Override public ModelKeyProvider getKeyProvider() { return LiveGridView.this.liveStore.getKeyProvider(); } @Override public Record getRecord(ModelData model) { return LiveGridView.this.liveStore.getRecord(model); } @Override public boolean hasRecord(ModelData model) { return LiveGridView.this.liveStore.hasRecord(model); } @Override public void sort(String field, SortDir sortDir) { LiveGridView.this.liveStore.sort(field, sortDir); sortInfo = liveStore.getSortState(); } }, cm); loader = (PagingLoader) liveStore.getLoader(); liveStore.addStoreListener(liveStoreListener); grid.getSelectionModel().bind(this.ds); } protected boolean isCached(int index) { if ((liveStore.getCount() == 0 && totalCount > 0) || (index < liveStoreOffset) || (index > (liveStoreOffset + getCacheSize() - getVisibleRowCount()))) { return false; } return true; } protected boolean isHorizontalScrollBarShowing() { return cm.getTotalWidth() + getScrollAdjust() > scroller.dom.getOffsetWidth(); } protected boolean loadLiveStore(int offset) { if (loaderTask == null) { loaderTask = new DelayedTask(new Listener() { public void handleEvent(BaseEvent be) { doLoad(); } }); } loaderOffset = offset; loaderTask.delay(loadDelay); if (isLoading) { return true; } else { isLoading = true; return false; } } @Override protected void notifyShow() { super.notifyShow(); updateRows((int) Math.ceil((double) liveScroller.getScrollTop() / getCalculatedRowHeight()), true); } @Override protected void onRemove(ListStore ds, ModelData m, int index, boolean isUpdate) { super.onRemove(ds, m, index, isUpdate); if (!isUpdate && liveStore.hasRecord(m)) { liveStore.getRecord(m).reject(false); } } @Override protected void renderUI() { super.renderUI(); scroller.setStyleAttribute("overflowY", "hidden"); liveScroller = grid.el().insertFirst( "
 
"); positionLiveScroller(); liveScroller.addEventsSunk(Event.ONSCROLL); mainBody.addEventsSunk(Event.ONMOUSEWHEEL); } @Override protected void resize() { final int oldCount = getVisibleRowCount(); super.resize(); if (mainBody != null) { resizeLiveScroller(); scroller.setWidth(grid.getWidth() - getScrollAdjust(), true); DeferredCommand.addCommand(new Command() { public void execute() { if (oldCount != getVisibleRowCount()) { updateRows(LiveGridView.this.viewIndex, true); } } }); } } protected boolean shouldCache(int index) { int cz = getCacheSize(); int i = (int) (cz * prefetchFactor); double low = liveStoreOffset + i; double high = liveStoreOffset + cz - getVisibleRowCount() - i; if ((index < low && liveStoreOffset > 0) || (index > high && liveStoreOffset != totalCount - cz)) { return true; } return false; } @Override protected void updateAllColumnWidths() { super.updateAllColumnWidths(); resizeLiveScroller(); updateRows(viewIndex, true); } @Override protected void updateColumnHidden(int index, boolean hidden) { super.updateColumnHidden(index, hidden); resizeLiveScroller(); updateRows(viewIndex, true); } @Override protected void updateColumnWidth(int col, int width) { super.updateColumnWidth(col, width); resizeLiveScroller(); updateRows(viewIndex, true); } @SuppressWarnings("unchecked") protected void updateRows(int newIndex, boolean reload) { int rowCount = getVisibleRowCount(); newIndex = Math.min(newIndex, Math.max(0, totalCount - rowCount)); int diff = newIndex - viewIndex; int delta = Math.abs(diff); // nothing has changed and we are not forcing a reload if (delta == 0 && !reload) { return; } viewIndex = newIndex; int liveStoreIndex = Math.max(0, viewIndex - liveStoreOffset); // load data if not already cached if (!isCached(viewIndex)) { maskView(); if (loadLiveStore(getLiveStoreCalculatedIndex(viewIndex))) { viewIndexReload = viewIndex; } return; } // do pre caching if (shouldCache(viewIndex) && !isLoading) { loadLiveStore(getLiveStoreCalculatedIndex(viewIndex)); } int rc = getVisibleRowCount(); if (delta > rc - 1) { reload = true; } if (reload) { delta = diff = rc; boolean p = preventScrollToTopOnRefresh; preventScrollToTopOnRefresh = true; ds.removeAll(); preventScrollToTopOnRefresh = p; } if (delta == 0) { return; } int count = ds.getCount(); if (diff > 0) { // rolling forward for (int c = 0; c < delta && c < count; c++) { ds.remove(0); } count = ds.getCount(); ds.add(liveStore.getRange(liveStoreIndex + count, liveStoreIndex + count + delta - 1)); } else { // rolling back for (int c = 0; c < delta && c < count; c++) { ds.remove(count - c - 1); } ds.insert(liveStore.getRange(liveStoreIndex, liveStoreIndex + delta - 1), 0); } LiveGridEvent event = (LiveGridEvent) createComponentEvent(null); fireEvent(Events.LiveGridViewUpdate, event); } private void maskView() { if (!isMasked && grid.isLoadMask()) { scroller.mask(GXT.MESSAGES.loadMask_msg()); isMasked = true; } } private void positionLiveScroller() { liveScroller.setTop(mainHd.getHeight()); } private void resizeLiveScroller() { int h = grid.getHeight(true) - mainHd.getHeight(true); if (isHorizontalScrollBarShowing()) { h -= XDOM.getScrollBarWidth(); } if (footer != null) { h -= footer.getHeight(); } liveScroller.setHeight(h, true); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy