annis.gui.widgets.gwt.client.ui.VAnnotationGrid.java Source code

Java tutorial

Introduction

Here is the source code for annis.gui.widgets.gwt.client.ui.VAnnotationGrid.java

Source

/*
 * Copyright 2011 Corpuslinguistic working group Humboldt University Berlin.
 *
 * 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 annis.gui.widgets.gwt.client.ui;

import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.TableCellElement;
import com.google.gwt.dom.client.TableRowElement;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTMLTable.Cell;
import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.Paintable;
import com.vaadin.client.UIDL;
import com.vaadin.client.Util;
import com.vaadin.client.VConsole;
import java.util.HashMap;
import java.util.Map;

/**
 *
 * @author thomas
 */
public class VAnnotationGrid extends Composite implements Paintable {

    /**
     * Set the CSS class name to allow styling.
     */
    public static final String CLASSNAME = "v-annotationgrid";

    /**
     * The client side widget identifier
     */
    protected String paintableId;

    /**
     * Reference to the server connection object.
     */
    ApplicationConnection gClient;

    private AnnotationGridTable table;

    private FlexTable.FlexCellFormatter formatter;

    private BiMap<Position, String> position2id;

    private Map<String, String[]> highlighted;

    private Map<Position, Double> startTimes;

    private Map<Position, Double> endTimes;

    // build maps row and col to a pdf page number
    private Map<Position, String> pdfPageNumbers;

    /**
     * when true, all html tags are rendered as text and are shown in grid cells.
     * Does not effect row captions.
     */
    private boolean escapeHTML = true;

    /**
     * The constructor should first call super() to initialize the component and
     * then handle any initialization relevant to Vaadin.
     */
    public VAnnotationGrid() {
        super();

        table = new AnnotationGridTable();

        formatter = table.getFlexCellFormatter();

        // we are wrapping the table element
        initWidget(table);

        // This method call of the Paintable interface sets the component
        // style name in DOM tree
        setStyleName(CLASSNAME);

        highlighted = new HashMap<String, String[]>();
        position2id = HashBiMap.create();
        startTimes = new HashMap<Position, Double>();
        endTimes = new HashMap<Position, Double>();
        pdfPageNumbers = new HashMap<Position, String>();
    }

    /**
     * Called whenever an update is received from the server
     */
    @Override
    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {

        // This call should be made first.
        // It handles sizes, captions, tooltips, etc. automatically.
        if (client.updateComponent(this, uidl, true)) {
            // If client.updateComponent returns true there has been no changes and we
            // do not need to update anything.
            return;
        }

        // Save reference to server connection object to be able to send
        // user interaction later
        this.gClient = client;

        // Save the client side identifier (paintable id) for the widget
        paintableId = uidl.getId();

        try {
            if (uidl.hasAttribute("escapeHTML")) {
                this.escapeHTML = uidl.getBooleanAttribute("escapeHTML");
            }

            UIDL rows = uidl.getChildByTagName("rows");
            if (rows != null) {
                // clear all old table cells
                table.removeAllRows();
                highlighted.clear();
                position2id.clear();

                for (int i = 0; i < rows.getChildCount(); i++) {
                    UIDL row = rows.getChildUIDL(i);
                    if ("row".equals(row.getTag())) {
                        addRow(row, i);
                    }
                }
            } // end if rows not null

            // add end events if necessary to have a nicely aligned regular grid
            int maxCellCount = 0;
            for (int row = 0; row < table.getRowCount(); row++) {
                maxCellCount = Math.max(maxCellCount, getRealColumnCount(row));
            }

            for (int row = 0; row < table.getRowCount(); row++) {
                int isValue = getRealColumnCount(row);

                if (isValue < maxCellCount) {
                    int diff = maxCellCount - isValue;
                    table.setHTML(row, table.getCellCount(row) + diff - 1, "");
                }
            }

        } catch (Exception ex) {
            VConsole.log(ex);
        }
    }

    private int getRealColumnCount(int row) {
        int result = 0;
        for (int i = 0; i < table.getCellCount(row); i++) {
            result += formatter.getColSpan(row, i);
        }
        return result;
    }

    private void addRow(UIDL row, int rowNumber) {

        String caption = row.getStringAttribute("caption");
        boolean showNamespace = row.getBooleanAttribute("show-namespace");
        String name;
        if (showNamespace) {
            name = caption;
        } else {
            String[] captionSplit = caption.split("::");
            name = captionSplit[captionSplit.length - 1];
        }

        boolean showCaption = row.getBooleanAttribute("show-caption");

        int startColumn = 0;

        if (showCaption) {
            table.setHTML(rowNumber, 0, Util.escapeHTML(name));
            formatter.addStyleName(rowNumber, 0, "header");
            startColumn = 1;
        }

        int colspanOffset = 0;

        UIDL events = row.getChildByTagName("events");
        for (int j = 0; j < events.getChildCount(); j++) {
            UIDL event = events.getChildUIDL(j);
            String id = event.getStringAttribute("id");
            int left = event.getIntAttribute("left");
            int right = event.getIntAttribute("right");
            String value = event.getStringAttribute("value");
            if (escapeHTML) {
                value = Util.escapeHTML(value);
            }

            // +1 because we also have a caption column, subtract columns we
            // jumped over by using colspan
            int col = left + startColumn - colspanOffset;

            table.setHTML(rowNumber, col, value);

            if (event.hasAttribute("tooltip")) {
                Element tdElement = table.getCellFormatter().getElement(rowNumber, col);
                tdElement.setTitle(event.getStringAttribute("tooltip"));
            }

            position2id.put(new Position(rowNumber, col), id);

            int colspan = right - left + 1;
            formatter.setColSpan(rowNumber, col, colspan);
            if (colspan > 1) {
                colspanOffset += (colspan - 1);
            }

            addStyleForEvent(event, rowNumber, col);

        }
    }

