/*
* Copyright 2003-2010 Tufts University Licensed under the
* Educational Community 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.osedu.org/licenses/ECL-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.
*/
/*
* VueDandDTree.java
*
* Created on September 17, 2003, 11:41 AM
*/
package tufts.vue;
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.net.*;
import java.awt.event.*;
import java.awt.datatransfer.*;
import java.awt.dnd.*;
import javax.swing.border.*;
import javax.swing.tree.*;
import java.util.Vector;
import javax.swing.event.*;
import osid.dr.*;
import osid.filing.*;
import tufts.oki.remoteFiling.*;
import tufts.oki.localFiling.*;
import java.awt.geom.Point2D;
import java.util.Iterator;
/**
*
* @version $Revision: 1.47 $ / $Date: 2010-02-03 19:17:40 $ / $Author: mike $
* @author rsaigal
*/
public class VueDandDTree extends VueDragTree implements DropTargetListener {
private final int ACCEPTABLE_DROP_TYPES =
DnDConstants.ACTION_COPY |
DnDConstants.ACTION_LINK |
DnDConstants.ACTION_MOVE;
private final boolean debug = true;
private final int FAVORITES = Resource.FAVORITES;
private final boolean sametree = true;
private final int newfavoritesnode = 0;
public VueDandDTree(FavoritesNode root){
super(root);
this.setRowHeight(30);
this.setEditable(false);
this.setShowsRootHandles(true);
this.expandRow(0);
this.setExpandsSelectedPaths(true);
this.getModel().addTreeModelListener(new VueTreeModelListener());
this. getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
VueDandDTreeCellRenderer renderer = new VueDandDTreeCellRenderer(this);
this.setCellRenderer(renderer);
// TODO: THE DROP CODE HERE IS COMPLETELY BROKEN. Drops don't work at all. I
// can't tell if they ever did, but it doesn't look like it. And the handle
// drop code is a wreck, and a duplicate of the code in DataSourceList, which at
// least takes drops, tho the processing is similarly broken. It will create
// directories out of plain files, etc, and it needless, painfully, uses the
// OSID V2 Filing OSID. OSID V3 promises to be much saner, tho even any V3
// Filing OSID impl is very unlikely to do anything to help us interface with
// the local operating system and filing system (it just makes it harder), and
// that's all we need to do here.
// Factor out the common code from MapDropTarget into a VueAbstractDropTarget
// for identifying transfer items and creating resources from them, leaving just
// the node code and map adding code in MapDropTarget.
// No point in doing this, but we're leaving it in just in case for now:
new DropTarget(this, // component
ACCEPTABLE_DROP_TYPES, // actions
this);
}
public void insertInto(MutableTreeNode newNode)
{
DefaultTreeModel model = (DefaultTreeModel)this.getModel();
ResourceNode o2 = (ResourceNode)getModel().getRoot();
model.insertNodeInto(newNode, (MutableTreeNode)o2, (o2.getChildCount()));
}
public void drop(DropTargetDropEvent e ) {
java.awt.Point dropLocation = e.getLocation();
ResourceNode rootNode;
boolean success = false;
Transferable transfer = e.getTransferable();
DataFlavor[] dataFlavors = transfer.getTransferDataFlavors();
String resourceName = null;
// java.util.List fileList = null;
//java.util.List resourceList = null;
java.util.List resourceList = null;
java.util.List fileList = null;
String droppedText = null;
DataFlavor foundFlavor = null;
Object foundData = null;
if (debug) System.out.println("drop: found " + dataFlavors.length + dataFlavors.toString());
try {
if (transfer.isDataFlavorSupported(Resource.DataFlavor)) {
foundFlavor = Resource.DataFlavor;
foundData = transfer.getTransferData(foundFlavor);
resourceList = (java.util.List)foundData;
} else if (transfer.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
foundFlavor = DataFlavor.javaFileListFlavor;
foundData = transfer.getTransferData(foundFlavor);
fileList = (java.util.List)foundData;
} else if (transfer.isDataFlavorSupported(DataFlavor.stringFlavor)) {
foundFlavor = DataFlavor.stringFlavor;
foundData = transfer.getTransferData(DataFlavor.stringFlavor);
droppedText = (String)foundData;
} else {
System.out.println("TRANSFER: found no supported dataFlavors");
}
} catch (UnsupportedFlavorException ex) {
ex.printStackTrace();
System.err.println("TRANSFER: Transfer lied about supporting " + foundFlavor);
e.dropComplete(false);
return;
} catch (ClassCastException ex) {
ex.printStackTrace();
System.err.println("TRANSFER: Transfer data did not match declared type! flavor="
+ foundFlavor + " data=" + foundData.getClass());
e.dropComplete(false);
return;
} catch (java.io.IOException ex) {
ex.printStackTrace();
System.err.println("TRANSFER: data no longer available");
e.dropComplete(false);
return;
}
DefaultTreeModel model = (DefaultTreeModel)this.getModel();
// New Favorites FolderNew Favorites Folder
//if ((this.getPathForLocation(dropLocation.x, dropLocation.y) == null)){rootNode = (ResourceNode)model.getRoot();
//System.out.println("loc"+"x"+dropLocation.x+"y"+dropLocation.y);
//}
//else
if (dropLocation.x < 4) {
rootNode = (ResourceNode)model.getRoot();
System.out.println("loc"+"x"+dropLocation.x+"y"+dropLocation.y);
} else if ((this.getPathForLocation(dropLocation.x, dropLocation.y) == null)){
rootNode = (ResourceNode)model.getRoot();
System.out.println("loc"+"x"+dropLocation.x+"y"+dropLocation.y);
}else{
rootNode = (ResourceNode)this.getPathForLocation(dropLocation.x, dropLocation.y).getLastPathComponent();
System.out.println("loc1"+ dropLocation.x+dropLocation.y);
if (rootNode == tufts.vue.VueDragTree.oldnode){//System.out.println("this is same");
return;
}
boolean parentdrop = false;
if (rootNode.getParent() == tufts.vue.VueDragTree.oldnode){System.out.println("Cannot move a parent node into a child.. Can cause infinite loops");
return;
}
}
if (rootNode.getResource().getClientType() == FAVORITES){
if (resourceList != null){
java.util.Iterator iter = resourceList.iterator();
while(iter.hasNext()) {
Resource resource = (Resource) iter.next();
if (DEBUG.DND) System.out.println("RESOURCE FOUND: " + resource+ " type ="+ resource.getClientType()+ " resource class:"+resource.getClass());
ResourceNode newNode;
// TODO: ALL THIS CODE IS IDENNTICAL TO THAT IN DataSourceList
if (resource.isLocalFile()) {
final CabinetResource cr = (CabinetResource) resource;
newNode = new CabinetNode(cr, CabinetNode.LOCAL);
if(DEBUG.DND) System.out.println("CABINET RESOURCE: " + resource+ "Entry: "+cr.getEntry()+ "entry type:"+cr.getEntry().getClass()+" type:"+cr.getEntry());
} else {
newNode =new ResourceNode(resource);
}
this.setRootVisible(true);
model.insertNodeInto(newNode, rootNode, (rootNode.getChildCount()));
this.expandPath(new TreePath(rootNode.getPath()));
//this.expandRow(0);
this.setRootVisible(false);
}
}else if (fileList != null){
java.util.Iterator iter = fileList.iterator();
while(iter.hasNext()) {
File file = (File)iter.next();
System.out.println("File Drop: " +file);
try{
final LocalFilingManager manager = LocalFileDataSource.getLocalFilingManager();
osid.shared.Agent agent = null;
LocalCabinet cab = LocalCabinet.instance(file.getAbsolutePath(),agent,null);
CabinetResource res = CabinetResource.create(cab);
CabinetEntry entry = res.getEntry();
CabinetNode cabNode = null;
if (entry instanceof RemoteCabinetEntry)
cabNode = new CabinetNode(res, CabinetNode.REMOTE);
else
cabNode = new CabinetNode(res, CabinetNode.LOCAL);
this.setRootVisible(true);
model.insertNodeInto(cabNode, rootNode, (rootNode.getChildCount()));
cabNode.explore();
}catch (Exception ex){}
this.expandPath(new TreePath(rootNode.getPath()));
this.setRootVisible(false);
}
}
else if (droppedText != null){
ResourceNode newNode = new ResourceNode(Resource.getFactory().get(droppedText));
this.setRootVisible(true);
model.insertNodeInto(newNode, rootNode, (rootNode.getChildCount()));
this.expandPath(new TreePath(rootNode.getPath()));
//this.expandRow(0);
this.setRootVisible(false);
}
if (e.isLocalTransfer()){
tufts.vue.VUE.dropIsLocal = true;
e.acceptDrop(DnDConstants.ACTION_MOVE);
e.dropComplete(true);
}
} else{
VueUtil.alert(null, VueResources.getString("dialog.resourceadd.message"), VueResources.getString("dialog.resourceadd.title"));
//.dropComplete(false);
}
}
private void insertSubTree(ResourceNode rootNode,ResourceNode cloneNode, DefaultTreeModel treeModel){
int i; int childCount = rootNode.getChildCount();
System.out.println("root" + rootNode +"childCount" + childCount);
for (i = 0; i < childCount; i++){
// ResourceNode newChildc = (ResourceNode)(((ResourceNode)(rootNode.getChildAt(i))).clone());
ResourceNode newChild = (ResourceNode)(rootNode.getChildAt(i));
ResourceNode newChildc = (ResourceNode)newChild.clone();
treeModel.insertNodeInto(newChildc, cloneNode, i);
insertSubTree(newChild,newChildc,treeModel);
}
}
class VueTreeModelListener implements TreeModelListener {
public void treeNodesChanged(TreeModelEvent e) {
ResourceNode node;
node = (ResourceNode)
(e.getTreePath().getLastPathComponent());
/*
* If the event lists children, then the changed
* node is the child of the node we've already
* gotten. Otherwise, the changed node and the
* specified node are the same.
*/
try {
int index = e.getChildIndices()[0];
node = (ResourceNode)
(node.getChildAt(index));
} catch (NullPointerException exc) {}
System.out.println("The user has finished editing the node.");
System.out.println("New value: " + node.getUserObject());
MapResource resource = (MapResource)node.getResource();
resource.setTitle(node.getUserObject().toString());
clearSelection();
}
public void treeNodesInserted(TreeModelEvent e) {
}
public void treeNodesRemoved(TreeModelEvent e) {
}
public void treeStructureChanged(TreeModelEvent e) {
}
}
class VueDandDTreeCellRenderer extends VueDragTreeCellRenderer
{
private boolean hasImageIcon;
private final Dimension imageIconPrefSize = new Dimension(Short.MAX_VALUE, 32+3);
private final Dimension defaultPrefSize = new Dimension(Short.MAX_VALUE, 20); // todo: common default for VueDragTree
private final Border lineBorder = new MatteBorder(1,0,0,0, tufts.vue.ui.ResourceList.DividerColor);
private final Border leftInsetBorder = lineBorder;
//private Border leftInsetBorder = new CompoundBorder(lineBorder, new EmptyBorder(0,8,0,0));
public VueDandDTreeCellRenderer(VueDandDTree pTree) {
super(pTree);
setAlignmentY(0.5f);
tree.addMouseMotionListener(new MouseMotionAdapter() {
public void mouseClicked(MouseEvent me){
if (me.getClickCount() == 1) {
TreePath treePath = tree.getPathForLocation(me.getX(), me.getY());
}
}
public void mouseMoved(MouseEvent me) {
TreePath treePath = tree.getPathForLocation(me.getX(), me.getY());
}
});
}
@Override
public Dimension getPreferredSize() {
if (hasImageIcon)
return imageIconPrefSize;
else
return defaultPrefSize;
}
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel,
boolean expanded,boolean leaf,int row, boolean hasFocus)
{
final ResourceNode node = (ResourceNode) value;
final Resource r = node.getResource();
final int level = node.getLevel();
if (level <= 1 && r != null) {
// if (leaf && r.isImage() /* &&!r.isLocalFile()*/ ) {
// // This will allow image content to show an icon that shows the image itself
// icon = r.getContentIcon(tree);
// //} else if (DEBUG.Enabled && !leaf) {
// } else if (!leaf) {
// // This will make folder items appear at 32x32 instead of the default tiny 16x16
// icon = r.getLargeIcon();
// }
// Items at the top level are treated differently
Icon icon = null;
if (r.isImage()) {
// This will allow image content to show an icon that shows the image itself
icon = r.getContentIcon(tree);
} else {
// This will make folder items appear at 32x32 instead of the default tiny 16x16
icon = r.getLargeIcon();
}
if (icon != null) {
hasImageIcon = true;
superGetTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
setIcon(icon);
setBorder(lineBorder);
return this;
}
}
super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
hasImageIcon = false;
if (level > 1 || row == 0) {
setBorder(null);
} else {
setBorder(leftInsetBorder);
}
return this;
}
}
public void dragEnter(DropTargetDragEvent me) { }
public void dragExit(DropTargetEvent e) {}
public void dragOver(DropTargetDragEvent e) { }
public void dropActionChanged(DropTargetDragEvent e) { }
private String readTextFlavor(DataFlavor flavor, Transferable transfer) {
java.io.Reader reader = null;
String value = null;
try {
reader = flavor.getReaderForText(transfer);
if (debug) System.out.println("\treader=" + reader);
char buf[] = new char[512];
int got = reader.read(buf);
value = new String(buf, 0, got);
if (debug) System.out.println("\t[" + value + "]");
if (reader.read() != -1)
System.out.println("there was more data in the reader");
} catch (Exception e) {
System.err.println("readTextFlavor: " + e);
}
return value;
}
public static void main(String args[]) {
VUE.init(args);
new Frame("An Active Frame").setVisible(true);
Resource r = Resource.getFactory().get("http://www.tufts.edu/");
VueDandDTree tree = new VueDandDTree(new FavoritesNode(r));
tufts.Util.displayComponent(tree);
}
public void addResource(Resource resource) {
// TODO Auto-generated method stub
ResourceNode rootNode = (ResourceNode)getModel().getRoot();
ResourceNode newNode = new ResourceNode(resource);
((DefaultTreeModel) getModel()).insertNodeInto((MutableTreeNode)newNode, (MutableTreeNode)rootNode, ((DefaultMutableTreeNode)rootNode).getChildCount());
this.expandPath(new TreePath(rootNode.getPath()));
}
}