view java/src/uk/ac/qmul/eecs/ccmi/gui/filechooser/FileSystemTree.java @ 1:e3935c01cde2 tip

moved license of PdPersistenceManager to the beginning of the file
author Fiore Martin <f.martin@qmul.ac.uk>
date Tue, 08 Jul 2014 19:52:03 +0100
parents 78b7fc5391a2
children
line wrap: on
line source
/*  
 CCmI Editor - A Collaborative Cross-Modal Diagram Editing Tool
  
 Copyright (C) 2011  Queen Mary University of London (http://ccmi.eecs.qmul.ac.uk/)

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program 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 for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/  

package uk.ac.qmul.eecs.ccmi.gui.filechooser;

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.ResourceBundle;

import javax.swing.AbstractAction;
import javax.swing.JTree;
import javax.swing.KeyStroke;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.filechooser.FileFilter;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;

import uk.ac.qmul.eecs.ccmi.sound.PlayerListener;
import uk.ac.qmul.eecs.ccmi.sound.SoundEvent;
import uk.ac.qmul.eecs.ccmi.sound.SoundFactory;
import uk.ac.qmul.eecs.ccmi.speech.NarratorFactory;

/*
 *
 * A JTree displaying the content for the local file system.
 * 
 *
 */
@SuppressWarnings("serial")
class FileSystemTree extends JTree {
	FileSystemTree(FileFilter filter){
		super(new DefaultTreeModel(FileSystemTreeNode.getRootNode(filter)));
		getAccessibleContext().setAccessibleName(ResourceBundle.getBundle(SpeechFileChooser.class.getName()).getString("tree.accessible_name"));
		getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
		setCellRenderer(new FileSystemTreeCellRendered(getCellRenderer()));

		setSelectionPath(new TreePath(getModel().getRoot()));
		overwriteTreeKeystrokes();
		this.addTreeSelectionListener(new TreeSelectionListener(){
			@Override
			public void valueChanged(TreeSelectionEvent evt) {
				if(treeSelectionListenerGateOpen){
					FileSystemTreeNode treeNode = (FileSystemTreeNode)evt.getPath().getLastPathComponent();
					NarratorFactory.getInstance().speak(treeNode.spokenText());
				}
			}
		});
	}

	@Override
	public void setSelectionPath(TreePath path){
		super.setSelectionPath(path);
		scrollPathToVisible(path);
		getSelectionPath();
	}
	
	public void setSelectionPath(File file){
		if(file == null)
			return;
		
		try {
			file = file.getCanonicalFile();
		} catch (IOException e) {
			setSelectionPath(new TreePath(getModel().getRoot()));
			return;
		}
		/* make a file path: a list of file's each one representing a directory of file's path */
		LinkedList<File> filePath = new LinkedList<File>();
		filePath.add(file);
		File parent = file.getParentFile();
		while(parent != null){
			filePath.add(0, parent);
			parent = parent.getParentFile();
		}
		/* make a TreePath out of the file path */
		FileSystemTreeNode currentNode = (FileSystemTreeNode)getModel().getRoot();
		TreePath treePath = new TreePath(currentNode);
		for(File f : filePath){
			boolean found = false;
			for(int i=0;i<currentNode.getChildCount();i++){
				if(currentNode.getChildAt(i).getFile().equals(f)){
					currentNode = currentNode.getChildAt(i);
					treePath = treePath.pathByAddingChild(currentNode);
					found = true;
					break;
				}
			}
			if(!found)
				break;
		}
		treeSelectionListenerGateOpen = false;
		setSelectionPath(treePath);
		treeSelectionListenerGateOpen = true;
	}

	public void applyFilter(FileFilter filter){
		FileSystemTreeNode selectedNode = (FileSystemTreeNode)getSelectionPath().getLastPathComponent();
		File file = selectedNode.getFile();
		treeSelectionListenerGateOpen = false;
		((DefaultTreeModel)getModel()).setRoot(FileSystemTreeNode.getRootNode(filter));
		treeSelectionListenerGateOpen = true;
		if(file == null)
			setSelectionPath(new TreePath(getModel().getRoot()));
		else
			setSelectionPath(file);
	}

	@Override
	protected  void	processMouseEvent(MouseEvent e){
		//do nothing as the tree does not have to be editable with mouse
	}

