com.google.gwt.view.client.AbstractDataProvider.java Source code

Java tutorial

Introduction

Here is the source code for com.google.gwt.view.client.AbstractDataProvider.java

Source

/*
 * 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.view.client;

import com.google.gwt.event.shared.HandlerRegistration;

import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * A base implementation of a data source for {@link HasData} implementations.
 *
 * @param <T> the data type of records in the list
 */
public abstract class AbstractDataProvider<T> implements ProvidesKey<T> {

    private Set<HasData<T>> displays = new HashSet<HasData<T>>();

    /**
     * The provider of keys for list items.
     */
    private final ProvidesKey<T> keyProvider;

    /**
     * The last row count.
     */
    private int lastRowCount = -1;

    /**
     * Indicates whether or not the last row count is exact.
     */
    private boolean lastRowCountExact;

    /**
     * A mapping of {@link HasData}s to their handlers.
     */
    private Map<HasData<T>, HandlerRegistration> rangeChangeHandlers = new HashMap<HasData<T>, HandlerRegistration>();

    /**
     * Construct an AbstractDataProvider without a key provider.
     */
    protected AbstractDataProvider() {
        this.keyProvider = null;
    }

    /**
     * Construct an AbstractDataProvider with a given key provider.
     * 
     * @param keyProvider a {@link ProvidesKey} object
     */
    protected AbstractDataProvider(ProvidesKey<T> keyProvider) {
        this.keyProvider = keyProvider;
    }

    /**
     * Adds a data display to this adapter. The current range of interest of the
     * display will be populated with data.
     *
     * @param display a {@link HasData}.
     */
    public void addDataDisplay(final HasData<T> display) {
        if (display == null) {
            throw new IllegalArgumentException("display cannot be null");
        } else if (displays.contains(display)) {
            throw new IllegalStateException("The specified display has already been added to this adapter.");
        }

        // Add the display to the set.
        displays.add(display);

        // Add a handler to the display.
        HandlerRegistration handler = display.addRangeChangeHandler(new RangeChangeEvent.Handler() {
            public void onRangeChange(RangeChangeEvent event) {
                AbstractDataProvider.this.onRangeChanged(display);
            }
        });
        rangeChangeHandlers.put(display, handler);

        // Update the data size in the display.
        if (lastRowCount >= 0) {
            display.setRowCount(lastRowCount, lastRowCountExact);
        }

        // Initialize the display with the current range.
        onRangeChanged(display);
    }

    /**
     * Get the set of displays currently assigned to this adapter.
     *
     * @return the set of {@link HasData}
     */
    public Set<HasData<T>> getDataDisplays() {
        return Collections.unmodifiableSet(displays);
    }

    /**
     * Get the key for a list item. The default implementation returns the item
     * itself.
     *
     * @param item the list item
     * @return the key that represents the item
     */
    public Object getKey(T item) {
        return keyProvider == null ? item : keyProvider.getKey(item);
    }

    /**
     * Get the {@link ProvidesKey} that provides keys for list items.
     *
     * @return the {@link ProvidesKey}
     */
    public ProvidesKey<T> getKeyProvider() {
        return keyProvider;
    }

    /**
     * Get the current ranges of all displays.
     *
     * @return the ranges
     */
    public Range[] getRanges() {
        Range[] ranges = new Range[displays.size()];
        int i = 0;
        for (HasData<T> display : displays) {
            ranges[i++] = display.getVisibleRange();
        }
        return ranges;
    }

    /**
     * Remove the given data display.
     * 
     * @param display a {@link HasData} instance
     * 
     * @throws IllegalStateException if the display is not present
     */
    public void removeDataDisplay(HasData<T> display) {
        if (!displays.contains(display)) {
            throw new IllegalStateException("HasData not present");
        }
        displays.remove(display);

        // Remove the handler.
        HandlerRegistration handler = rangeChangeHandlers.remove(display);
        handler.removeHandler();
    }

    /**
     * Called when a display changes its range of interest.
     *
     * @param display the display whose range has changed
     */
    protected abstract void onRangeChanged(HasData<T> display);

    /**
     * Inform the displays of the total number of items that are available.
     *
     * @param count the new total row count
     * @param exact true if the count is exact, false if it is an estimate
     */
    protected void updateRowCount(int count, boolean exact) {
        lastRowCount = count;
        lastRowCountExact = exact;

        for (HasData<T> display : displays) {
            display.setRowCount(count, exact);
        }
    }

    /**
     * Inform the displays of the new data.
     *
     * @param start the start index
     * @param values the data values
     */
    protected void updateRowData(int start, List<T> values) {
        for (HasData<T> display : displays) {
            updateRowData(display, start, values);
        }
    }

    /**
     * Informs a single display of new data.
     *
     * @param display the display to be updated
     * @param start the start index
     * @param values the data values
     */
    protected void updateRowData(HasData<T> display, int start, List<T> values) {
        int end = start + values.size();
        Range range = display.getVisibleRange();
        int curStart = range.getStart();
        int curLength = range.getLength();
        int curEnd = curStart + curLength;
        if (start == curStart || (curStart < end && curEnd > start)) {
            // Fire the handler with the data that is in the range.
            // Allow an empty list that starts on the page start.
            int realStart = curStart < start ? start : curStart;
            int realEnd = curEnd > end ? end : curEnd;
            int realLength = realEnd - realStart;
            List<T> realValues = values.subList(realStart - start, realStart - start + realLength);
            display.setRowData(realStart, realValues);
        }
    }
}