/* * Copyright 2010 The gwtquery plugins team. * * 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 gwtquery.plugins.droppable.client.gwt; import static com.google.gwt.query.client.GQuery.$; import com.google.gwt.cell.client.Cell; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.Element; import com.google.gwt.event.shared.EventBus; import com.google.gwt.event.shared.EventHandler; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.event.shared.SimpleEventBus; import com.google.gwt.event.shared.GwtEvent.Type; import com.google.gwt.query.client.Function; import com.google.gwt.safehtml.shared.SafeHtml; import com.google.gwt.user.cellview.client.CellList; import com.google.gwt.user.cellview.client.CellList.Resources; import com.google.gwt.view.client.ProvidesKey; import gwtquery.plugins.draggable.client.DraggableOptions; import gwtquery.plugins.draggable.client.events.BeforeDragStartEvent; import gwtquery.plugins.draggable.client.events.DragEvent; import gwtquery.plugins.draggable.client.events.DragStartEvent; import gwtquery.plugins.draggable.client.events.DragStopEvent; import gwtquery.plugins.draggable.client.events.BeforeDragStartEvent.BeforeDragStartEventHandler; import gwtquery.plugins.draggable.client.events.DragEvent.DragEventHandler; import gwtquery.plugins.draggable.client.events.DragStartEvent.DragStartEventHandler; import gwtquery.plugins.draggable.client.events.DragStopEvent.DragStopEventHandler; import gwtquery.plugins.droppable.client.DroppableOptions; import gwtquery.plugins.droppable.client.events.ActivateDroppableEvent; import gwtquery.plugins.droppable.client.events.DeactivateDroppableEvent; import gwtquery.plugins.droppable.client.events.DropEvent; import gwtquery.plugins.droppable.client.events.OutDroppableEvent; import gwtquery.plugins.droppable.client.events.OverDroppableEvent; import gwtquery.plugins.droppable.client.events.ActivateDroppableEvent.ActivateDroppableEventHandler; import gwtquery.plugins.droppable.client.events.DeactivateDroppableEvent.DeactivateDroppableEventHandler; import gwtquery.plugins.droppable.client.events.DropEvent.DropEventHandler; import gwtquery.plugins.droppable.client.events.OutDroppableEvent.OutDroppableEventHandler; import gwtquery.plugins.droppable.client.events.OverDroppableEvent.OverDroppableEventHandler; import gwtquery.plugins.droppable.client.gwt.CellDragAndDropBehaviour.CellDragOnlyBehaviour; import gwtquery.plugins.droppable.client.gwt.CellDragAndDropBehaviour.CellDropOnlyBehaviour; import java.util.List; /** * {@link com.google.gwt.user.cellview.client.CellList} implementation allowing dragging or dropping of the cells * * @param <T> the data type of list items * @author Julien Dramaix (julien.dramaix@gmail.com) */ public class DragAndDropCellList<T> extends CellList<T> { private static Resources DEFAULT_RESOURCES = GWT.create(Resources.class); /** * {@link CellDragAndDropBehaviour} used to determine if cells have to be * droppable and/or draggable */ private CellDragAndDropBehaviour<T> cellDragAndDropBehaviour; /** * {@link EventBus} where drag and drop events will be fired */ private EventBus dragAndDropHandlerManager; /** * The options used for draggable cells. */ private DraggableOptions draggableOptions; /** * The options used for droppable cells. */ private DroppableOptions droppableOptions; /** * Construct a new {@link DragAndDropCellList}. * * @param cell the cell used to render each item */ public DragAndDropCellList(final Cell<T> cell) { this(cell, DEFAULT_RESOURCES, null, null); } /** * Construct a new {@link DragAndDropCellList}. * * @param cell the cell used to render each item * @param cellDragAndDropBehaviour an instance of {@link CellDragAndDropBehaviour} or null if you * want that all cell are draggable and droppable. */ public DragAndDropCellList(final Cell<T> cell, CellDragAndDropBehaviour<T> cellDragAndDropBehaviour) { this(cell, DEFAULT_RESOURCES, null, cellDragAndDropBehaviour); } /** * Construct a new {@link DragAndDropCellList} with the specified * {@link ProvidesKey key provider}. * * @param cell the cell used to render each item * @param keyProvider an instance of ProvidesKey<T>, or null if the record object should * act as its own key */ public DragAndDropCellList(final Cell<T> cell, ProvidesKey<T> keyProvider) { this(cell, DEFAULT_RESOURCES, keyProvider, null); } /** * Construct a new {@link DragAndDropCellList} with the specified * {@link ProvidesKey key provider}. * * @param cell the cell used to render each item * @param keyProvider an instance of ProvidesKey<T>, or null if the record object should * act as its own key * @param cellDragAndDropBehaviour an instance of {@link CellDragAndDropBehaviour} or null if you * want that all cell are draggable and droppable. */ public DragAndDropCellList(final Cell<T> cell, ProvidesKey<T> keyProvider, CellDragAndDropBehaviour<T> cellDragAndDropBehaviour) { this(cell, DEFAULT_RESOURCES, keyProvider, cellDragAndDropBehaviour); } /** * Construct a new {@link DragAndDropCellList} with the specified * {@link Resources}. * * @param cell the cell used to render each item * @param resources the resources used for this widget */ public DragAndDropCellList(final Cell<T> cell, Resources resources) { this(cell, resources, null, null); } /** * Construct a new {@link DragAndDropCellList} with the specified * {@link Resources}. * * @param cell the cell used to render each item * @param resources the resources used for this widget * @param cellDragAndDropBehaviour an instance of {@link CellDragAndDropBehaviour} or null if you * want that all cell are draggable and droppable. */ public DragAndDropCellList(final Cell<T> cell, Resources resources, CellDragAndDropBehaviour<T> cellDragAndDropBehaviour) { this(cell, resources, null, cellDragAndDropBehaviour); } /** * Construct a new {@link DragAndDropCellList} with the specified * {@link Resources} and {@link ProvidesKey key provider}. * * @param cell the cell used to render each item * @param resources the resources used for this widget * @param keyProvider an instance of ProvidesKey<T>, or null if the record object should * act as its own key */ public DragAndDropCellList(final Cell<T> cell, Resources resources, ProvidesKey<T> keyProvider) { this(cell, resources, keyProvider, null); } /** * Construct a new {@link DragAndDropCellList} with the specified * {@link Resources} and {@link ProvidesKey key provider}. * * @param cell the cell used to render each item * @param resources the resources used for this widget * @param keyProvider an instance of ProvidesKey<T>, or null if the record object should * act as its own key * @param cellDragAndDropBehaviour an instance of {@link CellDragAndDropBehaviour} or null if you * want that all cell are draggable and droppable. */ public DragAndDropCellList(final Cell<T> cell, Resources resources, ProvidesKey<T> keyProvider, CellDragAndDropBehaviour<T> cellDragAndDropBehaviour) { super(cell, resources, keyProvider); this.cellDragAndDropBehaviour = cellDragAndDropBehaviour; this.draggableOptions = new DraggableOptions(); this.droppableOptions = new DroppableOptions(); } /** * Add a handler object that will manage the {@link BeforeDragStartEvent} * event. this kind of event is fired before the initialization of the drag * operation. */ public HandlerRegistration addBeforeDragHandler(BeforeDragStartEventHandler handler) { return addDragAndDropHandler(handler, BeforeDragStartEvent.TYPE); } /** * Add a handler object that will manage the {@link DragEvent} event. this * kind of event is fired during the move of the widget. */ public HandlerRegistration addDragHandler(DragEventHandler handler) { return addDragAndDropHandler(handler, DragEvent.TYPE); } /** * Add a handler object that will manage the {@link DragStartEvent} event. * This kind of event is fired when the drag operation starts. */ public HandlerRegistration addDragStartHandler(DragStartEventHandler handler) { return addDragAndDropHandler(handler, DragStartEvent.TYPE); } /** * Add a handler object that will manage the {@link DragStopEvent} event. This * kind of event is fired when the drag operation stops. */ public HandlerRegistration addDragStopHandler(DragStopEventHandler handler) { return addDragAndDropHandler(handler, DragStopEvent.TYPE); } /** * Add a handler object that will manage the {@link ActivateDroppableEvent} * event. This kind of event is fired each time a droppable cell is activated. */ public HandlerRegistration addActivateDroppableHandler(ActivateDroppableEventHandler handler) { return addDragAndDropHandler(handler, ActivateDroppableEvent.TYPE); } /** * Add a handler object that will manage the {@link DeactivateDroppableEvent} * event. This kind of event is fired each time a droppable cell is * deactivated. */ public HandlerRegistration addDeactivateDroppableHandler(DeactivateDroppableEventHandler handler) { return addDragAndDropHandler(handler, DeactivateDroppableEvent.TYPE); } /** * Add a handler object that will manage the {@link DropEvent} event. This * kind of event is fired when an acceptable draggable is drop on a droppable * cell. */ public HandlerRegistration addDropHandler(DropEventHandler handler) { return addDragAndDropHandler(handler, DropEvent.TYPE); } /** * Add a handler object that will manage the {@link OutDroppableEvent} event. * This kind of event is fired when an acceptable draggable is being dragged * out of a droppable cell. */ public HandlerRegistration addOutDroppableHandler(OutDroppableEventHandler handler) { return addDragAndDropHandler(handler, OutDroppableEvent.TYPE); } /** * Add a handler object that will manage the {@link OverDroppableEvent} event. * This kind of event is fired when an acceptable draggable is being dragged * over a droppable cell. */ public HandlerRegistration addOverDroppableHandler(OverDroppableEventHandler handler) { return addDragAndDropHandler(handler, OverDroppableEvent.TYPE); } /** * @return the {@link CellDragAndDropBehaviour} */ public CellDragAndDropBehaviour<T> getCellDragAndDropBehaviour() { return cellDragAndDropBehaviour; } /** * @return the {@link DraggableOptions} used to make cells draggable */ public DraggableOptions getDraggableOptions() { return draggableOptions; } /** * @return the {@link DroppableOptions} used to make cells droppable */ public DroppableOptions getDroppableOptions() { return droppableOptions; } /** * Set the {@link CellDragAndDropBehaviour}. If null is given, all cells will * be draggable and droppable * * @param cellDragAndDropBehaviour */ public void setCellDragAndDropBehaviour(CellDragAndDropBehaviour<T> cellDragAndDropBehaviour) { this.cellDragAndDropBehaviour = cellDragAndDropBehaviour; } /** * By invoking this method, the cells will be draggable only */ public void setCellDraggableOnly() { cellDragAndDropBehaviour = new CellDragOnlyBehaviour<T>(); } /** * By invoking this method, the cells will be droppable only */ public void setCellDroppableOnly() { cellDragAndDropBehaviour = new CellDropOnlyBehaviour<T>(); } /** * Set the {@link DraggableOptions} used to make cells draggable */ public void setDraggableOptions(DraggableOptions draggableOptions) { this.draggableOptions = draggableOptions; } /** * Set the {@link DroppableOptions} used to make cells droppable */ public void setDroppableOptions(DroppableOptions droppableOptions) { this.droppableOptions = droppableOptions; } protected void addDragAndDropBehaviour(List<T> values, int start) { int end = start + values.size(); for (int rowIndex = start; rowIndex < end; rowIndex++) { T value = values.get(rowIndex - start); Element newCell = getRowElement(rowIndex); DragAndDropCellWidgetUtils.get().maybeMakeDraggableOrDroppable(newCell, value, cellDragAndDropBehaviour, draggableOptions, droppableOptions, ensureDrangAndDropHandlers()); } } protected final <H extends EventHandler> HandlerRegistration addDragAndDropHandler(H handler, Type<H> type) { return ensureDrangAndDropHandlers().addHandler(type, handler); } protected void cleanAllCells() { $(getChildContainer()).children().each(new Function() { @Override public void f(Element div) { DragAndDropCellWidgetUtils.get().cleanCell(div); } }); } protected EventBus ensureDrangAndDropHandlers() { return dragAndDropHandlerManager == null ? dragAndDropHandlerManager = new SimpleEventBus() : dragAndDropHandlerManager; } @Override protected void onUnload() { cleanAllCells(); super.onUnload(); } @Override protected void replaceAllChildren(List<T> values, SafeHtml html) { // first clean old cell before remove it cleanAllCells(); // lets the super class replace all child super.replaceAllChildren(values, html); // make the new cell draggable or droppable addDragAndDropBehaviour(values, 0); } @Override protected void replaceChildren(List<T> values, int start, SafeHtml html) { // clean cell has being replaced int end = start + values.size(); for (int rowIndex = start; rowIndex < end; rowIndex++) { Element oldCell = getRowElement(rowIndex); DragAndDropCellWidgetUtils.get().cleanCell(oldCell); } // lets the super class replace all child super.replaceChildren(values, start, html); // make the new cell draggable or droppable addDragAndDropBehaviour(values, start); } void setDragAndDropHandlerManager(EventBus eventBus) { this.dragAndDropHandlerManager = eventBus; } }