javax.help.plaf.basic.BasicFavoritesNavigatorUI Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of javahelp Show documentation
Show all versions of javahelp Show documentation
The JavaHelp API provides a platform-independent help framework.
The newest version!
/*
* @(#)BasicFavoritesNavigatorUI.java 1.17 06/10/30
*
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package javax.help.plaf.basic;
import javax.help.*;
import javax.help.plaf.HelpNavigatorUI;
import javax.help.plaf.HelpUI;
import javax.help.event.HelpModelListener;
import javax.help.event.HelpModelEvent;
import java.util.EventObject;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import java.util.Locale;
import java.util.HashMap;
import javax.swing.*;
import javax.swing.plaf.ComponentUI;
import javax.swing.tree.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.io.Reader;
import java.io.Serializable;
import java.net.URL;
import java.net.URLConnection;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.awt.event.ComponentEvent;
import javax.help.Map.ID;
import java.text.Collator;
import java.text.RuleBasedCollator;
import java.net.MalformedURLException;
import java.util.HashSet;
import javax.help.event.HelpSetListener;
import javax.help.event.HelpSetEvent;
import java.awt.Cursor;
import java.awt.image.BufferedImage;
import java.awt.geom.Rectangle2D.Float;
import java.awt.geom.Rectangle2D;
import java.awt.geom.AffineTransform;
import java.awt.datatransfer.*;
import java.awt.dnd.*;
import java.awt.dnd.peer.*;
import java.io.IOException;
/**
* The default UI for JHelpNavigator of type Favorites
*
* @author Richard Gregor
* @version 1.17 10/30/06
*/
public class BasicFavoritesNavigatorUI extends HelpNavigatorUI
implements HelpModelListener, TreeSelectionListener, HelpSetListener,
PropertyChangeListener, TreeModelListener, Serializable {
protected JHelpFavoritesNavigator favorites;
protected JScrollPane sp;
protected FavoritesNode topNode;
protected JTree tree;
private String contentTitle;
protected RuleBasedCollator rbc;
protected String oldText;
protected DefaultMutableTreeNode currentFindNode;
protected Action addAction;
protected Action removeAction;
protected Action cutAction;
protected Action pasteAction;
protected Action copyAction;
protected Action folderAction;
protected JPopupMenu popup;
private HashMap dataMap = new HashMap();
// node wich will contain parsed favorites data
private FavoritesNode favNode = null;
// node which contents will be saved
private FavoritesNode rootNode = null;
private Locale locale = null;
private FavoritesNode selectedNode = null;
private FavoritesItem selectedItem = null;
private TreePath selectedTreePath = null;
private Map.ID selectedID = null;
private JMenuItem newFolderMI = null;
private JMenuItem addMI = null;
private JSeparator separatorMI = null;
private JMenuItem cutMI = null;
private JMenuItem copyMI = null;
private JMenuItem pasteMI = null;
private JMenuItem removeMI = null;
private HashMap hsMap = null;
//HasMap with visible node from favNode as key and its related node from rootNode as a value
private HashMap connections = new HashMap();
/**
* Vector of nodes used in CutAction
*/
private Vector nodeClipboard = new Vector();
static private boolean on1dot3 = false;
static {
try {
// Test if method introduced in 1.3 or greater is available.
Class klass = Class.forName("javax.swing.InputVerifier");
on1dot3 = (klass != null);
} catch (ClassNotFoundException e) {
on1dot3 = false;
}
}
public static ComponentUI createUI(JComponent x) {
return new BasicFavoritesNavigatorUI((JHelpFavoritesNavigator) x);
}
/**
* Creates BasicFavoritesUI for JHelpFavoritesNavigator
*/
public BasicFavoritesNavigatorUI(JHelpFavoritesNavigator b) {
ImageIcon icon = getImageIcon(b.getNavigatorView());
if (icon != null) {
setIcon(icon);
} else {
setIcon(UIManager.getIcon("FavoritesNav.icon"));
}
}
public void installUI(JComponent c) {
debug("installUI");
locale = HelpUtilities.getLocale(c);
addAction = new AddAction();
removeAction = new RemoveAction();
folderAction = new FolderAction();
favorites = (JHelpFavoritesNavigator)c;
HelpModel model = favorites.getModel();
favorites.setLayout(new BorderLayout());
favorites.addPropertyChangeListener(this);
if (model != null) {
model.addHelpModelListener(this); // for our own changes
model.addPropertyChangeListener(this); // for HelpSet change
HelpSet helpSet = model.getHelpSet();
if(helpSet != null)
helpSet.addHelpSetListener(this);
}
topNode = new FavoritesNode(new FavoritesItem("Favorites"));
if (on1dot3) {
// Use drag and drop if available
tree = new FavoritesTree(topNode);
} else {
tree = new JTree(topNode);
}
tree.setEditable(true);
tree.addMouseListener(new PopupListener());
cutAction = new CutAction();
copyAction = new CopyAction();
pasteAction = new PasteAction();
popup = new JPopupMenu();
newFolderMI = new JMenuItem((String)folderAction.getValue(folderAction.NAME));
newFolderMI.addActionListener(folderAction);
popup.add(newFolderMI);
addMI = new JMenuItem((String)addAction.getValue(addAction.NAME));
addMI.addActionListener(addAction);
popup.add(addMI);
separatorMI = new JSeparator();
popup.add(separatorMI);
cutMI = new JMenuItem((String)cutAction.getValue(cutAction.NAME));
cutMI.addActionListener(cutAction);
cutMI.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X,java.awt.Event.CTRL_MASK));
popup.add(cutMI);
copyMI = new JMenuItem((String)copyAction.getValue(copyAction.NAME));
copyMI.addActionListener(copyAction);
copyMI.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C,java.awt.Event.CTRL_MASK));
popup.add(copyMI);
pasteMI = new JMenuItem((String)pasteAction.getValue(pasteAction.NAME));
pasteMI.addActionListener(pasteAction);
pasteMI.setEnabled(false);
pasteMI.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V,java.awt.Event.CTRL_MASK));
popup.add(pasteMI);
removeMI = new JMenuItem((String) removeAction.getValue(removeAction.NAME));
removeMI.addActionListener(removeAction);
popup.add(removeMI);
tree.getModel().addTreeModelListener(this);
tree.addTreeSelectionListener(this);
TreeSelectionModel tsm = tree.getSelectionModel();
tsm.addTreeSelectionListener(this);
tree.setShowsRootHandles(true);
tree.setRootVisible(false);
setCellRenderer(favorites.getNavigatorView(), tree);
sp = new JScrollPane();
sp.getViewport().add(tree);
favorites.add("Center", sp);
reloadData();
}
/**
* Sets the desired cell renderer on this tree. This is exposed for redefinition
* by subclases.
*/
protected void setCellRenderer(NavigatorView view, JTree tree) {
tree.setCellRenderer(new BasicFavoritesCellRenderer());
}
public void uninstallUI(JComponent c) {
debug("uninstallUI");
HelpModel model = favorites.getModel();
favorites.removePropertyChangeListener(this);
TreeSelectionModel tsm = tree.getSelectionModel();
tsm.removeTreeSelectionListener(this);
favorites.setLayout(null);
favorites.removeAll();
if (model != null) {
model.removeHelpModelListener(this);
}
favorites = null;
}
public Dimension getPreferredSize(JComponent c) {
return new Dimension(200,100);
}
public Dimension getMinimumSize(JComponent c) {
return new Dimension(100,100);
}
public Dimension getMaximumSize(JComponent c) {
return new Dimension(Short.MAX_VALUE, Short.MAX_VALUE);
}
private void reloadData() {
debug("reloadData");
//needs refactoring - sholudn't parse each time!!! - only once
if (favorites.getModel() == null) {
return;
}
// remove all children
topNode.removeAllChildren();
FavoritesView view = (FavoritesView) favorites.getNavigatorView();
if (view == null) {
return;
}
favNode = view.getDataAsTree();
rootNode = favNode.getDeepCopy();
classifyNode(favNode);
while (favNode.getChildCount() > 0) {
// this looks strange but as you add a child to the top node
// it removes the child from the favNode so the getFirstChild
// will always get the first child
topNode.add((DefaultMutableTreeNode)favNode.getFirstChild());
}
// reload the tree data
((DefaultTreeModel)tree.getModel()).reload();
setVisibility(topNode);
}
/**
* Classifies the node. Determines wheter child will be visible or not according to node's HelpSet.
* Hides node without children when its HelpSet is not loaded
*
* @param node The FavoritesNode
*/
private void classifyNode(FavoritesNode node){
debug("classifyNode");
if(node == null)
return;
HelpModel model = favorites.getModel();
if(model == null){
node.removeAllChildren();
return;
}
HelpSet masterHelpSet = model.getHelpSet();
if(masterHelpSet == null){
node.removeAllChildren();
return;
}
hsMap = new HashMap();
hsMap.put(masterHelpSet.getTitle(), masterHelpSet);
fillHelpSetTitles(masterHelpSet);
// tags node's children wheter they are visible or not
classifyChildren(node);
}
/**
* Fills HashMap with actual HelpSets and their titles
*
* @param masterHelpSet The master HelpSet
*/
private void fillHelpSetTitles(HelpSet masterHelpSet){
for(Enumeration helpSets = masterHelpSet.getHelpSets();helpSets.hasMoreElements();){
HelpSet hs = (HelpSet) helpSets.nextElement();
if(hs != null){
hsMap.put(hs.getTitle(), hs);
debug(" fill title: "+hs.getTitle());
fillHelpSetTitles(hs);
}
}
}
/**
* Classifies children of node
*
* @param node The FavoritesNode
*/
private void classifyChildren(FavoritesNode node){
debug("classifyChildren: "+node);
if(node == null)
return;
boolean skipChild = true;
for(Enumeration children = node.preorderEnumeration();children.hasMoreElements();){
FavoritesNode chnode = (FavoritesNode)children.nextElement();
// Skip the first entry because it is node and we don't need
// to classify the node only it's children
if (skipChild) {
skipChild = false;
continue;
}
// Add this child node to the root node.
// Make a copy of the child node for the rootNode
FavoritesNode copy = chnode.getDeepCopy();
// establish the connection between the chnode and the copy
connections.put(chnode, copy);
// properly connect it to the childs corresponding parent in the
// rootnode.
FavoritesNode rootParent = (FavoritesNode)connections.get(chnode.getParent());
if (rootParent == null) {
rootParent = rootNode;
}
rootParent.add(copy);
// Now on to seeing if the item
FavoritesItem item = (FavoritesItem)chnode.getUserObject();
debug("classify item: "+ item);
//shouldn't happen
if(item == null){
debug("item is null : fillDataMap");
continue;
}
String target = item.getTarget();
String hsTitle = item.getHelpSetTitle();
if(!hsMap.containsKey(hsTitle)){
if(chnode.getVisibleChildCount() == 0){
if(item.emptyInitState() && item.isFolder()){
debug("empty init state");
continue;
}
//chnode.removeFromParent();
item.setVisible(false);
continue;
}
}
if(target == null){
debug("target is null:fillDataMap");
continue;
}
Map.ID id = null;
try{
id = Map.ID.create(target, (HelpSet)hsMap.get(hsTitle));
}catch(BadIDException ep){
debug(ep.getMessage());
continue;
}
debug("put to the dataMap: "+item);
dataMap.put(item,id);
}
//clear node
Vector toRemove = new Vector();
Enumeration nodesToRem = node.breadthFirstEnumeration();
while(nodesToRem.hasMoreElements()) {
FavoritesNode fn = (FavoritesNode)nodesToRem.nextElement();
if(!fn.isVisible()){
debug ("remove node:" +(FavoritesItem)fn.getUserObject());
toRemove.addElement(fn);
}
}
for (int i=0; i < toRemove.size(); i++) {
debug("removing " + toRemove.elementAt(i));
try {
node.remove((DefaultMutableTreeNode) toRemove.elementAt(i));
} catch (IllegalArgumentException iae) {
// ignore - supernode is already removed
}
}
}
/**
* Expands entry path and entry itself( when entry is not empty) for specific id
*
* @param target The target of entry
*/
private void expand(String target){
debug("expand called");
//find all nodes with certain id
Enumeration nodes = findNodes(target).elements();
DefaultMutableTreeNode node = null;
while(nodes.hasMoreElements()){
node = (DefaultMutableTreeNode)nodes.nextElement();
debug("expandPath :"+node);
if(node.getChildCount() > 0){
DefaultMutableTreeNode child =(DefaultMutableTreeNode) node.getFirstChild();
TreePath path = new TreePath(child.getPath());
tree.makeVisible(path);
}
else{
TreeNode[] treeNode = node.getPath();
TreePath path = new TreePath(treeNode);
//tree.scrollPathToVisible(path);
tree.makeVisible(path);
}
}
}
/**
* Returns all nodes with certain id
*
* @param target The target of entry
*
*/
private Vector findNodes(String target){
Enumeration nodes = topNode.preorderEnumeration();
DefaultMutableTreeNode node = null;
Vector nodeFound = new Vector();
while(nodes.hasMoreElements()){
node = (DefaultMutableTreeNode)nodes.nextElement();
debug(" node :"+ node.toString());
if(node != null){
FavoritesItem favoritesItem = (FavoritesItem)node.getUserObject();
if(favoritesItem == null)
debug("favoritesItem is null");
else{
//Map.ID id = favoritesItem.getID();
Map.ID id = (Map.ID)dataMap.get(favoritesItem);
if(id != null){
debug("id name :"+id.id);
debug("target :"+target);
Map.ID itemID = null;
try{
itemID = Map.ID.create(target,favorites.getModel().getHelpSet());
}
catch(BadIDException exp){
System.err.println("Not valid ID :"+target );
break;
}
if(id.equals(itemID))
nodeFound.addElement(node);
}
}
}
}
return nodeFound;
}
/**
* Collapses entry specified by id. If entry is empty collapses it's parent.
*
* @param target The target of entry
*/
private void collapse(String target){
Enumeration nodes = findNodes(target).elements();
DefaultMutableTreeNode node = null;
debug("collapse called");
while(nodes.hasMoreElements()){
node = (DefaultMutableTreeNode)nodes.nextElement();
if(node.getChildCount() > 0){
TreeNode[] treeNode = node.getPath();
TreePath path = new TreePath(treeNode);
tree.collapsePath(path);
tree.collapseRow(tree.getRowForPath(path));
}
else{
DefaultMutableTreeNode parent =(DefaultMutableTreeNode) node.getParent();
TreePath path = new TreePath(parent.getPath());
tree.collapseRow(tree.getRowForPath(path));
}
}
}
// Make all nodes visible
private void setVisibility(DefaultMutableTreeNode node) {
tree.expandPath(new TreePath(node.getPath()));
if (! node.isLeaf()) {
int max = node.getChildCount();
for (int i=0; i= 0){
for(int j = nodes.length - 1; j >= 0; j--){
FavoritesNode copy = ((FavoritesNode) nodes[j]).getDeepCopy();
rootParent.insert((DefaultMutableTreeNode)copy,place);
connections.put((FavoritesNode)nodes[j],copy);
}
}
}else if (firstIndex > 0){
//find what is before
FavoritesNode nodeBefore = (FavoritesNode)parent.getChildAt(firstIndex - 1);
FavoritesNode rootNode = (FavoritesNode)connections.get(nodeBefore);
place = rootParent.getIndex(rootNode)+1;
for(int k = nodes.length - 1; k >= 0; k--){
FavoritesNode copyNode = ((FavoritesNode)nodes[k]).getDeepCopy();
rootParent.insert((DefaultMutableTreeNode)copyNode,place);
connections.put((FavoritesNode)nodes[k],copyNode);
}
}
}
public void treeNodesRemoved(javax.swing.event.TreeModelEvent treeModelEvent) {
debug("nodes removed");
Object nodes[] = treeModelEvent.getChildren();
for(int i = 0; i < nodes.length; i++){
FavoritesNode originalNode = (FavoritesNode)nodes[i];
FavoritesNode remNode = (FavoritesNode)connections.get(originalNode);
if(remNode != null)
remNode.removeFromParent();
}
}
public void treeNodesChanged(javax.swing.event.TreeModelEvent treeModelEvent) {
debug("node changed");
TreeCellEditor editor = tree.getCellEditor();
Object newName = editor.getCellEditorValue();
if((newName instanceof String) && selectedItem != null){
debug("new name");
//data of old item
Map.ID itemID = (Map.ID)dataMap.get(selectedItem);
//remove old data from dataMap
dataMap.remove(selectedItem);
FavoritesNode fromRootNode = (FavoritesNode)connections.get(getSelectedNode());
//change name of old Item
selectedItem.setName((String)newName);
selectedNode.setUserObject(selectedItem);
if(fromRootNode != null){
FavoritesItem fromRootItem = (FavoritesItem) fromRootNode.getUserObject();
fromRootItem.setName((String)newName);
}
//put data to the dataMap
dataMap.put(selectedItem,itemID);
saveFavorites();
}
}
/**
* Returns the selected node
*
*/
public FavoritesNode getSelectedNode() {
return selectedNode;
}
/**
* AddAction class.
*
*/
public class AddAction extends AbstractAction{
public AddAction(){
super(HelpUtilities.getString(locale, "favorites.add"), SwingHelpUtilities.getImageIcon(BasicFavoritesNavigatorUI.class,"images/addToFav.gif"));
}
public void actionPerformed(ActionEvent ev){
debug("add");
String target = null;
String hstitle = null;
FavoritesItem favorite = null;
HelpModel helpModel = favorites.getModel();
HelpSet hs = helpModel.getHelpSet();
Map.ID ID = helpModel.getCurrentID();
URL url = helpModel.getCurrentURL();
if(ID != null){
target = ID.id;
hstitle = ID.hs.getTitle();
}
if(hstitle == null){
// need to determine the helpset title by looking at the
// starting URL of the
hstitle = getHelpSetTitle(hs, url);
if (hstitle == null) {
hstitle= hs.getTitle();
}
}
String urlSpec = null;
if(target == null) {
urlSpec = url.toExternalForm();
}
favorite = new FavoritesItem(contentTitle, target, urlSpec,
hstitle, Locale.getDefault());
dataMap.put(favorite,ID);
FavoritesNode node = new FavoritesNode(favorite);
DefaultTreeModel model = (DefaultTreeModel)tree.getModel();
model.insertNodeInto(node, topNode, topNode.getChildCount());
TreePath path = new TreePath(node.getPath());
tree.expandPath(path);
tree.setSelectionPath(path);
tree.scrollPathToVisible(path);
saveFavorites();
}
/**
* retuns a helpset title for a given url
*/
private String getHelpSetTitle(HelpSet hs, URL url) {
URL baseURL = hs.getHelpSetURL();
String urlExternal = url.toExternalForm();
String baseURLExternal = baseURL.toExternalForm();
if (urlExternal.startsWith(baseURLExternal)) {
return hs.getTitle();
}
Enumeration helpsets = hs.getHelpSets();
String title = null;
while (helpsets.hasMoreElements()) {
HelpSet testHS = (HelpSet) helpsets.nextElement();
title = getHelpSetTitle(testHS, url);
if (title != null) {
break;
}
}
return title;
}
}
/**
* Returns the Add action
*
*/
public Action getAddAction(){
return addAction;
}
/**
* RemoveAction class.
*
*/
public class RemoveAction extends AbstractAction{
public RemoveAction(){
super(HelpUtilities.getString(locale, "favorites.remove"), SwingHelpUtilities.getImageIcon(BasicFavoritesNavigatorUI.class,"images/remove.gif"));
}
public void actionPerformed(ActionEvent ev){
debug("remove");
DefaultMutableTreeNode node = null;
DefaultTreeModel model = (DefaultTreeModel)tree.getModel();
TreePath[] paths = tree.getSelectionPaths();
for(int i = 0 ; i < paths.length; i++){
if(paths[i] != null){
node = (DefaultMutableTreeNode)paths[i].getLastPathComponent();
model.removeNodeFromParent(node);
if(node != null){
FavoritesItem item = (FavoritesItem)node.getUserObject();
dataMap.remove(item);
}
}
saveFavorites();
}
}
}
/**
* Returns the RemoveAction object
*/
public Action getRemoveAction(){
return removeAction;
}
/**
* FolderAction class.
*
*/
public class FolderAction extends AbstractAction{
public FolderAction(){
super(HelpUtilities.getString(locale, "favorites.folder"), SwingHelpUtilities.getImageIcon(BasicFavoritesNavigatorUI.class,"images/folder.gif"));
}
public void actionPerformed(ActionEvent ev){
FavoritesItem favoriteFolder = new FavoritesItem(HelpUtilities.getString(locale, "favorites.folder"));
favoriteFolder.setAsFolder();
FavoritesNode node = new FavoritesNode(favoriteFolder);
TreePath nodePath = tree.getSelectionPath();
TreeNode parent = null;
if(nodePath == null)
parent = topNode;
else{
FavoritesNode selNode = (FavoritesNode)nodePath.getLastPathComponent();
parent = selNode.getParent();
}
DefaultTreeModel model = (DefaultTreeModel)tree.getModel();
model.insertNodeInto(node,(DefaultMutableTreeNode)parent,parent.getChildCount());
TreePath path = new TreePath(node.getPath());
tree.expandPath(path);
tree.setSelectionPath(path);
tree.scrollPathToVisible(path);
saveFavorites();
}
}
/**
* Returns the FolderAction object
*/
public Action getFolderAction(){
return folderAction;
}
/**
* CutAction class.
*/
public class CutAction extends AbstractAction{
public CutAction(){
super(HelpUtilities.getString(locale,"favorites.cut"));
}
public void actionPerformed(ActionEvent ev){
debug("cut");
DefaultMutableTreeNode node = null;
nodeClipboard.removeAllElements();
DefaultTreeModel model = (DefaultTreeModel)tree.getModel();
TreePath[] paths = tree.getSelectionPaths();
for(int i = 0 ; i < paths.length; i++){
if(paths[i] != null){
node = (DefaultMutableTreeNode)paths[i].getLastPathComponent();
if(node != null){
FavoritesItem item = (FavoritesItem)node.getUserObject();
nodeClipboard.add(node);
}
model.removeNodeFromParent(node);
}
}
saveFavorites();
pasteMI.setEnabled(true);
}
}
/**
* Returns the CutAction object
*/
public Action getCutAction(){
return cutAction;
}
/**
* PasteAction class.
*/
public class PasteAction extends AbstractAction{
public PasteAction(){
super(HelpUtilities.getString(locale,"favorites.paste"));
}
public void actionPerformed(ActionEvent ev){
debug("paste");
DefaultTreeModel model = (DefaultTreeModel)tree.getModel();
TreePath path = tree.getSelectionPath();
FavoritesNode node = (FavoritesNode)path.getLastPathComponent();
if(node != null){
if(node.getAllowsChildren()){
for(Enumeration nodes = nodeClipboard.elements(); nodes.hasMoreElements();){
model.insertNodeInto((DefaultMutableTreeNode)nodes.nextElement(),(DefaultMutableTreeNode)node,node.getChildCount());
}
}
else{
DefaultMutableTreeNode parent = (DefaultMutableTreeNode)node.getParent();
if(parent == null)
return;
int index = parent.getIndex(node);
for(Enumeration en = nodeClipboard.elements(); en.hasMoreElements();index++){
model.insertNodeInto((DefaultMutableTreeNode)en.nextElement(),parent,index);
}
}
saveFavorites();
}
}
}
/**
* Returns the PasteAction object
*/
public Action getPasteAction(){
return pasteAction;
}
/**
* CopyAction class.
*/
public class CopyAction extends AbstractAction{
public CopyAction(){
super(HelpUtilities.getString(locale,"favorites.copy"));
}
public void actionPerformed(ActionEvent ev){
debug("paste");
DefaultMutableTreeNode node = null;
nodeClipboard.removeAllElements();
DefaultTreeModel model = (DefaultTreeModel)tree.getModel();
TreePath[] paths = tree.getSelectionPaths();
for(int i = 0 ; i < paths.length; i++){
if(paths[i] != null){
node = (DefaultMutableTreeNode)paths[i].getLastPathComponent();
if(node != null){
FavoritesItem item = (FavoritesItem)node.getUserObject();
FavoritesNode copy = ((FavoritesNode)node).getDeepCopy();
nodeClipboard.add(copy);
}
}
}
saveFavorites();
pasteMI.setEnabled(true);
}
}
/**
* Returns the CopyAction Object
*/
public Action getCopyAction(){
return copyAction;
}
/**
* PopupListener class
*/
public class PopupListener extends MouseAdapter{
public void mousePressed(MouseEvent e){
maybeShowPopup(e);
}
public void mouseReleased(MouseEvent e){
maybeShowPopup(e);
}
private void maybeShowPopup(MouseEvent e) {
TreePath path = tree.getSelectionPath();
TreePath clickPath = tree.getPathForLocation(e.getX(),e.getY());
if (e.isPopupTrigger()) {
if (path != null && path.equals(clickPath)) {
separatorMI.setVisible(true);
cutMI.setVisible(true);
copyMI.setVisible(true);
pasteMI.setVisible(true);
removeMI.setVisible(true);
} else {
separatorMI.setVisible(false);
cutMI.setVisible(false);
copyMI.setVisible(false);
pasteMI.setVisible(false);
removeMI.setVisible(false);
}
popup.show(e.getComponent(), e.getX(), e.getY());
}
}
}
/**
* Class for JTree supported D&D features.
*/
public class FavoritesTree extends JTree implements DragGestureListener, DropTargetListener, DragSourceListener {
protected Map.ID selectedID = null;
private DragSource dragSource = null;
private DragSourceContext dragSourceContext = null;
private Point cursorLocation = null;
private TreePath pathSource;
private BufferedImage ghostImage;
private Point offset = new Point();
private Point ptLast = new Point();
private Rectangle2D ghostRect = new Rectangle2D.Float();
/**
* Data object of selected FavoritesNode
*/
private Map.ID hashCandidate;
/**
* Custom cursor
*/
private Cursor dndCursor;
/**
* Creates FavoritesTree
*
* @param root The root node of the tree
*/
public FavoritesTree(FavoritesNode root) {
super(root);
setEditable(true);
dragSource = DragSource.getDefaultDragSource();
DragGestureRecognizer dgr =
dragSource.createDefaultDragGestureRecognizer(this,DnDConstants.ACTION_COPY_OR_MOVE,this);
dgr.setSourceActions((dgr.getSourceActions()) &~ (InputEvent.BUTTON3_MASK));
DropTarget dropTarget = new DropTarget(this, this);
Toolkit tk = this.getToolkit();
if(tk.getBestCursorSize(16,16).equals(new Dimension(64,64)))
dndCursor = (Cursor) UIManager.get("HelpDnDCursor");
if(dndCursor == null)
debug("cursor is null");
putClientProperty("JTree.lineStyle", "None");
}
public void dragGestureRecognized(DragGestureEvent e) {
FavoritesNode dragNode = getSelectedNode();
if (dragNode != null) {
ghostImage = createGhostImage(e);
Transferable transferable = (Transferable) dragNode.getUserObject();
hashCandidate = (Map.ID)dataMap.get((FavoritesItem)transferable);
Cursor cursor = DragSource.DefaultCopyDrop;
int action = e.getDragAction();
if(action == DnDConstants.ACTION_MOVE){
debug("action move");
cursor = DragSource.DefaultMoveDrop;
}
dragSource.startDrag(e,dndCursor,ghostImage,new Point(5,5), transferable,this);
}
}
private BufferedImage createGhostImage(DragGestureEvent e){
debug("createGhostImage");
BufferedImage ghostImage = null;
Point ptDragOrigin = e.getDragOrigin();
TreePath path = getPathForLocation(ptDragOrigin.x, ptDragOrigin.y);
if (path == null)
return ghostImage;
Rectangle raPath = getPathBounds(path);
offset.setLocation(ptDragOrigin.x-raPath.x, ptDragOrigin.y-raPath.y);
JLabel lbl = (JLabel) getCellRenderer().getTreeCellRendererComponent
(this,path.getLastPathComponent(),false, isExpanded(path),getModel().isLeaf(path.getLastPathComponent()),0,false);
lbl.setSize((int)raPath.getWidth(), (int)raPath.getHeight());
ghostImage = new BufferedImage((int)raPath.getWidth(), (int)raPath.getHeight(), BufferedImage.TYPE_INT_ARGB_PRE);
Graphics2D g2 = ghostImage.createGraphics();
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC, 0.5f));
lbl.paint(g2);
Icon icon = lbl.getIcon();
int nStartOfText = (icon == null) ? 0 : icon.getIconWidth()+lbl.getIconTextGap();
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_OVER, 0.5f));
g2.setPaint(new GradientPaint(nStartOfText, 0, SystemColor.controlShadow,
getWidth(), 0, new Color(255,255,255,0)));
g2.fillRect(nStartOfText, 0, getWidth(), ghostImage.getHeight());
g2.dispose();
return ghostImage;
}
public void dragDropEnd(DragSourceDropEvent dsde) {
debug("dragDropEnd");
}
public void dragEnter(DragSourceDragEvent dsde) {
debug("dragEnter");
setCursor(dsde);
}
public void dragOver(DragSourceDragEvent dsde) {
debug("drag over");
setCursor(dsde);
}
public void dropActionChanged(DragSourceDragEvent dsde) {
debug("dropActionChanged");
setCursor(dsde);
}
public void dragExit(DragSourceEvent dsde) {
debug("dragExit");
}
/**
* Sets appropriate cursor type according to event
*
* @param dsde DrageSourceDrageEvent
*/
private void setCursor(DragSourceDragEvent dsde) {
if (cursorLocation == null) return;
TreePath destinationPath =
getPathForLocation(cursorLocation.x, cursorLocation.y);
DragSourceContext dsc = dsde.getDragSourceContext();
if (testDropTarget(destinationPath, selectedTreePath) == null){
dsc.setCursor(DragSource.DefaultCopyDrop);
}
else {
dsc.setCursor(DragSource.DefaultCopyNoDrop);
}
}
public void drop(DropTargetDropEvent e) {
debug("drop");
try {
Transferable tr = e.getTransferable();
if (!tr.isDataFlavorSupported( FavoritesItem.FAVORITES_FLAVOR)){
debug("drop rejected not data flavor");
e.rejectDrop();
}
FavoritesItem childInfo = (FavoritesItem) tr.getTransferData( FavoritesItem.FAVORITES_FLAVOR );
Point loc = e.getLocation();
TreePath destinationPath = getPathForLocation(loc.x, loc.y);
final String msg = testDropTarget(destinationPath, selectedTreePath);
if (msg != null) {
e.rejectDrop();
debug("Error : "+msg);
return;
}
FavoritesNode newParent =
(FavoritesNode) destinationPath.getLastPathComponent();
debug("new parent: "+newParent);
//get old parent node
FavoritesNode oldParent = (FavoritesNode) getSelectedNode().getParent();
FavoritesNode selNode = (FavoritesNode) getSelectedNode();
FavoritesItem selItem = (FavoritesItem) selNode.getUserObject();
FavoritesNode newNode = selNode.getDeepCopy();
int action = e.getDropAction();
boolean copyAction = (action == DnDConstants.ACTION_COPY);
debug("copy action: "+ copyAction);
//make new child node
FavoritesNode newChild = new FavoritesNode(childInfo);
debug("new child: "+newChild);
try {
if (!copyAction){
FavoritesNode fromRootNode = (FavoritesNode)connections.get(getSelectedNode());
if(fromRootNode != null)
fromRootNode.removeFromParent();
oldParent.remove(getSelectedNode());
}
DefaultTreeModel model = (DefaultTreeModel)getModel();
if (!newParent.getAllowsChildren()){
TreeNode parent = newParent.getParent();
if(parent != null){
int index = parent.getIndex(newParent);
model.insertNodeInto(newNode,(DefaultMutableTreeNode)parent, index+1);
}
}else
model.insertNodeInto(newNode,newParent,newParent.getChildCount());
if (copyAction)
e.acceptDrop(DnDConstants.ACTION_COPY);
else e.acceptDrop(DnDConstants.ACTION_MOVE);
}
catch (java.lang.IllegalStateException ils) {
debug("drop ejected");
e.rejectDrop();
}
e.getDropTargetContext().dropComplete(true);
FavoritesItem newItem = (FavoritesItem) newNode.getUserObject();
dataMap.put(newItem, hashCandidate);
DefaultTreeModel model = (DefaultTreeModel) getModel();
model.reload(oldParent);
model.reload(newParent);
TreePath parentPath = new TreePath(newParent.getPath());
expandPath(parentPath);
saveFavorites();
}
catch (IOException io) {
e.rejectDrop();
debug("drop rejected" + io);
}
catch (UnsupportedFlavorException ufe) {
e.rejectDrop();
debug("drop rejected: "+ ufe);
}
}
public void dragEnter(DropTargetDragEvent e) {
}
public void dragExit(DropTargetEvent e) {
if (!DragSource.isDragImageSupported()) {
repaint(ghostRect.getBounds());
}
}
public void dragOver(DropTargetDragEvent e) {
Point pt = e.getLocation();
if (pt.equals(ptLast))
return;
ptLast = pt;
Point cursorLocationBis = e.getLocation();
TreePath destinationPath = getPathForLocation(cursorLocationBis.x, cursorLocationBis.y);
Graphics2D g2 = (Graphics2D) getGraphics();
if(testDropTarget(destinationPath, selectedTreePath) == null){
e.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
if (!DragSource.isDragImageSupported()) {
paintImmediately(ghostRect.getBounds());
ghostRect.setRect(pt.x - offset.x, pt.y - offset.y, ghostImage.getWidth(), ghostImage.getHeight());
g2.drawImage(ghostImage, AffineTransform.getTranslateInstance(ghostRect.getX(), ghostRect.getY()), null);
}
}else
e.rejectDrag();
}
public void dropActionChanged(DropTargetDragEvent e) {
}
/**
* Tests whether drop location is valid or not
*
* @param destination The destination path
* @param dropper The path for the node to be dropped
* @return Null if no problems, otherwise an explanation
*/
private String testDropTarget(TreePath destination, TreePath dropper) {
boolean destinationPathIsNull = destination == null;
if (destinationPathIsNull){
return "Invalid drop location.";
//remove ghostLikeImage
}
FavoritesNode node = (FavoritesNode) destination.getLastPathComponent();
if (destination.equals(dropper))
return "Destination cannot be same as source";
if ( dropper.isDescendant(destination))
return "Destination node cannot be a descendant.";
if ( dropper.getParentPath().equals(destination))
return "Destination node cannot be a parent.";
return null;
}
}
/**
* For printf debugging.
*/
private static boolean debug = false;
private static void debug(String str) {
if (debug) {
System.out.println("BasicFavoritesNavigatorUI: " + str);
}
}
}