/**
* author: Marcel Genzmehr
* 18.08.2011
*/
package org.docear.plugin.core.workspace.node;
import java.awt.Component;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTargetDropEvent;
import java.io.File;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.Vector;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.DefaultTreeCellRenderer;
import org.docear.plugin.core.DocearController;
import org.docear.plugin.core.IBibtexDatabase;
import org.docear.plugin.core.IDocearLibrary;
import org.docear.plugin.core.event.DocearEvent;
import org.docear.plugin.core.event.DocearEventType;
import org.docear.plugin.core.event.IDocearEventListener;
import org.docear.plugin.core.workspace.actions.DocearLibraryNewMindmap;
import org.docear.plugin.core.workspace.actions.DocearLibraryOpenLocation;
import org.freeplane.core.util.LogUtils;
import org.freeplane.core.util.TextUtils;
import org.freeplane.features.mode.Controller;
import org.freeplane.plugin.workspace.WorkspaceController;
import org.freeplane.plugin.workspace.WorkspaceUtils;
import org.freeplane.plugin.workspace.components.menu.WorkspacePopupMenu;
import org.freeplane.plugin.workspace.components.menu.WorkspacePopupMenuBuilder;
import org.freeplane.plugin.workspace.dnd.IDropAcceptor;
import org.freeplane.plugin.workspace.dnd.IWorkspaceTransferableCreator;
import org.freeplane.plugin.workspace.dnd.WorkspaceTransferable;
import org.freeplane.plugin.workspace.event.IWorkspaceNodeActionListener;
import org.freeplane.plugin.workspace.event.WorkspaceActionEvent;
import org.freeplane.plugin.workspace.model.AWorkspaceTreeNode;
import org.freeplane.plugin.workspace.nodes.AFolderNode;
import org.freeplane.plugin.workspace.nodes.DefaultFileNode;
import org.freeplane.plugin.workspace.nodes.FolderLinkNode;
import org.freeplane.plugin.workspace.nodes.LinkTypeFileNode;
public class FolderTypeLibraryNode extends AFolderNode implements IDocearEventListener, IDocearLibrary, IWorkspaceNodeActionListener, IWorkspaceTransferableCreator, IDropAcceptor, TreeModelListener {
private static final Icon DEFAULT_ICON = new ImageIcon(FolderTypeLibraryNode.class.getResource("/images/folder-database.png"));
private static final long serialVersionUID = 1L;
private final Vector<URI> mindmapIndex = new Vector<URI>();
private final Vector<IBibtexDatabase> referencesIndex = new Vector<IBibtexDatabase>();
private final Set<FolderTypeProjectsNode> projectIndex = new HashSet<FolderTypeProjectsNode>();
private static WorkspacePopupMenu popupMenu = null;
/***********************************************************************************
* CONSTRUCTORS
**********************************************************************************/
public FolderTypeLibraryNode(String type) {
super(type);
DocearEvent event = new DocearEvent(this, DocearEventType.NEW_LIBRARY);
DocearController.getController().dispatchDocearEvent(event);
DocearController.getController().addDocearEventListener(this);
WorkspaceUtils.getModel().addTreeModelListener(this);
}
/***********************************************************************************
* METHODS
**********************************************************************************/
public void initializePopup() {
if (popupMenu == null) {
Controller controller = Controller.getCurrentController();
controller.addAction(new DocearLibraryNewMindmap());
controller.removeAction(new DocearLibraryOpenLocation().getKey());
controller.addAction(new DocearLibraryOpenLocation());
popupMenu = new WorkspacePopupMenu();
WorkspacePopupMenuBuilder.addActions(popupMenu, new String[] {WorkspacePopupMenuBuilder.createSubMenu(TextUtils.getRawText("workspace.action.new.label")),
"workspace.action.node.new.folder",
"workspace.action.node.new.link",
WorkspacePopupMenuBuilder.SEPARATOR,
"workspace.action.library.new.mindmap",
WorkspacePopupMenuBuilder.endSubMenu(),
WorkspacePopupMenuBuilder.SEPARATOR,
"workspace.action.node.open.location",
WorkspacePopupMenuBuilder.SEPARATOR,
"workspace.action.node.cut",
"workspace.action.node.copy",
"workspace.action.node.paste",
WorkspacePopupMenuBuilder.SEPARATOR,
"workspace.action.node.remove",
"workspace.action.file.delete",
WorkspacePopupMenuBuilder.SEPARATOR,
"workspace.action.node.refresh"
});
}
}
public boolean setIcons(DefaultTreeCellRenderer renderer) {
renderer.setOpenIcon(DEFAULT_ICON);
renderer.setClosedIcon(DEFAULT_ICON);
renderer.setLeafIcon(DEFAULT_ICON);
return true;
}
protected AWorkspaceTreeNode clone(FolderTypeLibraryNode node) {
for(IBibtexDatabase ref : referencesIndex) {
node.addReferenceToIndex(ref);
}
for(URI uri : mindmapIndex) {
node.addMindmapToIndex(uri);
}
return super.clone(node);
}
public AWorkspaceTreeNode clone() {
FolderTypeLibraryNode node = new FolderTypeLibraryNode(getType());
return clone(node);
}
protected void addMindmapToIndex(URI uri) {
mindmapIndex.add(uri);
}
protected void addReferenceToIndex(IBibtexDatabase ref) {
referencesIndex.clear();
if(ref == null) {
return;
}
referencesIndex.add(ref);
DocearEvent event = new DocearEvent(this, DocearEventType.LIBRARY_CHANGED, ref);
DocearController.getController().dispatchDocearEvent(event);
}
protected void addProjectToIndex(FolderTypeProjectsNode project) {
projectIndex.clear();
if(project == null) {
return;
}
projectIndex.add(project);
}
/**
* @param file
* @return
*/
private AWorkspaceTreeNode createFSNodeLinks(File file) {
AWorkspaceTreeNode node = null;
if(file.isDirectory()) {
FolderLinkNode pNode = new FolderLinkNode();
pNode.setPath(WorkspaceUtils.getWorkspaceRelativeURI(file));
node = pNode;
}
else {
LinkTypeFileNode lNode = new LinkTypeFileNode();
lNode.setLinkPath(WorkspaceUtils.getWorkspaceRelativeURI(file));
node = lNode;
}
node.setName(file.getName());
return node;
}
private void processWorkspaceNodeDrop(List<AWorkspaceTreeNode> nodes, int dropAction) {
try {
for(AWorkspaceTreeNode node : nodes) {
AWorkspaceTreeNode newNode = null;
if(node instanceof DefaultFileNode) {
newNode = createFSNodeLinks(((DefaultFileNode) node).getFile());
}
else {
if(dropAction == DnDConstants.ACTION_COPY) {
newNode = node.clone();
}
else if (dropAction == DnDConstants.ACTION_MOVE) {
AWorkspaceTreeNode parent = node.getParent();
WorkspaceUtils.getModel().cutNodeFromParent(node);
parent.refresh();
newNode = node;
}
}
if(newNode == null) {
continue;
}
WorkspaceUtils.getModel().addNodeTo(newNode, this);
WorkspaceController.getController().getExpansionStateHandler().addPathKey(this.getKey());
}
WorkspaceUtils.saveCurrentConfiguration();
}
catch (Exception e) {
LogUtils.warn(e);
}
refresh();
}
private void processFileListDrop(List<File> files, int dropAction) {
try {
for(File srcFile : files) {
WorkspaceUtils.getModel().addNodeTo(createFSNodeLinks(srcFile), this);
}
WorkspaceUtils.saveCurrentConfiguration();
}
catch (Exception e) {
LogUtils.warn(e);
}
refresh();
}
private void processUriListDrop(List<URI> uris, int dropAction) {
try {
for(URI uri : uris) {
File srcFile = new File(uri);
if(srcFile == null || !srcFile.exists()) {
continue;
}
WorkspaceUtils.getModel().addNodeTo(createFSNodeLinks(srcFile), this);
};
WorkspaceUtils.saveCurrentConfiguration();
}
catch (Exception e) {
LogUtils.warn(e);
}
refresh();
}
/***********************************************************************************
* REQUIRED METHODS FOR INTERFACES
**********************************************************************************/
public void handleEvent(DocearEvent event) {
if(event.getType() == DocearEventType.LIBRARY_NEW_MINDMAP_INDEXING_REQUEST) {
if(event.getEventObject() instanceof URI) {
URI uri = (URI) event.getEventObject();
if(!mindmapIndex.contains(uri)) {
LogUtils.info("DOCEAR: adding mindmap to library: "+ uri);
addMindmapToIndex(uri);
}
}
}
else if(event.getType() == DocearEventType.LIBRARY_NEW_REFERENCES_INDEXING_REQUEST) {
if(event.getEventObject() instanceof IBibtexDatabase) {
if(!referencesIndex.contains((IBibtexDatabase) event.getEventObject())) {
LogUtils.info("DOCEAR: adding reference database to library: "+ event.getEventObject());
addReferenceToIndex((IBibtexDatabase) event.getEventObject());
}
}
}
else if(event.getType() == DocearEventType.LIBRARY_EMPTY_MINDMAP_INDEX_REQUEST) {
mindmapIndex.removeAllElements();
}
else if(event.getType() == DocearEventType.LIBRARY_NEW_PROJECT_INDEXING_REQUEST) {
if(event.getEventObject() instanceof FolderTypeProjectsNode) {
if(!projectIndex.contains((FolderTypeProjectsNode) event.getEventObject())) {
LogUtils.info("DOCEAR: adding project to library: "+ event.getEventObject());
addProjectToIndex((FolderTypeProjectsNode) event.getEventObject());
}
}
}
}
public void handleAction(WorkspaceActionEvent event) {
if (event.getType() == WorkspaceActionEvent.MOUSE_RIGHT_CLICK) {
showPopup( (Component) event.getBaggage(), event.getX(), event.getY());
}
}
public List<URI> getMindmaps() {
return mindmapIndex;
}
public Set<FolderTypeProjectsNode> getProjects() {
return projectIndex;
}
public List<URI> getProjectPaths() {
List<URI> uriList= new ArrayList<URI>();
Iterator<FolderTypeProjectsNode> iter= projectIndex.iterator();
while(iter.hasNext()) {
uriList.add(iter.next().getPath());
}
return uriList;
}
public URI getBibtexDatabase() {
URI uri = null;
if(referencesIndex.size() > 0) {
return referencesIndex.get(0).getUri();
}
return uri;
}
public boolean acceptDrop(DataFlavor[] flavors) {
for(DataFlavor flavor : flavors) {
if(WorkspaceTransferable.WORKSPACE_FILE_LIST_FLAVOR.equals(flavor)
|| WorkspaceTransferable.WORKSPACE_URI_LIST_FLAVOR.equals(flavor)
|| WorkspaceTransferable.WORKSPACE_NODE_FLAVOR.equals(flavor)
) {
return true;
}
}
return false;
}
@SuppressWarnings("unchecked")
public boolean processDrop(Transferable transferable, int dropAction) {
try {
if(transferable.isDataFlavorSupported(WorkspaceTransferable.WORKSPACE_NODE_FLAVOR)) {
processWorkspaceNodeDrop((List<AWorkspaceTreeNode>) transferable.getTransferData(WorkspaceTransferable.WORKSPACE_NODE_FLAVOR), dropAction);
}
else if(transferable.isDataFlavorSupported(WorkspaceTransferable.WORKSPACE_FILE_LIST_FLAVOR)) {
processFileListDrop((List<File>) transferable.getTransferData(WorkspaceTransferable.WORKSPACE_FILE_LIST_FLAVOR), dropAction);
}
else if(transferable.isDataFlavorSupported(WorkspaceTransferable.WORKSPACE_URI_LIST_FLAVOR)) {
ArrayList<URI> uriList = new ArrayList<URI>();
String uriString = (String) transferable.getTransferData(WorkspaceTransferable.WORKSPACE_URI_LIST_FLAVOR);
if (!uriString.startsWith("file://")) {
return false;
}
String[] uriArray = uriString.split("\r\n");
for(String singleUri : uriArray) {
try {
uriList.add(URI.create(singleUri));
}
catch (Exception e) {
LogUtils.info("DOCEAR - "+ e.getMessage());
}
}
processUriListDrop(uriList, dropAction);
}
}
catch (Exception e) {
LogUtils.warn(e);
}
return true;
}
public boolean processDrop(DropTargetDropEvent event) {
event.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
Transferable transferable = event.getTransferable();
if(processDrop(transferable, event.getDropAction())) {
event.dropComplete(true);
return true;
}
event.dropComplete(false);
return false;
}
public Transferable getTransferable() {
return null;
}
public WorkspacePopupMenu getContextMenu() {
if (popupMenu == null) {
initializePopup();
}
return popupMenu;
}
public URI getPath() {
// this is a virtual folder, no path is needed
return null;
}
public URI getLibraryPath() {
return DocearController.getController().getLibraryPath();
}
public void treeNodesChanged(TreeModelEvent e) {
}
public void treeNodesInserted(TreeModelEvent event) {
if(this.getTreePath().isDescendant(event.getTreePath())) {
for(Object newNode : event.getChildren()) {
if(newNode instanceof DefaultFileNode) {
URI uri = ((DefaultFileNode)newNode).getFile().toURI();
addToIndex(uri);
}
else
if(newNode instanceof LinkTypeFileNode && ((LinkTypeFileNode)newNode).getLinkPath() != null) {
URI uri = WorkspaceUtils.absoluteURI(((LinkTypeFileNode)newNode).getLinkPath());
addToIndex(uri);
}
}
}
}
private void addToIndex(URI uri) {
if((new File(uri)).getName().endsWith(".mm") && !mindmapIndex.contains(uri)) {
LogUtils.info("DOCEAR: adding new mindmap to library: "+ uri);
mindmapIndex.add(uri);
}
}
public void treeNodesRemoved(TreeModelEvent event) {
//TODO: propagate other filetypes
if(this.getTreePath().isDescendant(event.getTreePath())) {
for(Object newNode : event.getChildren()) {
if(newNode instanceof DefaultFileNode) {
URI uri = ((DefaultFileNode)newNode).getFile().toURI();
removeFromIndex(uri);
}
else
if(newNode instanceof LinkTypeFileNode) {
URI uri = WorkspaceUtils.absoluteURI(((LinkTypeFileNode)newNode).getLinkPath());
removeFromIndex(uri);
}
}
}
}
private void removeFromIndex(URI uri) {
if((new File(uri)).getName().endsWith(".mm") && mindmapIndex.contains(uri)) {
LogUtils.info("DOCEAR: mindmap removed from library: "+ uri);
mindmapIndex.remove(uri);
}
}
public void treeStructureChanged(TreeModelEvent e) {
// TODO Auto-generated method stub
}
}