All Downloads are FREE. Search and download functionalities are using the official Maven repository.

annis.gui.widgets.gwt.client.ui.VAnnotationGrid Maven / Gradle / Ivy

There is a newer version: 4.0.0-beta.4
Show newest version
/*
 * 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 position2id;

  private Map highlighted;

  private Map startTimes;

  private Map endTimes;

  // build maps row and col to a pdf page number
  private Map 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();
    position2id = HashBiMap.create();
    startTimes = new HashMap();
    endTimes = new HashMap();
    pdfPageNumbers = new HashMap();
  }

  /**
   * 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;
        }
      }
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy