Package com.google.gwt.user.cellview.client

Source Code of com.google.gwt.user.cellview.client.CellList$Template

/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.user.cellview.client;

import com.google.gwt.cell.client.Cell;
import com.google.gwt.cell.client.Cell.Context;
import com.google.gwt.cell.client.ValueUpdater;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.EventTarget;
import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.CssResource;
import com.google.gwt.resources.client.CssResource.ImportedWithPrefix;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.resources.client.ImageResource.ImageOptions;
import com.google.gwt.resources.client.ImageResource.RepeatStyle;
import com.google.gwt.safehtml.client.SafeHtmlTemplates;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.safehtml.shared.SafeHtmlUtils;
import com.google.gwt.user.cellview.client.HasDataPresenter.LoadingState;
import com.google.gwt.user.client.Event;
import com.google.gwt.view.client.CellPreviewEvent;
import com.google.gwt.view.client.ProvidesKey;
import com.google.gwt.view.client.SelectionModel;

import java.util.List;
import java.util.Set;

/**
* A single column list of cells.
*
* <p>
* <h3>Examples</h3>
* <dl>
* <dt>Trivial example</dt>
* <dd>{@example com.google.gwt.examples.cellview.CellListExample}</dd>
* <dt>ValueUpdater example</dt>
* <dd>{@example com.google.gwt.examples.cellview.CellListValueUpdaterExample}</dd>
* <dt>Key provider example</dt>
* <dd>{@example com.google.gwt.examples.view.KeyProviderExample}</dd>
* </dl>
* </p>
*
* @param <T> the data type of list items
*/
public class CellList<T> extends AbstractHasData<T> {

  /**
   * A ClientBundle that provides images for this widget.
   */
  public interface Resources extends ClientBundle {
    /**
     * The background used for selected items.
     */
    @ImageOptions(repeatStyle = RepeatStyle.Horizontal, flipRtl = true)
    ImageResource cellListSelectedBackground();

    /**
     * The styles used in this widget.
     */
    @Source(Style.DEFAULT_CSS)
    Style cellListStyle();
  }

  /**
   * Styles used by this widget.
   */
  @ImportedWithPrefix("gwt-CellList")
  public interface Style extends CssResource {
    /**
     * The path to the default CSS styles used by this resource.
     */
    String DEFAULT_CSS = "com/google/gwt/user/cellview/client/CellList.css";

    /**
     * Applied to even items.
     */
    String cellListEvenItem();

    /**
     * Applied to the keyboard selected item.
     */
    String cellListKeyboardSelectedItem();

    /**
     * Applied to odd items.
     */
    String cellListOddItem();

    /**
     * Applied to selected items.
     */
    String cellListSelectedItem();

    /**
     * Applied to the widget.
     */
    String cellListWidget();
  }

  interface Template extends SafeHtmlTemplates {
    @Template("<div onclick=\"\" __idx=\"{0}\" class=\"{1}\" style=\"outline:none;\" >{2}</div>")
    SafeHtml div(int idx, String classes, SafeHtml cellContents);

    @Template("<div onclick=\"\" __idx=\"{0}\" class=\"{1}\" style=\"outline:none;\" tabindex=\"{2}\">{3}</div>")
    SafeHtml divFocusable(int idx, String classes, int tabIndex,
        SafeHtml cellContents);

    @Template("<div onclick=\"\" __idx=\"{0}\" class=\"{1}\" style=\"outline:none;\" tabindex=\"{2}\" accesskey=\"{3}\">{4}</div>")
    SafeHtml divFocusableWithKey(int idx, String classes, int tabIndex,
        char accessKey, SafeHtml cellContents);
  }

  /**
   * The default page size.
   */
  private static final int DEFAULT_PAGE_SIZE = 25;

  private static Resources DEFAULT_RESOURCES;

  private static final Template TEMPLATE = GWT.create(Template.class);

  private static Resources getDefaultResources() {
    if (DEFAULT_RESOURCES == null) {
      DEFAULT_RESOURCES = GWT.create(Resources.class);
    }
    return DEFAULT_RESOURCES;
  }

  private final Cell<T> cell;
  private boolean cellIsEditing;
  private final Element childContainer;

