/*
* Copyright 2008 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.gen2.table.client;
import com.google.gwt.user.client.rpc.IsSerializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
/**
* A helper class that provides all of the inner classes used by
* {@link TableModel}. These classes cannot be included in the
* {@link TableModel} class itself because of a JDT error that prevents the GWT
* RPC generator from creating implementations of remote services:
* https://bugs.eclipse.org/bugs/show_bug.cgi?id=243820
*
* This class should be removed once this bug is fixed.
*/
public final class TableModelHelper {
/**
* Information about the sort order of a specific column in a table.
*/
public static class ColumnSortInfo implements IsSerializable {
/**
* True if the sort order is ascending.
*/
private boolean ascending;
/**
* The column index.
*/
private int column;
/**
* Default constructor used for RPC.
*/
public ColumnSortInfo() {
this(0, true);
}
/**
* Construct a new {@link ColumnSortInfo}.
*
* @param column the column index
* @param ascending true if sorted ascending
*/
public ColumnSortInfo(int column, boolean ascending) {
this.column = column;
this.ascending = ascending;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof ColumnSortInfo) {
return equals((ColumnSortInfo) obj);
}
return false;
}
/**
* Check if this object is equal to another. The objects are equal if the
* column and ascending values are equal.
*
* @param csi the other object
* @return true if objects are the same
*/
public boolean equals(ColumnSortInfo csi) {
if (csi == null) {
return false;
}
return getColumn() == csi.getColumn()
&& isAscending() == csi.isAscending();
}
/**
* @return the column index
*/
public int getColumn() {
return column;
}
@Override
public int hashCode() {
return super.hashCode();
}
/**
* @return true if ascending, false if descending
*/
public boolean isAscending() {
return ascending;
}
/**
* Set whether or not the sorting is ascending or descending.
*
* @param ascending true if ascending, false if descending
*/
public void setAscending(boolean ascending) {
this.ascending = ascending;
}
/**
* Set the column index.
*
* @param column the column index
*/
public void setColumn(int column) {
this.column = column;
}
}
/**
* An ordered list of sorting info where each entry tells us how to sort a
* single column. The first entry is the primary sort order, the second entry
* is the first tie-breaker, and so on.
*/
public static class ColumnSortList implements IsSerializable,
Iterable<ColumnSortInfo> {
/**
* A List used to manage the insertion/removal of {@link ColumnSortInfo}.
*/
private List<ColumnSortInfo> infos = new ArrayList<ColumnSortInfo>();
/**
* Add a {@link ColumnSortInfo} to this list. If the column already exists,
* it will be removed from its current position and placed at the start of
* the list, becoming the primary sort info.
*
* This add method inserts an entry at the beginning of the list. It does
* not append the entry to the end of the list.
*
* @param sortInfo the {@link ColumnSortInfo} to add
*/
public void add(ColumnSortInfo sortInfo) {
add(0, sortInfo);
}
/**
* Inserts the specified {@link ColumnSortInfo} at the specified position in
* this list. If the column already exists in the sort info, the index will
* be adjusted to account for any removed entries.
*
* @param sortInfo the {@link ColumnSortInfo} to add
*/
public void add(int index, ColumnSortInfo sortInfo) {
// Remove sort info for duplicate columns
int column = sortInfo.getColumn();
for (int i = 0; i < infos.size(); i++) {
ColumnSortInfo curInfo = infos.get(i);
if (curInfo.getColumn() == column) {
infos.remove(i);
i--;
if (column < index) {
index--;
}
}
}
// Insert the new sort info
infos.add(index, sortInfo);
}
/**
* Removes all of the elements from this list.
*/
public void clear() {
infos.clear();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof ColumnSortList) {
return equals((ColumnSortList) obj);
}
return false;
}
/**
* Check if this object is equal to another.
*
* @param csl the other object
* @return true if objects are equal
*/
public boolean equals(ColumnSortList csl) {
// Object is null
if (csl == null) {
return false;
}
// Check the size of the lists
int size = size();
if (size != csl.size()) {
return false;
}
// Compare the entries
for (int i = 0; i < size; i++) {
if (!infos.get(i).equals(csl.infos.get(i))) {
return false;
}
}
// Everything is equal
return true;
}
/**
* Get the primary (first) {@link ColumnSortInfo}'s column index.
*
* @return the primary column or -1 if not sorted
*/
public int getPrimaryColumn() {
ColumnSortInfo primaryInfo = getPrimaryColumnSortInfo();
if (primaryInfo == null) {
return -1;
}
return primaryInfo.getColumn();
}
/**
* Get the primary (first) {@link ColumnSortInfo}.
*
* @return the primary column sort info
*/
public ColumnSortInfo getPrimaryColumnSortInfo() {
if (infos.size() > 0) {
return infos.get(0);
}
return null;
}
@Override
public int hashCode() {
return super.hashCode();
}
/**
* Get the primary (first) {@link ColumnSortInfo}'s sort order.
*
* @return true if ascending, false if descending
*/
public boolean isPrimaryAscending() {
ColumnSortInfo primaryInfo = getPrimaryColumnSortInfo();
if (primaryInfo == null) {
return true;
}
return primaryInfo.isAscending();
}
public Iterator<ColumnSortInfo> iterator() {
return new ImmutableIterator<ColumnSortInfo>(infos.iterator());
}
/**
* Remove a {@link ColumnSortInfo} from the list.
*
* @param sortInfo the {@link ColumnSortInfo} to remove
*/
public boolean remove(Object sortInfo) {
return infos.remove(sortInfo);
}
/**
* @return the number of {@link ColumnSortInfo} in the list
*/
public int size() {
return infos.size();
}
/**
* @return a duplicate of this list
*/
ColumnSortList copy() {
ColumnSortList copy = new ColumnSortList();
for (ColumnSortInfo info : this) {
copy.infos.add(new ColumnSortInfo(info.getColumn(), info.isAscending()));
}
return copy;
}
}
/**
* A {@link TableModelHelper} request.
*/
public static class Request implements IsSerializable {
/**
* The number of rows to request.
*/
private int numRows;
/**
* An ordered list of {@link ColumnSortInfo}.
*/
private ColumnSortList columnSortList;
/**
* The first row of table data to request.
*/
private int startRow;
/**
* Default constructor used for RPC.
*/
public Request() {
this(0, 0, null);
}
/**
* Construct a new {@link Request}.
*
* @param startRow the first row to request
* @param numRows the number of rows to request
*/
public Request(int startRow, int numRows) {
this(startRow, numRows, null);
}
/**
* Construct a new {@link Request} with information about the sort order of
* columns.
*
* @param startRow the first row to request
* @param numRows the number of rows to request
* @param columnSortList a list of {@link ColumnSortInfo}
*/
public Request(int startRow, int numRows, ColumnSortList columnSortList) {
this.startRow = startRow;
this.numRows = numRows;
this.columnSortList = columnSortList;
}
/**
* @return the list of {@link ColumnSortInfo}
*/
public ColumnSortList getColumnSortList() {
return columnSortList;
}
/**
* @return the number of requested rows
*/
public int getNumRows() {
return numRows;
}
/**
* @return the first requested row
*/
public int getStartRow() {
return startRow;
}
}
/**
* A response from the {@link TableModelHelper}.
*
* @param <RowType> the data type of the row values
*/
public abstract static class Response<RowType> {
/**
* Get the objects associated with the retrieved rows.
*
* @return the objects associated with the retrieved row
*/
public abstract Iterator<RowType> getRowValues();
}
/**
* A response from the {@link TableModelHelper} that is serializable, and can
* by used over RPC.
*
* @param <RowType> the serializable data type of the row values
*/
public static class SerializableResponse<RowType extends IsSerializable>
extends Response<RowType> implements IsSerializable {
/**
* The {@link Collection} of row values.
*/
private Collection<RowType> rowValues;
/**
* Default constructor used for RPC.
*/
public SerializableResponse() {
this(null);
}
/**
* Create a new {@link SerializableResponse}.
*/
public SerializableResponse(Collection<RowType> rowValues) {
this.rowValues = rowValues;
}
@Override
public Iterator<RowType> getRowValues() {
return rowValues.iterator();
}
}
/**
* Wrap an {@link Iterator} in an immutable iterator.
*/
private static class ImmutableIterator<E> implements Iterator<E> {
private Iterator<E> iterator;
public ImmutableIterator(Iterator<E> iterator) {
this.iterator = iterator;
}
public boolean hasNext() {
return iterator.hasNext();
}
public E next() {
return iterator.next();
}
public void remove() {
throw (new UnsupportedOperationException());
}
}
}