/* * 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.user.datepicker.client; import com.google.gwt.dom.client.Element; import com.google.gwt.event.dom.client.KeyDownEvent; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.impl.ElementMapperImpl; import com.google.gwt.user.client.ui.Grid; import com.google.gwt.user.client.ui.UIObject; import java.util.ArrayList; import java.util.Iterator; /** * Highlighting, selectable cell grid. Used to help construct the default * calendar view. * * @param <V> type of value in grid. */ abstract class CellGridImpl<V> extends Grid { /** * Cell type. */ public abstract class Cell extends UIObject { private boolean enabled = true; private V value; private int index; /** * Create a cell grid. * * @param elem the wrapped element * @param value the value */ public Cell(Element elem, V value) { this.value = value; Cell current = this; index = cellList.size(); cellList.add(current); setElement(elem); elementToCell.put(current); } public V getValue() { return value; } public boolean isEnabled() { return enabled; } public boolean isHighlighted() { return this == highlightedCell; } public boolean isSelected() { return selectedCell == this; } public final void setEnabled(boolean enabled) { this.enabled = enabled; onEnabled(enabled); } public void verticalNavigation(int keyCode) { switch (keyCode) { case KeyCodes.KEY_UP: setHighlighted(previousItem()); break; case KeyCodes.KEY_DOWN: setHighlighted(nextItem()); break; case KeyCodes.KEY_ESCAPE: // Figure out new event for this. break; case KeyCodes.KEY_ENTER: setSelected(this); break; } } protected Cell nextItem() { if (index == getLastIndex()) { return cellList.get(0); } else { return cellList.get(index + 1); } } /** * @param enabled */ protected void onEnabled(boolean enabled) { updateStyle(); } /** * @param highlighted */ protected void onHighlighted(boolean highlighted) { updateStyle(); } /** * @param selected */ protected void onSelected(boolean selected) { updateStyle(); } protected Cell previousItem() { if (index != 0) { return cellList.get(index - 1); } else { return cellList.get(getLastIndex()); } } protected abstract void updateStyle(); private int getLastIndex() { return cellList.size() - 1; } } private Cell highlightedCell; private Cell selectedCell; private ElementMapperImpl<Cell> elementToCell = new ElementMapperImpl<Cell>(); private ArrayList<Cell> cellList = new ArrayList<Cell>(); protected CellGridImpl() { setCellPadding(0); setCellSpacing(0); setBorderWidth(0); sinkEvents(Event.ONCLICK | Event.ONMOUSEOVER | Event.ONMOUSEOUT); } public Cell getCell(Element element) { // This cast is always valid because both Element types are JSOs and have // no new fields are added in the subclass. return elementToCell.get((com.google.gwt.user.client.Element) element); } public Cell getCell(Event e) { // Find out which cell was actually clicked. Element td = getEventTargetCell(e); return td != null ? elementToCell.get((com.google.gwt.user.client.Element) td) : null; } public Cell getCell(int i) { return cellList.get(i); } public Iterator getCells() { return cellList.iterator(); } public Cell getHighlightedCell() { return highlightedCell; } public int getNumCells() { return cellList.size(); } public Cell getSelectedCell() { return selectedCell; } public V getSelectedValue() { return getValue(selectedCell); } public V getValue(Cell cell) { return (cell == null ? null : cell.getValue()); } @Override public void onBrowserEvent(Event event) { switch (DOM.eventGetType(event)) { case Event.ONCLICK: { Cell cell = getCell(event); if (isActive(cell)) { setSelected(cell); } break; } case Event.ONMOUSEOUT: { Element e = DOM.eventGetFromElement(event); if (e != null) { Cell cell = elementToCell.get((com.google.gwt.user.client.Element) e); if (cell == highlightedCell) { setHighlighted(null); } } break; } case Event.ONMOUSEOVER: { Element e = DOM.eventGetToElement(event); if (e != null) { Cell cell = elementToCell.get((com.google.gwt.user.client.Element) e); if (isActive(cell)) { setHighlighted(cell); } } break; } } } @Override public void onUnload() { setHighlighted(null); } public final void setHighlighted(Cell nextHighlighted) { if (nextHighlighted == highlightedCell) { return; } Cell oldHighlighted = highlightedCell; highlightedCell = nextHighlighted; if (oldHighlighted != null) { oldHighlighted.onHighlighted(false); } if (highlightedCell != null) { highlightedCell.onHighlighted(true); } } public final void setSelected(Cell cell) { Cell last = getSelectedCell(); selectedCell = cell; if (last != null) { last.onSelected(false); } if (selectedCell != null) { selectedCell.onSelected(true); } onSelected(last, selectedCell); } protected void onKeyDown(Cell lastHighlighted, KeyDownEvent event) { if (event.isAnyModifierKeyDown()) { return; } int keyCode = event.getNativeKeyCode(); if (lastHighlighted == null) { if (keyCode == KeyCodes.KEY_DOWN && cellList.size() > 0) { setHighlighted(cellList.get(0)); } } else { lastHighlighted.verticalNavigation(keyCode); } } protected abstract void onSelected(Cell lastSelected, Cell cell); private boolean isActive(Cell cell) { return cell != null && cell.isEnabled(); } }