  private SafeHtml emptyListMessage = SafeHtmlUtils.fromSafeConstant("");
  private final Element emptyMessageElem;

  private final Style style;

  private ValueUpdater<T> valueUpdater;

  /**
   * Construct a new {@link CellList}.
   *
   * @param cell the cell used to render each item
   */
  public CellList(final Cell<T> cell) {
    this(cell, getDefaultResources(), null);
  }

  /**
   * Construct a new {@link CellList} with the specified {@link Resources}.
   *
   * @param cell the cell used to render each item
   * @param resources the resources used for this widget
   */
  public CellList(final Cell<T> cell, Resources resources) {
    this(cell, resources, null);
  }

  /**
   * Construct a new {@link CellList} with the specified {@link ProvidesKey key provider}.
   *
   * @param cell the cell used to render each item
   * @param keyProvider an instance of ProvidesKey<T>, or null if the record
   *        object should act as its own key
   */
  public CellList(final Cell<T> cell, ProvidesKey<T> keyProvider) {
    this(cell, getDefaultResources(), keyProvider);
  }

  /**
   * Construct a new {@link CellList} with the specified {@link Resources}
   * and {@link ProvidesKey key provider}.
   *
   * @param cell the cell used to render each item
   * @param resources the resources used for this widget
   * @param keyProvider an instance of ProvidesKey<T>, or null if the record
   *        object should act as its own key
   */
  public CellList(final Cell<T> cell, Resources resources, ProvidesKey<T> keyProvider) {
    super(Document.get().createDivElement(), DEFAULT_PAGE_SIZE, keyProvider);
    this.cell = cell;
    this.style = resources.cellListStyle();
    this.style.ensureInjected();

    String widgetStyle = this.style.cellListWidget();
    if (widgetStyle != null) {
      // The widget style is null when used in CellBrowser.
      addStyleName(widgetStyle);
    }

    // Create the DOM hierarchy.
    childContainer = Document.get().createDivElement();

    emptyMessageElem = Document.get().createDivElement();
    showOrHide(emptyMessageElem, false);

    DivElement outerDiv = getElement().cast();
    outerDiv.appendChild(childContainer);
    outerDiv.appendChild(emptyMessageElem);

    // Sink events that the cell consumes.
    CellBasedWidgetImpl.get().sinkEvents(this, cell.getConsumedEvents());
  }

  /**
   * Get the message that is displayed when there is no data.
   *
   * @return the empty message
   * @see #setEmptyListMessage(SafeHtml)
   */
  public SafeHtml getEmptyListMessage() {
    return emptyListMessage;
  }

  /**
   * Get the {@link Element} for the specified index. If the element has not
   * been created, null is returned.
   *
   * @param indexOnPage the index on the page
   * @return the element, or null if it doesn't exists
   * @throws IndexOutOfBoundsException if the index is outside of the current
   *           page
   */
  public Element getRowElement(int indexOnPage) {
    getPresenter().flush();
    checkRowBounds(indexOnPage);
    if (childContainer.getChildCount() > indexOnPage) {
      return childContainer.getChild(indexOnPage).cast();
    }
    return null;
  }

  /**
   * Set the message to display when there is no data.
   *
   * @param html the message to display when there are no results
   * @see #getEmptyListMessage()
   */
  public void setEmptyListMessage(SafeHtml html) {
    this.emptyListMessage = html;
    emptyMessageElem.setInnerHTML(html.asString());
  }

  /**
   * Set the value updater to use when cells modify items.
   *
   * @param valueUpdater the {@link ValueUpdater}
   */
  public void setValueUpdater(ValueUpdater<T> valueUpdater) {
    this.valueUpdater = valueUpdater;
  }

  @Override
  protected boolean dependsOnSelection() {
    return cell.dependsOnSelection();
  }

  /**
   * Called when a user action triggers selection.
   *
   * @param event the event that triggered selection
   * @param value the value that was selected
   * @param indexOnPage the index of the value on the page
   * @deprecated use
   *             {@link #addCellPreviewHandler(com.google.gwt.view.client.CellPreviewEvent.Handler)}
   *             instead
   */
  @Deprecated
  protected void doSelection(Event event, T value, int indexOnPage) {
  }

