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

com.google.gwt.user.cellview.client.CellList Maven / Gradle / Ivy

There is a newer version: 2.10.0
Show newest version
/*
 * 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.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.LoadingStateChangeEvent.LoadingState;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.AttachDetachException;
import com.google.gwt.user.client.ui.DeckPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.CellPreviewEvent;
import com.google.gwt.view.client.ProvidesKey;
import com.google.gwt.view.client.SelectionModel;

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

/**
 * A single column list of cells.
 * 
 * 

*

Examples

*
*
Trivial example
*
{@example com.google.gwt.examples.cellview.CellListExample}
*
ValueUpdater example
*
{@example com.google.gwt.examples.cellview.CellListValueUpdaterExample}
*
Key provider example
*
{@example com.google.gwt.examples.view.KeyProviderExample}
*
*

* * @param the data type of list items */ public class CellList extends AbstractHasData { /** * 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("
{2}
") SafeHtml div(int idx, String classes, SafeHtml cellContents); @Template("
{3}
") SafeHtml divFocusable(int idx, String classes, int tabIndex, SafeHtml cellContents); @Template("
{4}
") 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 cell; private boolean cellIsEditing; private final Element childContainer; private SafeHtml emptyListMessage = SafeHtmlUtils.fromSafeConstant(""); private final SimplePanel emptyListWidgetContainer = new SimplePanel(); private final SimplePanel loadingIndicatorContainer = new SimplePanel(); /** * A {@link DeckPanel} to hold widgets associated with various loading states. */ private final DeckPanel messagesPanel = new DeckPanel(); private final Style style; private ValueUpdater valueUpdater; /** * Construct a new {@link CellList}. * * @param cell the cell used to render each item */ public CellList(final Cell 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 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, or null if the record * object should act as its own key */ public CellList(final Cell cell, ProvidesKey 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, or null if the record * object should act as its own key */ public CellList(final Cell cell, Resources resources, ProvidesKey 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); } // Add the child container. childContainer = Document.get().createDivElement(); DivElement outerDiv = getElement().cast(); outerDiv.appendChild(childContainer); // Attach the message panel. outerDiv.appendChild(messagesPanel.getElement()); adopt(messagesPanel); messagesPanel.add(emptyListWidgetContainer); messagesPanel.add(loadingIndicatorContainer); // 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) * @deprecated as of GWT 2.3, use {@link #getEmptyListWidget()} instead */ @Deprecated public SafeHtml getEmptyListMessage() { return emptyListMessage; } /** * Get the widget displayed when the list has no rows. * * @return the empty list widget */ public Widget getEmptyListWidget() { return emptyListWidgetContainer.getWidget(); } /** * Get the widget displayed when the data is loading. * * @return the loading indicator */ public Widget getLoadingIndicator() { return loadingIndicatorContainer.getWidget(); } /** * 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() * @deprecated as of GWT 2.3, use * {@link #setEmptyDataWidget(com.google.gwt.user.client.ui.Widget)} * instead */ @Deprecated public void setEmptyListMessage(SafeHtml html) { this.emptyListMessage = html; setEmptyListWidget(html == null ? null : new HTML(html)); } /** * Set the widget to display when the list has no rows. * * @param widget the empty data widget */ public void setEmptyListWidget(Widget widget) { emptyListWidgetContainer.setWidget(widget); } /** * Set the widget to display when the data is loading. * * @param widget the loading indicator */ public void setLoadingIndicator(Widget widget) { loadingIndicatorContainer.setWidget(widget); } /** * Set the value updater to use when cells modify items. * * @param valueUpdater the {@link ValueUpdater} */ public void setValueUpdater(ValueUpdater valueUpdater) { this.valueUpdater = valueUpdater; } @Override protected boolean dependsOnSelection() { return cell.dependsOnSelection(); } @Override protected void doAttachChildren() { try { doAttach(messagesPanel); } catch (Throwable e) { throw new AttachDetachException(Collections.singleton(e)); } } @Override protected void doDetachChildren() { try { doDetach(messagesPanel); } catch (Throwable e) { throw new AttachDetachException(Collections.singleton(e)); } } /** * 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 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 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 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()); } } /** * Called when the loading state changes. * * @param state the new loading state */ @Override protected void onLoadingStateChanged(LoadingState state) { Widget message = null; if (state == LoadingState.LOADING) { // Loading indicator. message = loadingIndicatorContainer; } else if (state == LoadingState.LOADED && getPresenter().isEmpty()) { // Empty table. message = emptyListWidgetContainer; } // Switch out the message to display. if (message != null) { messagesPanel.showWidget(messagesPanel.getWidgetIndex(message)); } // Show the correct container. showOrHide(getChildContainer(), message == null); messagesPanel.setVisible(message != null); // Fire an event. super.onLoadingStateChanged(state); } @Override protected void renderRowValues(SafeHtmlBuilder sb, List values, int start, SelectionModel 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); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy