/*
* Copyright 2009 Fred Sauer
*
* 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 com.allen_sauer.gwt.dnd.client.drop;
import com.google.gwt.user.client.ui.InsertPanel;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.Widget;
import com.allen_sauer.gwt.dnd.client.DragContext;
import com.allen_sauer.gwt.dnd.client.VetoDragException;
import com.allen_sauer.gwt.dnd.client.util.CoordinateLocation;
import com.allen_sauer.gwt.dnd.client.util.DOMUtil;
import com.allen_sauer.gwt.dnd.client.util.LocationWidgetComparator;
/**
* A {@link DropController} for {@link InsertPanel} drop targets.
*/
public abstract class AbstractInsertPanelDropController extends AbstractPositioningDropController {
/**
* Our drop target.
*/
protected final InsertPanel dropTarget;
private int dropIndex;
private Widget positioner = null;
/**
* @see FlowPanelDropController#FlowPanelDropController(com.google.gwt.user.client.ui.FlowPanel)
*
* @param dropTarget the insert panel drop target
*/
public AbstractInsertPanelDropController(InsertPanel dropTarget) {
super((Panel) dropTarget);
this.dropTarget = dropTarget;
}
@Override
public void onDrop(DragContext context) {
assert dropIndex != -1 : "Should not happen after onPreviewDrop did not veto";
for (Widget widget : context.selectedWidgets) {
dropTarget.insert(widget, dropIndex);
// Works with and without drag proxy
dropIndex = dropTarget.getWidgetIndex(widget) + 1;
}
super.onDrop(context);
}
@Override
public void onEnter(DragContext context) {
super.onEnter(context);
positioner = newPositioner(context);
int targetIndex = DOMUtil.findIntersect(dropTarget, new CoordinateLocation(context.mouseX,
context.mouseY), getLocationWidgetComparator());
dropTarget.insert(positioner, targetIndex);
}
@Override
public void onLeave(DragContext context) {
positioner.removeFromParent();
positioner = null;
super.onLeave(context);
}
@Override
public void onMove(DragContext context) {
super.onMove(context);
int targetIndex = DOMUtil.findIntersect(dropTarget, new CoordinateLocation(context.mouseX,
context.mouseY), getLocationWidgetComparator());
// check that positioner not already in the correct location
int positionerIndex = dropTarget.getWidgetIndex(positioner);
if (positionerIndex != targetIndex && (positionerIndex != targetIndex - 1 || targetIndex == 0)) {
if (positionerIndex == 0 && dropTarget.getWidgetCount() == 1) {
// do nothing, the positioner is the only widget
} else if (targetIndex == -1) {
// outside drop target, so remove positioner to indicate a drop will not happen
positioner.removeFromParent();
} else {
dropTarget.insert(positioner, targetIndex);
}
}
}
@Override
public void onPreviewDrop(DragContext context) throws VetoDragException {
dropIndex = dropTarget.getWidgetIndex(positioner);
if (dropIndex == -1) {
throw new VetoDragException();
}
super.onPreviewDrop(context);
}
/**
* Required implementation method which provides the desired comparator strategy.
* @return the comparator strategy to be used
*/
protected abstract LocationWidgetComparator getLocationWidgetComparator();
/**
* Called by {@link AbstractInsertPanelDropController#onEnter(DragContext)} to create a new
* positioner widget for this {@link InsertPanel} drop target. Override this method to customize
* the look and feel of
* your positioner. The positioner widget may not have any CSS borders or margins, although there
* are no such restrictions on the children of the positioner widget. If borders and/or margins
* are desired, wrap that widget in a {@link com.google.gwt.user.client.ui.SimplePanel} with a
* <code>0px</code> border and margin.
*
* @param context The current drag context.
* @return a new positioner widget
*/
protected abstract Widget newPositioner(DragContext context);
}