com.vaadin.v7.client.renderers.ClickableRenderer Maven / Gradle / Ivy
Show all versions of vaadin-compatibility-client Show documentation
/*
* Copyright (C) 2000-2023 Vaadin Ltd
*
* This program is available under Vaadin Commercial License and Service Terms.
*
* See for the full
* license.
*/
package com.vaadin.v7.client.renderers;
import com.google.gwt.dom.client.BrowserEvents;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.EventTarget;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.DomEvent;
import com.google.gwt.event.dom.client.MouseEvent;
import com.google.gwt.event.shared.EventHandler;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Widget;
import com.google.web.bindery.event.shared.HandlerRegistration;
import com.vaadin.client.WidgetUtil;
import com.vaadin.v7.client.widget.escalator.Cell;
import com.vaadin.v7.client.widget.escalator.RowContainer;
import com.vaadin.v7.client.widget.grid.CellReference;
import com.vaadin.v7.client.widget.grid.EventCellReference;
import com.vaadin.v7.client.widgets.Escalator;
import com.vaadin.v7.client.widgets.Grid;
import com.vaadin.v7.shared.ui.grid.GridConstants.Section;
/**
* An abstract superclass for renderers that render clickable widgets. Click
* handlers can be added to a renderer to listen to click events emitted by all
* widgets rendered by the renderer.
*
* @param
* the presentation (column) type
* @param
* the widget type
*
* @since 7.4
* @author Vaadin Ltd
*/
public abstract class ClickableRenderer
extends WidgetRenderer implements ClickHandler {
/**
* A handler for {@link RendererClickEvent renderer click events}.
*
* @param
* the row type of the containing Grid
*
* @see ButtonRenderer#addClickHandler(RendererClickHandler)
*/
public interface RendererClickHandler extends EventHandler {
/**
* Called when a rendered button is clicked.
*
* @param event
* the event representing the click
*/
void onClick(RendererClickEvent event);
}
/**
* An event fired when a widget rendered by a ClickableWidgetRenderer
* subclass is clicked.
*
* @param
* the row type of the containing Grid
*/
@SuppressWarnings("rawtypes")
public static class RendererClickEvent
extends MouseEvent {
@SuppressWarnings("unchecked")
static final Type TYPE = new Type(
BrowserEvents.CLICK, new RendererClickEvent());
private CellReference cell;
private R row;
private RendererClickEvent() {
}
/**
* Returns the cell of the clicked button.
*
* @return the cell
*/
public CellReference getCell() {
return cell;
}
/**
* Returns the data object corresponding to the row of the clicked
* button.
*
* @return the row data object
*/
public R getRow() {
return row;
}
@Override
public Type getAssociatedType() {
return TYPE;
}
@Override
@SuppressWarnings("unchecked")
protected void dispatch(RendererClickHandler handler) {
EventTarget target = getNativeEvent().getEventTarget();
if (!Element.is(target)) {
return;
}
Element e = Element.as(target);
Grid grid = (Grid) findClosestParentGrid(e);
cell = findCell(grid, e);
row = cell.getRow();
handler.onClick(this);
}
/**
* Returns the cell the given element belongs to.
*
* @param grid
* the grid instance that is queried
* @param e
* a cell element or the descendant of one
* @return the cell or null if the element is not a grid cell or a
* descendant of one
*/
private static CellReference findCell(Grid grid, Element e) {
RowContainer container = getEscalator(grid).findRowContainer(e);
if (container == null) {
return null;
}
Cell cell = container.getCell(e);
EventCellReference cellReference = new EventCellReference(
grid);
// FIXME: Section is currently always body. Might be useful for the
// future to have an actual check.
cellReference.set(cell, Section.BODY);
return cellReference;
}
private static native Escalator getEscalator(Grid> grid)
/*-{
return [email protected]::escalator;
}-*/;
/**
* Returns the Grid instance containing the given element, if any.
*
* Note: This method may not work reliably if the grid
* in question is wrapped in a {@link Composite} unless the
* element is inside another widget that is a child of the wrapped grid;
* please refer to the note in
* {@link WidgetUtil#findWidget(Element, Class) Util.findWidget} for
* details.
*
* @param e
* the element whose parent grid to find
* @return the parent grid or null if none found.
*/
private static Grid> findClosestParentGrid(Element e) {
Widget w = WidgetUtil.findWidget(e, null);
while (w != null && !(w instanceof Grid)) {
w = w.getParent();
}
return (Grid>) w;
}
}
private HandlerManager handlerManager;
/**
* {@inheritDoc}
*
* Implementation note: It is the implementing method's
* responsibility to add {@code this} as a click handler of the returned
* widget, or a widget nested therein, in order to make click events
* propagate properly to handlers registered via
* {@link #addClickHandler(RendererClickHandler) addClickHandler}.
*/
@Override
public abstract W createWidget();
/**
* Adds a click handler to this button renderer. The handler is invoked
* every time one of the widgets rendered by this renderer is clicked.
*
* Note that the row type of the click handler must match the row type of
* the containing Grid.
*
* @param handler
* the click handler to be added
*/
public HandlerRegistration addClickHandler(
RendererClickHandler> handler) {
if (handlerManager == null) {
handlerManager = new HandlerManager(this);
}
return handlerManager.addHandler(RendererClickEvent.TYPE, handler);
}
@Override
public void onClick(ClickEvent event) {
/*
* The handler manager is lazily instantiated so it's null iff
* addClickHandler is never called.
*/
if (handlerManager != null) {
DomEvent.fireNativeEvent(event.getNativeEvent(), handlerManager);
}
}
}