	private void overwriteTreeKeystrokes() {
		/* overwrite the keys. up and down arrow are overwritten so that it loops when the top and the  */
		/* bottom are reached rather than getting stuck                                                 */ 

		/* Overwrite keystrokes up,down,left,right arrows and space, shift, ctrl */
		getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN,0),"down");
		getActionMap().put("down", new AbstractAction(){
			@Override
			public void actionPerformed(ActionEvent evt) {
				FileSystemTreeNode treeNode = (FileSystemTreeNode)getLastSelectedPathComponent();
				/* look if we've got a sibling node after (we are not at the bottom) */
				FileSystemTreeNode nextTreeNode = treeNode.getNextSibling(); 
				SoundEvent loop = null;
				if(nextTreeNode == null){
					TreeNode parent = treeNode.getParent();
					if(parent == null) /* root node, just stay there */
						nextTreeNode = treeNode;
					else /* loop = go to first child of own parent */
						nextTreeNode = (FileSystemTreeNode)parent.getChildAt(0);
					loop = SoundEvent.LIST_BOTTOM_REACHED;
				}

				final String speech = nextTreeNode.spokenText(); 
				treeSelectionListenerGateOpen = false;
				setSelectionPath(new TreePath(nextTreeNode.getPath()));
				treeSelectionListenerGateOpen = true;
				SoundFactory.getInstance().play(loop, new PlayerListener(){
					public void playEnded() {
						NarratorFactory.getInstance().speak(speech);
					}
				});
			}});

		/* Overwrite keystrokes up,down,left,right arrows and space, shift, ctrl */
		getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_UP,0),"up");
		getActionMap().put("up", new AbstractAction(){
			@Override
			public void actionPerformed(ActionEvent evt) {
				FileSystemTreeNode treeNode = (FileSystemTreeNode)getLastSelectedPathComponent();
				/* look if we've got a sibling node after (we are not at the bottom) */
				FileSystemTreeNode peviousTreeNode = treeNode.getPreviousSibling(); 
				SoundEvent loop = null;
				if(peviousTreeNode == null){
					TreeNode parent = treeNode.getParent();
					if(parent == null) /* root node, just stay there */
						peviousTreeNode = treeNode;
					else /* loop = go to first child of own parent */
						peviousTreeNode = (FileSystemTreeNode)parent.getChildAt(parent.getChildCount()-1);
					loop = SoundEvent.LIST_TOP_REACHED;
				}

				final String speech = peviousTreeNode.spokenText();
				treeSelectionListenerGateOpen = false;
				setSelectionPath(new TreePath(peviousTreeNode.getPath()));
				treeSelectionListenerGateOpen = true;
				SoundFactory.getInstance().play(loop, new PlayerListener(){
					public void playEnded() {
						NarratorFactory.getInstance().speak(speech);
					}
				});
			}});

		getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT,0),"left");
		getActionMap().put("left", new AbstractAction(){
			@Override
			public void actionPerformed(ActionEvent evt) {
				TreePath path = getSelectionPath();
				TreeNode treeNode = (TreeNode)path.getLastPathComponent();
				final FileSystemTreeNode parent = (FileSystemTreeNode)treeNode.getParent();
				if(parent == null){/* root node */
					SoundFactory.getInstance().play(SoundEvent.ERROR);
				}
				else{
					TreePath newPath = new TreePath(parent.getPath());
					treeSelectionListenerGateOpen = false;
					setSelectionPath(newPath);
					collapsePath(newPath);
					treeSelectionListenerGateOpen = true;
					SoundFactory.getInstance().play(SoundEvent.TREE_NODE_COLLAPSE,new PlayerListener(){
						@Override
						public void playEnded() {
							NarratorFactory.getInstance().speak(parent.spokenText());
						}
					});
				}
			}
		});

		getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT,0),"right");
		getActionMap().put("right", new AbstractAction(){
			@Override
			public void actionPerformed(ActionEvent evt) {
				TreePath path = getSelectionPath();
				TreeNode treeNode = (TreeNode)path.getLastPathComponent();
				if(treeNode.isLeaf()){/* leaf node */
					SoundFactory.getInstance().play(SoundEvent.ERROR);
				}
				else{
					expandPath(path);
					final FileSystemTreeNode firstChild = (FileSystemTreeNode)treeNode.getChildAt(0); 
					treeSelectionListenerGateOpen = false;
					setSelectionPath(new TreePath(firstChild.getPath()));
					treeSelectionListenerGateOpen = true;
					SoundFactory.getInstance().play(SoundEvent.TREE_NODE_EXPAND,new PlayerListener(){
						@Override
						public void playEnded() {
							NarratorFactory.getInstance().speak(firstChild.spokenText());
						}
					});
				}
			}
		});

		getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE,0),"space");
		getActionMap().put("space",new AbstractAction(){
			@Override
			public void actionPerformed(ActionEvent evt) {
				TreePath path = getSelectionPath();
				FileSystemTreeNode treeNode = (FileSystemTreeNode)path.getLastPathComponent();
				NarratorFactory.getInstance().speak(treeNode.toString());
			}
		});
		
		getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE,InputEvent.CTRL_DOWN_MASK), "ctrl_space");
		getActionMap().put("ctrl_space", new AbstractAction(){
			@Override
			public void actionPerformed(ActionEvent evt) {
				TreePath path = getSelectionPath();
				FileSystemTreeNode treeNode = (FileSystemTreeNode)path.getLastPathComponent();
				NarratorFactory.getInstance().speak(treeNode.getFile().getPath());
			}
		});
		/* make the tree ignore the page up and page down keys */
		getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP,0),"none");
		getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN,0),"none");
	}
	private boolean treeSelectionListenerGateOpen;
}

/**
 * This class  overwrites the default cell renderer in order to always render directories with a  
 * directory-icon regardless whether they are a leaf node or not. 
 *
 */
class FileSystemTreeCellRendered implements TreeCellRenderer {
	FileSystemTreeCellRendered(TreeCellRenderer delegate){
		this.delegate = delegate;
	}

	@Override
	public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, 
			boolean expanded, boolean leaf, int row, boolean hasFocus)  {
		if(leaf && ((FileSystemTreeNode)value).getFile().isDirectory() )
			return delegate.getTreeCellRendererComponent(tree, value, selected, expanded, false, row, hasFocus);
		return delegate.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
	}

	TreeCellRenderer delegate;
}