com.google.gerrit.client.ui.NavigationTable.java Source code

Java tutorial

Introduction

Here is the source code for com.google.gerrit.client.ui.NavigationTable.java

Source

// 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.KeyCodes;
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.Event;
import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
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.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> {
    protected class MyFlexTable extends FancyFlexTable.MyFlexTable {
        public MyFlexTable() {
            sinkEvents(Event.ONDBLCLICK | Event.ONCLICK);
        }

        @Override
        public void onBrowserEvent(final Event event) {
            switch (DOM.eventGetType(event)) {
            case Event.ONCLICK: {
                // Find out which cell was actually clicked.
                final Element td = getEventTargetCell(event);
                if (td == null) {
                    break;
                }
                final int row = rowOf(td);
                if (getRowItem(row) != null) {
                    onCellSingleClick(rowOf(td), columnOf(td));
                    return;
                }
                break;
            }
            case Event.ONDBLCLICK: {
                // Find out which cell was actually clicked.
                Element td = getEventTargetCell(event);
                if (td == null) {
                    return;
                }
                onCellDoubleClick(rowOf(td), columnOf(td));
                return;
            }
            }
            super.onBrowserEvent(event);
        }
    }

    @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(String itemHelpName) {
        this();
        keysNavigation.add(new PrevKeyCommand(0, 'k', Util.M.helpListPrev(itemHelpName)));
        keysNavigation.add(new NextKeyCommand(0, 'j', Util.M.helpListNext(itemHelpName)));
        keysNavigation.add(new OpenKeyCommand(0, 'o', Util.M.helpListOpen(itemHelpName)));
        keysNavigation.add(new OpenKeyCommand(0, KeyCodes.KEY_ENTER, Util.M.helpListOpen(itemHelpName)));
    }

    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);
            }
        }
    }

    /** Invoked when the user double clicks on a table cell. */
    protected void onCellDoubleClick(int row, int column) {
        onOpenRow(row);
    }

    /** Invoked when the user clicks on a table cell. */
    protected void onCellSingleClick(int row, int column) {
        movePointerTo(row);
    }

    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 {
                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);
            pointer.removeFromParent();
        }
        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();
    }

    @Override
    protected MyFlexTable createFlexTable() {
        return new MyFlexTable();
    }

    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();
        }
    }
}