  /**
   * Fire an event to the cell.
   *
   * @param context the {@link Context} of the cell
   * @param event the event that was fired
   * @param parent the parent of the cell
   * @param value the value of the cell
   */
  protected void fireEventToCell(Context context, Event event, Element parent,
      T value) {
    Set<String> consumedEvents = cell.getConsumedEvents();
    if (consumedEvents != null && consumedEvents.contains(event.getType())) {
      boolean cellWasEditing = cell.isEditing(context, parent, value);
      cell.onBrowserEvent(context, parent, value, event, valueUpdater);
      cellIsEditing = cell.isEditing(context, parent, value);
      if (cellWasEditing && !cellIsEditing) {
        CellBasedWidgetImpl.get().resetFocus(new Scheduler.ScheduledCommand() {
          public void execute() {
            setFocus(true);
          }
        });
      }
    }
  }

  /**
   * Return the cell used to render each item.
   */
  protected Cell<T> getCell() {
    return cell;
  }

  /**
   * Get the parent element that wraps the cell from the list item. Override
   * this method if you add structure to the element.
   *
   * @param item the row element that wraps the list item
   * @return the parent element of the cell
   */
  protected Element getCellParent(Element item) {
    return item;
  }

  @Override
  protected Element getChildContainer() {
    return childContainer;
  }

  @Override
  protected Element getKeyboardSelectedElement() {
    // Do not use getRowElement() because that will flush the presenter.
    int rowIndex = getKeyboardSelectedRow();
    if (rowIndex >= 0 && childContainer.getChildCount() > rowIndex) {
      return childContainer.getChild(rowIndex).cast();
    }
    return null;
  }

  @Override
  protected boolean isKeyboardNavigationSuppressed() {
    return cellIsEditing;
  }

  @Override
  protected void onBlur() {
    // Remove the keyboard selection style.
    Element elem = getKeyboardSelectedElement();
    if (elem != null) {
      elem.removeClassName(style.cellListKeyboardSelectedItem());
    }
  }

  @SuppressWarnings("deprecation")
  @Override
  protected void onBrowserEvent2(Event event) {
    // Get the event target.
    EventTarget eventTarget = event.getEventTarget();
    if (!Element.is(eventTarget)) {
      return;
    }
    final Element target = event.getEventTarget().cast();

    // Forward the event to the cell.
    String idxString = "";
    Element cellTarget = target;
    while ((cellTarget != null)
        && ((idxString = cellTarget.getAttribute("__idx")).length() == 0)) {
      cellTarget = cellTarget.getParentElement();
    }
    if (idxString.length() > 0) {
      // Select the item if the cell does not consume events. Selection occurs
      // before firing the event to the cell in case the cell operates on the
      // currently selected item.
      String eventType = event.getType();
      boolean isClick = "click".equals(eventType);
      int idx = Integer.parseInt(idxString);
      int indexOnPage = idx - getPageStart();
      if (!isRowWithinBounds(indexOnPage)) {
        // If the event causes us to page, then the index will be out of bounds.
        return;
      }

      // Get the cell parent before doing selection in case the list is redrawn.
      boolean isSelectionHandled = cell.handlesSelection()
          || KeyboardSelectionPolicy.BOUND_TO_SELECTION == getKeyboardSelectionPolicy();
      Element cellParent = getCellParent(cellTarget);
      T value = getVisibleItem(indexOnPage);
      Context context = new Context(idx, 0, getValueKey(value));
      CellPreviewEvent<T> previewEvent = CellPreviewEvent.fire(this, event,
          this, context, value, cellIsEditing, isSelectionHandled);
      if (isClick && !cellIsEditing && !isSelectionHandled) {
        doSelection(event, value, indexOnPage);
      }

      // Focus on the cell.
      if (isClick) {
        /*
         * If the selected element is natively focusable, then we do not want to
         * steal focus away from it.
         */
        boolean isFocusable = CellBasedWidgetImpl.get().isFocusable(target);
        isFocused = isFocused || isFocusable;
        getPresenter().setKeyboardSelectedRow(indexOnPage, !isFocusable, false);
      }

      // Fire the event to the cell if the list has not been refreshed.
      if (!previewEvent.isCanceled()) {
        fireEventToCell(context, event, cellParent, value);
      }
    }
  }

