Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    Drag/drop bwteen TreeGrid

    Hi,
    I am facing a tough situation.
    I have two trees: one source tree and one destination. Both tree are backed up by GWT-based DataSource (see the sticky thread). If I dragged one node from source tree and drop it to destination tree, only a "Update" operation is invoked in the source tree. No any operation is invoked in the destination tree. I have no plugin point to perform the server operation.
    Are anyone aware of this?
    Any suggestion?

    thanks

    #2
    Hi Jason,

    Does the destination tree have a DataSource? What dragDataAction is configured for the source tree? Is there a foreignKey declaration between the two DataSources? Code would help.

    Be sure to look at both this blog post to understand some of the automatic drag and drop behaviors that may be kicking in.

    Comment


      #3
      DataSources for source tree and destination tree are unrelated.
      I produced a simple exmaple illustrates the issue
      Code:
      
      import com.google.gwt.core.client.EntryPoint;
      import com.google.gwt.core.client.GWT;
      import com.google.gwt.core.client.JavaScriptObject;
      import com.smartgwt.client.data.DSRequest;
      import com.smartgwt.client.data.DSResponse;
      import com.smartgwt.client.data.DataSource;
      import com.smartgwt.client.data.fields.DataSourceBooleanField;
      import com.smartgwt.client.data.fields.DataSourceIntegerField;
      import com.smartgwt.client.data.fields.DataSourceTextField;
      import com.smartgwt.client.types.DSDataFormat;
      import com.smartgwt.client.types.DSProtocol;
      import com.smartgwt.client.types.DragDataAction;
      import com.smartgwt.client.types.ListGridFieldType;
      import com.smartgwt.client.widgets.Canvas;
      import com.smartgwt.client.widgets.events.DrawEvent;
      import com.smartgwt.client.widgets.events.DrawHandler;
      import com.smartgwt.client.widgets.grid.ListGridRecord;
      import com.smartgwt.client.widgets.layout.HLayout;
      import com.smartgwt.client.widgets.tree.Tree;
      import com.smartgwt.client.widgets.tree.TreeGrid;
      import com.smartgwt.client.widgets.tree.TreeGridField;
      import com.smartgwt.client.widgets.tree.TreeNode;
      
      public class Test implements EntryPoint
      {
      
      	Canvas content=new Canvas();
      	public void onModuleLoad()
      	{
      	
      		content.setHeight(500);
      		content.setWidth(300);
      		content.setContents("");
      		
      		HLayout canvas = new HLayout();
      		canvas.setWidth100();
      		canvas.setHeight100();
      		
      		TreeGrid srcGrid=createGrid();
      		srcGrid.setCanEdit(false);
      		srcGrid.setCanDrop(false);
      		srcGrid.setCanDragRecordsOut(true);
      		srcGrid.setDragDataAction(DragDataAction.COPY);
      		TestTreeDataSource src=(TestTreeDataSource)srcGrid.getDataSource();
      		src.content=content;
      		
      		
      		TreeGrid destGrid=createGrid();
      		destGrid.setCanReorderRecords(false);
      		destGrid.setCanReparentNodes(true);
      		destGrid.setCanAcceptDroppedRecords(true);
      		destGrid.setCanDragRecordsOut(false);
      		destGrid.setCanDropOnLeaves(false);
      		 src=(TestTreeDataSource)destGrid.getDataSource();
      		 src.content=content;
      		
      		canvas.addMember(srcGrid);
      		canvas.addMember(destGrid);
      		canvas.addMember(content);
      		canvas.draw();
      
      	}
      
      
      	public TreeGrid createGrid()
      	{
      		final TreeGrid jobFiles = new TreeGrid();
      		jobFiles.setWidth(200);
      		jobFiles.setHeight100();
      
      		jobFiles.setShowRoot(false);
      		// ----------edge
      
      		jobFiles.setShowEdges(true);
      		jobFiles.setBorder("opx");
      		jobFiles.setBodyStyleName("normal");
      
      		jobFiles.setAnimateFolders(false);
      		jobFiles.setShowHeader(true);
      		
      
      		TreeGridField tf = new TreeGridField("name", "Job Files");
      		tf.setCanToggle(false);
      		tf.setCanSort(false);
      		tf.setTreeField(true);
      		tf.setType(ListGridFieldType.TEXT);
      		jobFiles.setFields(tf);
      
      		TreeNode[] nodes = new TreeNode[1];
      		TreeNode jobRootNode = new TreeNode();
      		nodes[0] = jobRootNode;
      		jobRootNode.setAttribute("id", 1);
      		jobRootNode.setAttribute("name", "root");
      		jobRootNode.setAttribute("folder", true);
      		
      		jobFiles.setInitialData(nodes);
      		jobFiles.setLoadDataOnDemand(true);
      		DataSource src=new TestTreeDataSource();
      		jobFiles.setDataSource(src);
      
      		jobFiles.addDrawHandler(new DrawHandler()
      		{
      			public void onDraw(DrawEvent event)
      			{
      				Tree tree = jobFiles.getTree();
      				tree.getRoot().setAttribute("name", "");
      				tree.setNameProperty("name");
      				tree.setPathDelim("/");
      				tree.setIsFolderProperty("folder");
      			}
      		});
      
      	
      		return jobFiles;
      	}
      	
      }
      
      //from GWT-DataSOurce thread
      abstract class GwtRpcDataSource extends DataSource
      {
      
      	public GwtRpcDataSource()
      	{
      		setDataProtocol(DSProtocol.CLIENTCUSTOM);
      		setDataFormat(DSDataFormat.CUSTOM);
      		setClientOnly(false);
      	}
      
      	@Override
      	protected Object transformRequest(DSRequest request)
      	{
      		String requestId = request.getRequestId();
      		DSResponse response = new DSResponse();
      		response.setAttribute("clientContext", request.getAttributeAsObject("clientContext"));
      		// Asume success
      		response.setStatus(0);
      		switch (request.getOperationType())
      		{
      		case FETCH:
      			executeFetch(requestId, request, response);
      			break;
      		case ADD:
      			executeAdd(requestId, request, response);
      			break;
      		case UPDATE:
      			executeUpdate(requestId, request, response);
      			break;
      		case REMOVE:
      			executeRemove(requestId, request, response);
      			break;
      		default:
      			// Operation not implemented.
      			break;
      		}
      		return request.getData();
      	}
      
      	protected abstract void executeFetch(String requestId, DSRequest request, DSResponse response);
      
      	protected abstract void executeAdd(String requestId, DSRequest request, DSResponse response);
      
      	protected abstract void executeUpdate(String requestId, DSRequest request, DSResponse response);
      
      	protected abstract void executeRemove(String requestId, DSRequest request, DSResponse response);
      
      }
      
      class TestTreeDataSource extends GwtRpcDataSource
      {
      
      	private int myid=100;
      	private int getMyId()
      	{
      		return myid++;
      	}
      	public TestTreeDataSource()
      	{
      		super();
      		DataSourceIntegerField idField = new DataSourceIntegerField("id");
      		idField.setPrimaryKey(true);
      
      		DataSourceTextField nameField = new DataSourceTextField("name");
      		DataSourceBooleanField folderField = new DataSourceBooleanField("folder");
      		setFields(idField, nameField, folderField);
      	}
      	
      	public Canvas content;
      	
      	private void updateContent(String message)
      	{
      		content.setContents(content.getContents()+this.id+":"+message+"<br/>");
      	}
      	
      
      	@Override
      	protected void executeAdd(String requestId, DSRequest request, DSResponse response)
      	{
      
      		updateContent("add is called for datasource ");
      	}
      
      	@Override
      	protected void executeFetch(final String requestId, final DSRequest request, final DSResponse response)
      	{
      		updateContent("fetch is called for datasource ");
      		//simuate the GWT request
      		JavaScriptObject obj = request.getAttributeAsJavaScriptObject("parentNode");
      		final TreeNode parentNode = new TreeNode(obj);
      		final String nodeID = parentNode.getAttribute("id");
      		TreeNode[] list = new TreeNode[5];
      		for (int i = 0; i < list.length; i++)
      		{
      			TreeNode record = new TreeNode();
      			int nodeId=getMyId();
      			record.setAttribute("name", nodeId);
      			record.setAttribute("id", nodeId);
      			if (nodeId>110)
      			{
      				record.setAttribute("folder", false);
      			} else
      			{
      				record.setAttribute("folder", true);
      			}
      			record.setParentID(nodeID);
      			list[i] = record;
      			
      		}
      		response.setData(list);
      		processResponse(requestId, response);
      	}
      
      	@Override
      	protected void executeRemove(String requestId, DSRequest request, DSResponse response)
      	{
      		updateContent("remove is called for datasource ");
      
      	}
      
      	@Override
      	protected void executeUpdate(String requestId, DSRequest request, DSResponse response)
      	{
      		updateContent("update is called for datasource ");
      		final TreeNode oldNode = new TreeNode(request.getAttributeAsJavaScriptObject("data"));
      		ListGridRecord[] list = new ListGridRecord[1];
      		list[0] = oldNode;
      		response.setData(list);
      		processResponse(requestId, response);
      	}
      
      }
      In this example, no operation is called for destination datasource.

      Comment


        #4
        What operation are you hoping will be performed on the target tree, an "add"? It doesn't look like your target tree has a foreignKey declaration and parentIdField that would allow the tree to know what to do.

        By the way, adding a Drop handler allows you to do this yourself.

        Comment


          #5
          I expect an add operation is invoked in the target tree since the node is complete new node for target tree.

          My target tree has froeign key and parentID. The executeFetch has this line of code:record.setParentID(nodeID); to establish parent/child relationship.

          The sourcetree and target tree are unrelated.

          Suppose the source tree is NFS file system and target tree is a local file system. When a node is dragged from NFS to local file, I will perform a copy operation. I will attach a addDragStartHandler to source tree. The addDragStartHandler will populate enough information to the node so that the destination datasource knows how to perform the copy action.

          Does this make sense?

          Comment


            #6
            So again, your problem is that there's no parentId field or foriegnKey declared in the datasource. Setting a parentId on a node is not the same thing, what you're effectively doing is reparenting the node with respect to the tree it was in before. Just add the declaration to the DataSource and try it.

            By the way, not sure, but this is probably reported as a problem in the Developer Console.

            Comment


              #7
              I had make this work by adding DragStartHandler and DropHandler.
              Code:
              import com.google.gwt.core.client.EntryPoint;
              import com.google.gwt.core.client.GWT;
              import com.google.gwt.core.client.JavaScriptObject;
              import com.smartgwt.client.data.DSRequest;
              import com.smartgwt.client.data.DSResponse;
              import com.smartgwt.client.data.DataSource;
              import com.smartgwt.client.data.fields.DataSourceBooleanField;
              import com.smartgwt.client.data.fields.DataSourceIntegerField;
              import com.smartgwt.client.data.fields.DataSourceTextField;
              import com.smartgwt.client.types.DSDataFormat;
              import com.smartgwt.client.types.DSProtocol;
              import com.smartgwt.client.types.DragDataAction;
              import com.smartgwt.client.types.ListGridFieldType;
              import com.smartgwt.client.util.JSOHelper;
              import com.smartgwt.client.widgets.Canvas;
              import com.smartgwt.client.widgets.events.DragStartEvent;
              import com.smartgwt.client.widgets.events.DragStartHandler;
              import com.smartgwt.client.widgets.events.DrawEvent;
              import com.smartgwt.client.widgets.events.DrawHandler;
              import com.smartgwt.client.widgets.events.DropEvent;
              import com.smartgwt.client.widgets.events.DropHandler;
              import com.smartgwt.client.widgets.grid.ListGridRecord;
              import com.smartgwt.client.widgets.layout.HLayout;
              import com.smartgwt.client.widgets.tree.Tree;
              import com.smartgwt.client.widgets.tree.TreeGrid;
              import com.smartgwt.client.widgets.tree.TreeGridField;
              import com.smartgwt.client.widgets.tree.TreeNode;
              
              public class Test implements EntryPoint
              {
              
              	Canvas content=new Canvas();
              	TreeNode srcNode;
              	public void onModuleLoad()
              	{
              	
              		content.setHeight(500);
              		content.setWidth(300);
              		content.setContents("");
              		
              		HLayout canvas = new HLayout();
              		canvas.setWidth100();
              		canvas.setHeight100();
              		
              		final TreeGrid srcGrid=createGrid();
              		srcGrid.setCanEdit(false);
              		srcGrid.setCanDrop(false);
              		srcGrid.setCanDragRecordsOut(true);
              		srcGrid.setDragDataAction(DragDataAction.COPY);
              		TestTreeDataSource src=(TestTreeDataSource)srcGrid.getDataSource();
              		src.content=content;
              		srcGrid.addDragStartHandler(new DragStartHandler(){
              
              			public void onDragStart(DragStartEvent event)
              			{
              				
              				srcNode=(TreeNode)srcGrid.getRecord(srcGrid.getEventRow());
              				updateContent("src node name is "+srcNode.getAttribute("name"));
              				
              			}});
              		
              		final TreeGrid destGrid=createGrid();
              		destGrid.setCanReorderRecords(false);
              		destGrid.setCanReparentNodes(true);
              		destGrid.setCanAcceptDroppedRecords(true);
              		destGrid.setCanDragRecordsOut(false);
              		destGrid.setCanDropOnLeaves(false);
              		destGrid.addDropHandler(new DropHandler(){
              
              			public void onDrop(DropEvent event)
              			{
              				
              				TreeNode targetNode=(TreeNode)destGrid.getRecord(destGrid.getEventRow());
              				updateContent("drop event is performed "+targetNode.getAttribute("name"));
              				updateContent("target tree id "+destGrid.getID());
              				TreeNode node=new TreeNode();
              				node.setAttribute("name", srcNode.getAttribute("name"));
              				node.setParentID(targetNode.getAttribute("id"));
              				node.setAttribute("_mysrc", "nfs");
              				destGrid.addData(node);
              				
              				
              				
              			}});
              		 src=(TestTreeDataSource)destGrid.getDataSource();
              		 src.content=content;
              		
              		canvas.addMember(srcGrid);
              		canvas.addMember(destGrid);
              		canvas.addMember(content);
              		canvas.draw();
              
              	}
              
              
              	public TreeGrid createGrid()
              	{
              		final TreeGrid jobFiles = new TreeGrid();
              		jobFiles.setWidth(200);
              		jobFiles.setHeight100();
              
              		jobFiles.setShowRoot(false);
              		// ----------edge
              
              		jobFiles.setShowEdges(true);
              		jobFiles.setBorder("opx");
              		jobFiles.setBodyStyleName("normal");
              
              		jobFiles.setAnimateFolders(false);
              		jobFiles.setShowHeader(true);
              		
              
              		TreeGridField tf = new TreeGridField("name", "Job Files");
              		tf.setCanToggle(false);
              		tf.setCanSort(false);
              		tf.setTreeField(true);
              		tf.setType(ListGridFieldType.TEXT);
              		jobFiles.setFields(tf);
              
              		TreeNode[] nodes = new TreeNode[1];
              		TreeNode jobRootNode = new TreeNode();
              		nodes[0] = jobRootNode;
              		jobRootNode.setAttribute("id", 1);
              		jobRootNode.setAttribute("name", "root");
              		jobRootNode.setAttribute("folder", true);
              		
              		jobFiles.setInitialData(nodes);
              		jobFiles.setLoadDataOnDemand(true);
              		DataSource src=new TestTreeDataSource();
              		jobFiles.setDataSource(src);
              
              		jobFiles.addDrawHandler(new DrawHandler()
              		{
              			public void onDraw(DrawEvent event)
              			{
              				Tree tree = jobFiles.getTree();
              				tree.getRoot().setAttribute("name", "");
              				tree.setNameProperty("name");
              				tree.setPathDelim("/");
              				tree.setIsFolderProperty("folder");
              			}
              		});
              
              	
              		return jobFiles;
              	}
              	protected void updateContent(String message)
              	{
              		content.setContents(content.getContents()+message+"<br/>");
              	}
              	
              	
              }
              
              //from GWT-DataSOurce thread
              abstract class GwtRpcDataSource extends DataSource
              {
              
              	public GwtRpcDataSource()
              	{
              		setDataProtocol(DSProtocol.CLIENTCUSTOM);
              		setDataFormat(DSDataFormat.CUSTOM);
              		setClientOnly(false);
              	}
              
              
              	public Canvas content;
              	
              	protected void updateContent(String message)
              	{
              		content.setContents(content.getContents()+this.id+":"+message+"<br/>");
              	}
              	
              	@Override
              	protected Object transformRequest(DSRequest request)
              	{
              		String requestId = request.getRequestId();
              		DSResponse response = new DSResponse();
              		response.setAttribute("clientContext", request.getAttributeAsObject("clientContext"));
              		// Asume success
              		response.setStatus(0);
              		updateContent(request.getOperationType().toString()+"is called on "+id);
              		switch (request.getOperationType())
              		{
              		case FETCH:
              			executeFetch(requestId, request, response);
              			break;
              		case ADD:
              			executeAdd(requestId, request, response);
              			break;
              		case UPDATE:
              			executeUpdate(requestId, request, response);
              			break;
              		case REMOVE:
              			executeRemove(requestId, request, response);
              			break;
              		default:
              			// Operation not implemented.
              			break;
              		}
              		return request.getData();
              	}
              
              	protected abstract void executeFetch(String requestId, DSRequest request, DSResponse response);
              
              	protected abstract void executeAdd(String requestId, DSRequest request, DSResponse response);
              
              	protected abstract void executeUpdate(String requestId, DSRequest request, DSResponse response);
              
              	protected abstract void executeRemove(String requestId, DSRequest request, DSResponse response);
              
              }
              
              class TestTreeDataSource extends GwtRpcDataSource
              {
              
              	private int myid=100;
              	private int getMyId()
              	{
              		return myid++;
              	}
              	public TestTreeDataSource()
              	{
              		super();
              		DataSourceIntegerField idField = new DataSourceIntegerField("id");
              		idField.setPrimaryKey(true);
              
              		DataSourceTextField nameField = new DataSourceTextField("name");
              		DataSourceBooleanField folderField = new DataSourceBooleanField("folder");
              		setFields(idField, nameField, folderField);
              	}
              	
              
              	@Override
              	protected void executeAdd(final String requestId, final DSRequest request, final DSResponse response)
              	{
              
              		updateContent("add is called for datasource ");
              		final TreeNode oldNode = new TreeNode(request.getAttributeAsJavaScriptObject("data"));
              		if (oldNode.getAttribute("_mysrc")!=null)
              		{
              			//from expected source tree.
              			oldNode.setAttribute("id", getMyId());
              		}
              		
              		ListGridRecord[] list = new ListGridRecord[1];
              		list[0] = oldNode;
              		response.setData(list);
              		processResponse(requestId, response);
              	}
              
              	@Override
              	protected void executeFetch(final String requestId, final DSRequest request, final DSResponse response)
              	{
              		updateContent("fetch is called for datasource ");
              		//simuate the GWT request
              		JavaScriptObject obj = request.getAttributeAsJavaScriptObject("parentNode");
              		final TreeNode parentNode = new TreeNode(obj);
              		final String nodeID = parentNode.getAttribute("id");
              		TreeNode[] list = new TreeNode[5];
              		for (int i = 0; i < list.length; i++)
              		{
              			TreeNode record = new TreeNode();
              			int nodeId=getMyId();
              			record.setAttribute("name", nodeId);
              			record.setAttribute("id", nodeId);
              			if (nodeId>110)
              			{
              				record.setAttribute("folder", false);
              			} else
              			{
              				record.setAttribute("folder", true);
              			}
              			record.setParentID(nodeID);
              			list[i] = record;
              			
              		}
              		response.setData(list);
              		processResponse(requestId, response);
              	}
              
              	@Override
              	protected void executeRemove(String requestId, DSRequest request, DSResponse response)
              	{
              		updateContent("remove is called for datasource ");
              
              	}
              
              	@Override
              	protected void executeUpdate(String requestId, DSRequest request, DSResponse response)
              	{
              		updateContent("update is called for datasource ");
              		final TreeNode oldNode = new TreeNode(request.getAttributeAsJavaScriptObject("data"));
              		ListGridRecord[] list = new ListGridRecord[1];
              		list[0] = oldNode;
              		response.setData(list);
              		processResponse(requestId, response);
              	}
              
              }

              Comment


                #8
                Originally posted by Isomorphic
                So again, your problem is that there's no parentId field or foriegnKey declared in the datasource. Setting a parentId on a node is not the same thing, what you're effectively doing is reparenting the node with respect to the tree it was in before. Just add the declaration to the DataSource and try it.

                By the way, not sure, but this is probably reported as a problem in the Developer Console.
                have a parentId field does not work either. In fact, my data(folder/files) really does not have a unique ID. In my implementation, ID is generated just to satisfy the TreeGrid requirement. ID is not used in server. The path from tree.getPath is used in server.

                Comment


                  #9
                  Yes, that's very common. Use the path as the id and the parent's path as the parentId.

                  Comment


                    #10
                    Originally posted by jasonzhang2002
                    I had make this work by adding DragStartHandler and DropHandler.
                    Unfortunately, I found that a drop handler will destroy the built-in drop handler which I still need. This behavior is mentioned in this thread :http://forums.smartclient.com/showthread.php?t=3432. This thread is posted in Dec 2008. Is a fix available?

                    thanks
                    -jason

                    Comment


                      #11
                      This has been fixed in SVN. For TreeGrid drop handling, use TreeGrid.addFolderDropHandler.

                      Code:
                      treeGrid.addFolderDropHandler(new FolderDropHandler() {
                            public void onFolderDrop(FolderDropEvent event) {
                                TreeNode[] nodes = event.getNodes();
                                int index = event.getIndex();
                             }
                       });
                      Sanjiv

                      Comment

                      Working...
                      X