package org.ovirt.engine.ui.common.widget.table; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.EventTarget; import com.google.gwt.dom.client.InputElement; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.DomEvent; import com.google.gwt.event.dom.client.DragEndEvent; import com.google.gwt.event.dom.client.DragEnterEvent; import com.google.gwt.event.dom.client.DragLeaveEvent; import com.google.gwt.event.dom.client.DragOverEvent; import com.google.gwt.event.dom.client.DragStartEvent; import com.google.gwt.event.dom.client.DropEvent; import com.google.gwt.event.dom.client.MouseDownEvent; import com.google.gwt.event.dom.client.MouseUpEvent; import com.google.gwt.resources.client.CssResource; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.uibinder.client.UiHandler; import com.google.gwt.user.cellview.client.Column; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.FocusPanel; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.SimpleCheckBox; import com.google.gwt.user.client.ui.Widget; /** * Item rendered within the {@link ColumnContextMenu}. * * @param <T> * Table row data type. */ public class ColumnContextMenuItem<T> extends Composite { interface WidgetUiBinder extends UiBinder<Widget, ColumnContextMenuItem> { WidgetUiBinder uiBinder = GWT.create(WidgetUiBinder.class); } interface Style extends CssResource { String highlightable(); String dragSource(); String validDropTarget(); } @UiField Style style; @UiField FocusPanel container; @UiField Label title; @UiField SimpleCheckBox checkBox; private final ColumnController<T> controller; private final Column<T, ?> column; public ColumnContextMenuItem(ColumnController<T> controller, Column<T, ?> column) { this.controller = controller; this.column = column; initWidget(WidgetUiBinder.uiBinder.createAndBindUi(this)); getElement().setDraggable(Element.DRAGGABLE_TRUE); update(); } public void update() { title.setText(controller.getColumnContextMenuTitle(column)); checkBox.setValue(controller.isColumnVisible(column)); container.setStyleName(style.highlightable(), true); container.setStyleName(style.dragSource(), false); container.setStyleName(style.validDropTarget(), false); } boolean eventTargetIsCheckBox(DomEvent<?> event) { EventTarget eventTarget = event.getNativeEvent().getEventTarget(); return InputElement.is(eventTarget) && "checkbox".equals(InputElement.as(eventTarget).getAttribute("type")); //$NON-NLS-1$ //$NON-NLS-2$ } @UiHandler("checkBox") void onClick(ClickEvent event) { boolean visible = checkBox.getValue(); controller.setColumnVisible(column, visible); } @UiHandler("container") void onMouseDown(MouseDownEvent event) { if (!eventTargetIsCheckBox(event)) { container.setStyleName(style.highlightable(), false); container.setStyleName(style.dragSource(), true); } } @UiHandler("container") void onMouseUp(MouseUpEvent event) { if (!eventTargetIsCheckBox(event)) { container.setStyleName(style.highlightable(), true); container.setStyleName(style.dragSource(), false); } } @UiHandler("container") void onDragStart(DragStartEvent event) { int itemColumnIndex = controller.getColumnIndex(column); // While the HTML5 DnD spec allows setting "drag data" within // "dragstart" event, it prevents access to that data in every // other event, except for the "drop" event. This way, it's not // possible to check "drag data" _during_ a drag operation, e.g. // in order to visually highlight a possible drop target. controller.setDragIndex(itemColumnIndex); // Without this, the DnD behavior doesn't seem to be triggered. event.getDataTransfer().setData("text", String.valueOf(itemColumnIndex)); //$NON-NLS-1$ // Define a custom drag image. event.getDataTransfer().setDragImage(getElement(), event.getNativeEvent().getClientX() - getAbsoluteLeft(), event.getNativeEvent().getClientY() - getAbsoluteTop()); } @UiHandler("container") void onDragEnter(DragEnterEvent event) { // This is actually needed for the "drop" event to fire at all. event.preventDefault(); container.setStyleName(style.highlightable(), false); } @UiHandler("container") void onDragOver(DragOverEvent event) { // This is actually needed for the "drop" event to fire at all. event.preventDefault(); int draggedColumnIndex = controller.getDragIndex(); int itemColumnIndex = controller.getColumnIndex(column); // Highlight the drop target. container.setStyleName(style.validDropTarget(), draggedColumnIndex != itemColumnIndex); } @UiHandler("container") void onDragLeave(DragLeaveEvent event) { container.setStyleName(style.validDropTarget(), false); } @UiHandler("container") void onDragEnd(DragEndEvent event) { controller.updateColumnContextMenu(); } @UiHandler("container") void onDrop(DropEvent event) { // Make sure to prevent the (useless) default browser action, // e.g. "open as link" for the dropped element. event.preventDefault(); int draggedColumnIndex = controller.getDragIndex(); int itemColumnIndex = controller.getColumnIndex(column); // Swap the columns. if (draggedColumnIndex != itemColumnIndex) { controller.swapColumns(controller.getColumn(draggedColumnIndex), column); } // Reset the drag index. controller.setDragIndex(ColumnController.NO_DRAG); } }