  @Override
  protected void onFocus() {
    // Add the keyboard selection style.
    Element elem = getKeyboardSelectedElement();
    if (elem != null) {
      elem.addClassName(style.cellListKeyboardSelectedItem());
    }
  }

  @Override
  protected void renderRowValues(SafeHtmlBuilder sb, List<T> values, int start,
      SelectionModel<? super T> selectionModel) {
    String keyboardSelectedItem = " " + style.cellListKeyboardSelectedItem();
    String selectedItem = " " + style.cellListSelectedItem();
    String evenItem = style.cellListEvenItem();
    String oddItem = style.cellListOddItem();
    int keyboardSelectedRow = getKeyboardSelectedRow() + getPageStart();
    int length = values.size();
    int end = start + length;
    for (int i = start; i < end; i++) {
      T value = values.get(i - start);
      boolean isSelected = selectionModel == null ? false
          : selectionModel.isSelected(value);

      StringBuilder classesBuilder = new StringBuilder();
      classesBuilder.append(i % 2 == 0 ? evenItem : oddItem);
      if (isSelected) {
        classesBuilder.append(selectedItem);
      }

      SafeHtmlBuilder cellBuilder = new SafeHtmlBuilder();
      Context context = new Context(i, 0, getValueKey(value));
      cell.render(context, value, cellBuilder);

      if (i == keyboardSelectedRow) {
        // This is the focused item.
        if (isFocused) {
          classesBuilder.append(keyboardSelectedItem);
        }
        char accessKey = getAccessKey();
        if (accessKey != 0) {
          sb.append(TEMPLATE.divFocusableWithKey(i, classesBuilder.toString(),
              getTabIndex(), accessKey, cellBuilder.toSafeHtml()));
        } else {
          sb.append(TEMPLATE.divFocusable(i, classesBuilder.toString(),
              getTabIndex(), cellBuilder.toSafeHtml()));
        }
      } else {
        sb.append(TEMPLATE.div(i, classesBuilder.toString(),
            cellBuilder.toSafeHtml()));
      }
    }
  }

  @Override
  protected boolean resetFocusOnCell() {
    int row = getKeyboardSelectedRow();
    if (isRowWithinBounds(row)) {
      Element rowElem = getKeyboardSelectedElement();
      Element cellParent = getCellParent(rowElem);
      T value = getVisibleItem(row);
      Context context = new Context(row + getPageStart(), 0, getValueKey(value));
      return cell.resetFocus(context, cellParent, value);
    }
    return false;
  }

  @Override
  protected void setKeyboardSelected(int index, boolean selected,
      boolean stealFocus) {
    if (!isRowWithinBounds(index)) {
      return;
    }

    Element elem = getRowElement(index);
    if (!selected || isFocused || stealFocus) {
      setStyleName(elem, style.cellListKeyboardSelectedItem(), selected);
    }
    setFocusable(elem, selected);
    if (selected && stealFocus && !cellIsEditing) {
      elem.focus();
      onFocus();
    }
  }

  /**
   * @deprecated this method is never called by AbstractHasData, render the
   *             selected styles in
   *             {@link #renderRowValues(SafeHtmlBuilder, List, int, SelectionModel)}
   */
  @Override
  @Deprecated
  protected void setSelected(Element elem, boolean selected) {
    setStyleName(elem, style.cellListSelectedItem(), selected);
  }

  @Override
  void setLoadingState(LoadingState state) {
    showOrHide(emptyMessageElem, state == LoadingState.EMPTY);
    // TODO(jlabanca): Add a loading icon.
  }

  /**
   * Show or hide an element.
   *
   * @param element the element
   * @param show true to show, false to hide
   */
  private void showOrHide(Element element, boolean show) {
    if (show) {
      element.getStyle().clearDisplay();
    } else {
      element.getStyle().setDisplay(Display.NONE);
    }
  }
}
TOP

Related Classes of com.google.gwt.user.cellview.client.CellList$Template

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.