blob: 1beae9dd92a587b9788dff3c147f972404aedafb [file] [log] [blame]
// Copyright (C) 2009 The Android Open Source Project
//
// 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.gerrit.client.ui;
import com.google.gerrit.client.Gerrit;
import com.google.gwt.dom.client.Document;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.UIObject;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
import com.google.gwtexpui.globalkey.client.GlobalKey;
import com.google.gwtexpui.globalkey.client.KeyCommand;
import com.google.gwtexpui.globalkey.client.KeyCommandSet;
import com.google.gwtexpui.safehtml.client.SafeHtml;
import java.util.LinkedHashMap;
import java.util.Map.Entry;
public abstract class NavigationTable<RowItem> extends FancyFlexTable<RowItem> {
@SuppressWarnings("serial")
private static final LinkedHashMap<String, Object> savedPositions =
new LinkedHashMap<String, Object>(10, 0.75f, true) {
@Override
protected boolean removeEldestEntry(Entry<String, Object> eldest) {
return size() >= 20;
}
};
private final Image pointer;
protected final KeyCommandSet keysNavigation;
protected final KeyCommandSet keysAction;
private HandlerRegistration regNavigation;
private HandlerRegistration regAction;
private int currentRow = -1;
private String saveId;
private boolean computedScrollType;
private ScrollPanel parentScrollPanel;
protected NavigationTable() {
pointer = new Image(Gerrit.RESOURCES.arrowRight());
keysNavigation = new KeyCommandSet(Gerrit.C.sectionNavigation());
keysAction = new KeyCommandSet(Gerrit.C.sectionActions());
}
protected abstract void onOpenRow(int row);
protected abstract Object getRowItemKey(RowItem item);
private void onUp() {
for (int row = currentRow - 1; row >= 0; row--) {
if (getRowItem(row) != null) {
movePointerTo(row);
break;
}
}
}
private void onDown() {
final int max = table.getRowCount();
for (int row = currentRow + 1; row < max; row++) {
if (getRowItem(row) != null) {
movePointerTo(row);
break;
}
}
}
private void onOpen() {
if (0 <= currentRow && currentRow < table.getRowCount()) {
if (getRowItem(currentRow) != null) {
onOpenRow(currentRow);
}
}
}
protected int getCurrentRow() {
return currentRow;
}
protected void ensurePointerVisible() {
final int max = table.getRowCount();
int row = currentRow;
final int init = row;
if (row < 0) {
row = 0;
} else if (max <= row) {
row = max - 1;
}
final CellFormatter fmt = table.getCellFormatter();
final int sTop = Document.get().getScrollTop();
final int sEnd = sTop + Document.get().getClientHeight();
while (0 <= row && row < max) {
final Element cur = DOM.getParent(fmt.getElement(row, C_ARROW));
final int cTop = cur.getAbsoluteTop();
final int cEnd = cTop + cur.getOffsetHeight();
if (cEnd < sTop) {
row++;
} else if (sEnd < cTop) {
row--;
} else if (getRowItem(row) != null) {
break;
}
}
if (init != row) {
movePointerTo(row, false);
}
}
protected void movePointerTo(final int newRow) {
movePointerTo(newRow, true);
}
protected void movePointerTo(final int newRow, final boolean scroll) {
final CellFormatter fmt = table.getCellFormatter();
final boolean clear = 0 <= currentRow && currentRow < table.getRowCount();
if (clear) {
final Element tr = DOM.getParent(fmt.getElement(currentRow, C_ARROW));
UIObject.setStyleName(tr, Gerrit.RESOURCES.css().activeRow(), false);
}
if (newRow >= 0) {
table.setWidget(newRow, C_ARROW, pointer);
final Element tr = DOM.getParent(fmt.getElement(newRow, C_ARROW));
UIObject.setStyleName(tr, Gerrit.RESOURCES.css().activeRow(), true);
if (scroll) {
scrollIntoView(tr);
}
} else if (clear) {
table.setWidget(currentRow, C_ARROW, null);
}
currentRow = newRow;
}
protected void scrollIntoView(final Element tr) {
if (!computedScrollType) {
parentScrollPanel = null;
Widget w = getParent();
while (w != null) {
if (w instanceof ScrollPanel) {
parentScrollPanel = (ScrollPanel) w;
break;
}
w = w.getParent();
}
computedScrollType = true;
}
if (parentScrollPanel != null) {
parentScrollPanel.ensureVisible(new UIObject() {
{
setElement(tr);
}
});
} else {
tr.scrollIntoView();
}
}
protected void movePointerTo(final Object oldId) {
final int row = findRow(oldId);
if (0 <= row) {
movePointerTo(row);
}
}
protected int findRow(final Object oldId) {
if (oldId != null) {
final int max = table.getRowCount();
for (int row = 0; row < max; row++) {
final RowItem c = getRowItem(row);
if (c != null && oldId.equals(getRowItemKey(c))) {
return row;
}
}
}
return -1;
}
@Override
protected void resetHtml(SafeHtml body) {
currentRow = -1;
super.resetHtml(body);
}
public void finishDisplay() {
if (saveId != null) {
movePointerTo(savedPositions.get(saveId));
}
if (currentRow < 0) {
onDown();
}
}
public void setSavePointerId(final String id) {
saveId = id;
}
public void setRegisterKeys(final boolean on) {
if (on && isAttached()) {
if (regNavigation == null) {
regNavigation = GlobalKey.add(this, keysNavigation);
}
if (regAction == null) {
regAction = GlobalKey.add(this, keysAction);
}
} else {
if (regNavigation != null) {
regNavigation.removeHandler();
regNavigation = null;
}
if (regAction != null) {
regAction.removeHandler();
regAction = null;
}
}
}
@Override
protected void onLoad() {
computedScrollType = false;
parentScrollPanel = null;
}
@Override
protected void onUnload() {
setRegisterKeys(false);
if (saveId != null && currentRow >= 0) {
final RowItem c = getRowItem(currentRow);
if (c != null) {
savedPositions.put(saveId, getRowItemKey(c));
}
}
computedScrollType = false;
parentScrollPanel = null;
super.onUnload();
}
public class PrevKeyCommand extends KeyCommand {
public PrevKeyCommand(int mask, char key, String help) {
super(mask, key, help);
}
@Override
public void onKeyPress(final KeyPressEvent event) {
ensurePointerVisible();
onUp();
}
}
public class NextKeyCommand extends KeyCommand {
public NextKeyCommand(int mask, char key, String help) {
super(mask, key, help);
}
@Override
public void onKeyPress(final KeyPressEvent event) {
ensurePointerVisible();
onDown();
}
}
public class OpenKeyCommand extends KeyCommand {
public OpenKeyCommand(int mask, int key, String help) {
super(mask, key, help);
}
@Override
public void onKeyPress(final KeyPressEvent event) {
ensurePointerVisible();
onOpen();
}
}
}