PDA

View Full Version : Specified TreePanel DropTarget



f.sauter
6 Jan 2010, 4:31 AM
I had mostly the same problem like Serge Adda (http://www.extjs.com/forum/showthread.php?t=82158) (http://www.extjs.com/forum/showthread.php?t=82158). We want to drag-and-drop some elements from tree T1 into tree T2 under certain allowed elements (ie "branch under tree", and "apple under branch", not possible: "apple under tree").

So I wrote my own class (see below). I would welcome improvement suggestions!



package com.mypackage.public.utility

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import com.extjs.gxt.ui.client.data.BeanModel;
import com.extjs.gxt.ui.client.data.ModelData;
import com.extjs.gxt.ui.client.event.DNDEvent;
import com.extjs.gxt.ui.client.widget.treepanel.TreePanel;
import com.google.gwt.core.client.GWT;

/**
* An extension for <code>TreePanelDropTarget</code> to handle
* drop restrictions and some other stuff.
*
* <p>Code snippet:</p>
* <pre>
* TreePanelDropTargetExtended dropTarget = new TreePanelDropTargetExtended(treePanel) {
* onShowFeedback(ModelData targetModel, ModelData sourceModel, DNDEvent event) {
* if(targetModel.get("myspecial").equals(sourceModel.get("myspecial"))) {
* event.getStatus().setStatus(false);
* }
* }
* };
*
* dropTarget.setAutoExpand(true);
* dropTarget.setFeedback(Feedback.BOTH);
* dropTarget.setAllowDropOnNullNode(false);
* //you can only drop a branch on a tree
* dropTarget.addDropRestriction(TreeModel.class, BranchModel.class);
* //you can only drop an apple on a branch
* dropTarget.addDropRestriction(BranchModel.class, AppleModel.class);
* </pre>
*
* @see http://www.sencha.com/forum/showthread.php?89108-Specified-TreePanel-DropTarget
*/
public class TreePanelDropTarget extends com.extjs.gxt.ui.client.dnd.TreePanelDropTarget {

private Boolean allowDropOnNullNode = true;

private HashMap<Class<?>, List<Class<?>>> dropRestrictions = new HashMap<Class<?>, List<Class<?>>>();

public TreePanelDropTarget(TreePanel<?> tree) {
super(tree);
}

@Override @SuppressWarnings("unchecked") protected void showFeedback(DNDEvent event) { super.showFeedback(event); // not a null node: if (this.activeItem != null) { try { DragSource source = (DragSource) event.getSource(); List<ModelData> list = (List<ModelData>) source.getData(); for (ModelData sourceTreeModel : list) { if (this.canDropOn(sourceTreeModel) == false) { clearStyles(event); } this.onShowFeedback(this.activeItem.getModel(), sourceTreeModel, event); } } catch (Exception e){ GWT.log("Source maybe not a DragSource?!", e); } } else if (this.allowDropOnNullNode == false) { clearStyles(event); } else { //nothing - no rules } }

/**
*
* @param sourceTreeModel
* @return <code>true<code> if there are no restrictions or the source
* is dropped on a valid target otherwise <code>false</code>
*/
private boolean canDropOn(ModelData sourceTreeModel) {
Object targetObject = activeItem.getModel();
Object sourceObject = sourceTreeModel;
if (this.dropRestrictions.isEmpty() == true) {
return true;
} else {
// check for BeanModels
if (targetObject instanceof BeanModel) {
targetObject = ((BeanModel) targetObject).getBean();
}
if (sourceObject instanceof BeanModel) {
sourceObject = ((BeanModel) sourceObject).getBean();
}
// check restriction
if (
this.dropRestrictions.get(targetObject.getClass()) != null &&
this.dropRestrictions.get(targetObject.getClass()).contains(sourceObject.getClass())
) {
return true;
}
}
return false;
}

/**
* This function need not be invoked. Is called for each
* selected model once when models are dragged over a target.
*
* Should only override this function.
*
* @param targetModel
* @param sourceModel
* @param event
*/
protected void onShowFeedback(ModelData targetModel, ModelData sourceModel, DNDEvent event) {

}

/**
* Adds a new drop restriction according 2 classes.
*
* @param targetClass
* @param sourceClass
*/
public void addDropRestriction(Class<?> targetClass, Class<?> sourceClass){
List<Class<?>> allowedSourceClasses = this.dropRestrictions.get(targetClass);
if (allowedSourceClasses == null) {
allowedSourceClasses = new ArrayList<Class<?>>();
}
allowedSourceClasses.add(sourceClass);
this.dropRestrictions.put(targetClass, allowedSourceClasses);
}

/**
* Returns whether drops are allowed on null nodes of the tree panel.
*
* @return true of drops on null nodes are allowed
*/
public boolean isAllowDropOnNullNode() {
return allowDropOnNullNode;
}

/**
* True to allow drops on a null node (defaults to true).
*
* @param allowDropOnNullNode false to enable drops on a null node
*/
public void setAllowDropOnNullNode(Boolean allowDropOnNullNode) {
this.allowDropOnNullNode = allowDropOnNullNode;
}
}

Arno.Nyhm
29 Jan 2010, 1:43 AM
because a haspmap can only have unique keys you can rewrite the method canDropOn in this way:



private boolean canDropOn(ModelData sourceTreeModel) {
ModelData targetTreeModel = activeItem.getModel();
String targetClass = targetTreeModel.getClass().getName();
String sourceClass = sourceTreeModel.getClass().getName();
return (this.dropRestrictions.isEmpty() || sourceClass.equals(dropRestrictions.get(targetClass)));
}



PS:
i think the intension was to have more then one restriction per class. then an other collection would be better for this case?

f.sauter
9 Mar 2010, 1:19 PM
Yes u are right, thanks for the hint! it should be possible to have more then one class as a key. will improve this (sometime in the near future..)

Update 18.03.2010:
added restriction class.