    private void addStyleForEvent(UIDL event, int rowNumber, int col) {
        String id = event.getStringAttribute("id");

        // style given by the server component
        if (event.hasAttribute("style")) {
            String[] styles = event.getStringArrayAttribute("style");
            for (String s : styles) {
                formatter.addStyleName(rowNumber, col, s);
            }
        } else {
            formatter.addStyleName(rowNumber, col, "single_event");
        }

        // fill highlight map
        if (event.hasAttribute("highlight")) {
            highlighted.put(id, event.getStringArrayAttribute("highlight"));
        }

        if (event.hasAttribute("startTime")) {
            formatter.addStyleName(rowNumber, col, "speaker");
            startTimes.put(new Position(rowNumber, col), event.getDoubleAttribute("startTime"));
            if (event.hasAttribute("endTime")) {
                endTimes.put(new Position(rowNumber, col), event.getDoubleAttribute("endTime"));
            }
        }

        if (event.hasAttribute("openPDF")) {
            String number = event.getStringAttribute("openPDF");
            formatter.addStyleName(rowNumber, col, "pdf");
            pdfPageNumbers.put(new Position(rowNumber, col), number);
        }
    }

    public void onClick(int row, int col) {

        VConsole.log("clicked row " + row + " col " + col);
        VConsole.log("size of pdfPageNumbers: " + pdfPageNumbers.size());

        Position pos = new Position(row, col);
        if (startTimes.containsKey(pos)) {
            if (endTimes.containsKey(pos)) {
                gClient.updateVariable(paintableId, "play", "" + startTimes.get(pos) + "-" + endTimes.get(pos),
                        true);
            } else {
                gClient.updateVariable(paintableId, "play", "" + startTimes.get(pos), true);
            }

        }

        if (pdfPageNumbers.containsKey(pos)) {
            gClient.updateVariable(paintableId, "openPDF", pdfPageNumbers.get(pos), true);
        }
    }

    public static class Position {

        private int column, row;

        public Position(Cell cell) {
            this.column = cell.getCellIndex();
            this.row = cell.getRowIndex();
        }

        public Position(int row, int column) {
            this.column = column;
            this.row = row;
        }

        public int getColumn() {
            return column;
        }

        public void setColumn(int column) {
            this.column = column;
        }

        public int getRow() {
            return row;
        }

        public void setRow(int row) {
            this.row = row;
        }

        @Override
        public int hashCode() {
            int hash = 7;
            hash = 71 * hash + this.column;
            hash = 71 * hash + this.row;
            return hash;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final Position other = (Position) obj;
            if (this.column != other.column) {
                return false;
            }
            if (this.row != other.row) {
                return false;
            }
            return true;
        }
    }

    public class AnnotationGridTable extends FlexTable {

        public AnnotationGridTable() {
            sinkEvents(Event.ONMOUSEOVER | Event.ONMOUSEOUT | Event.ONCLICK);
        }

        @Override
        public void onBrowserEvent(Event event) {
            Element td = getEventTargetCell(event);
            if (td == null) {
                return;
            }

            int row = TableRowElement.as(td.getParentElement()).getSectionRowIndex();
            int column = TableCellElement.as(td).getCellIndex();

            String id = position2id.get(new Position(row, column));
            String[] targetIDs = highlighted.get(id);

            // only do something if the cell is highlighting other cells
            if (targetIDs != null && targetIDs.length > 0) {
                switch (event.getTypeInt()) {
                case Event.ONMOUSEOVER:
                    td.addClassName("highlight-source");

                    for (String targetID : targetIDs) {
                        Position pos = position2id.inverse().get(targetID);
                        if (pos != null) {
                            formatter.addStyleName(pos.getRow(), pos.getColumn(), "highlight-target");
                        }
                    }

                    break;
                case Event.ONMOUSEOUT:
                    td.removeClassName("highlight-source");
                    for (String targetID : targetIDs) {
                        Position pos = position2id.inverse().get(targetID);
                        if (pos != null) {
                            formatter.removeStyleName(pos.getRow(), pos.getColumn(), "highlight-target");
                        }
                    }
                    break;
                case Event.ONCLICK:
                    onClick(row, column);
                    break;
                default:
                    // do nothing
                    break;
                }
            }
        }
    }
}