package org.netbeans.gradle.project.view; import java.awt.Image; import java.awt.event.ActionEvent; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.StringTokenizer; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.AbstractAction; import javax.swing.Action; import org.jtrim.utils.ExceptionHelper; import org.netbeans.gradle.project.NbStrings; import org.netbeans.gradle.project.api.nodes.NodeRefresher; import org.netbeans.gradle.project.api.nodes.SingleNodeFactory; import org.netbeans.gradle.project.util.RefreshableChildren; import org.netbeans.spi.java.project.support.ui.PackageView; import org.netbeans.spi.project.ui.PathFinder; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; import org.openide.loaders.DataFolder; import org.openide.loaders.DataObject; import org.openide.loaders.DataObjectNotFoundException; import org.openide.nodes.Children; import org.openide.nodes.FilterNode; import org.openide.nodes.Node; import org.openide.nodes.NodeNotFoundException; import org.openide.nodes.NodeOp; public final class NodeUtils { private static final Logger LOGGER = Logger.getLogger(NodeUtils.class.getName()); public static NodeRefresher defaultNodeRefresher( final Children children, final RefreshableChildren childrenRefresher) { ExceptionHelper.checkNotNullArgument(children, "children"); ExceptionHelper.checkNotNullArgument(childrenRefresher, "childrenRefresher"); return new NodeRefresher() { @Override public void refreshNode() { childrenRefresher.refreshChildren(); NodeUtils.refreshChildNodes(children); } }; } public static Action getRefreshNodeAction(Node node) { return getRefreshNodeAction(node, NbStrings.getScanForChangesCaption()); } public static Action getRefreshNodeAction(final Node node, String caption) { ExceptionHelper.checkNotNullArgument(node, "node"); ExceptionHelper.checkNotNullArgument(caption, "caption"); return new RefreshNodeAction(caption, node); } public static void refreshChildNodes(Children children) { ExceptionHelper.checkNotNullArgument(children, "children"); for (Node child: children.getNodes(false)) { NodeRefresher refresher = child.getLookup().lookup(NodeRefresher.class); if (refresher != null) { refresher.refreshNode(); } } } public static FileObject tryGetFileSearchTarget(Object target) { if (target instanceof FileObject) { return (FileObject)target; } if (target instanceof DataObject) { return ((DataObject)target).getPrimaryFile(); } return null; } public static Node findFileChildNode(Children children, FileObject file) { ExceptionHelper.checkNotNullArgument(children, "children"); ExceptionHelper.checkNotNullArgument(file, "file"); for (Node child: children.getNodes(true)) { if (NodeUtils.isNodeOfFile(child, file)) { return child; } } return null; } public static boolean isNodeOfFile(Node node, FileObject file) { ExceptionHelper.checkNotNullArgument(node, "node"); ExceptionHelper.checkNotNullArgument(file, "file"); for (FileObject nodeFile: node.getLookup().lookupAll(FileObject.class)) { if (file.equals(nodeFile)) { return true; } } return false; } public static Node askChildrenPackageViewsForTarget(Children children, Object target) { ExceptionHelper.checkNotNullArgument(children, "children"); ExceptionHelper.checkNotNullArgument(target, "target"); for (Node child: children.getNodes(true)) { Node result = PackageView.findPath(child, target); if (result != null) { return result; } } return null; } public static Node askChildrenForTarget(Children children, Object target) { ExceptionHelper.checkNotNullArgument(children, "children"); ExceptionHelper.checkNotNullArgument(target, "target"); for (Node child: children.getNodes(true)) { for (PathFinder nodeFinder: child.getLookup().lookupAll(PathFinder.class)) { Node result = nodeFinder.findPath(child, target); if (result != null) { return result; } } } return null; } public static PathFinder childrenFileFinder() { return ChildrenFileFinder.INSTANCE; } public static PathFinder askChildrenNodeFinder() { return AskChildrenNodeFinder.INSTANCE; } public static PathFinder askChildrenPackageViewsFinder() { return AskChildrenPackageViewsFinder.INSTANCE; } public static Node findChildFileOfFolderNode(Node folderNode, FileObject file) { ExceptionHelper.checkNotNullArgument(folderNode, "folderNode"); ExceptionHelper.checkNotNullArgument(file, "file"); // Copied from the LogicalViewProvider implementation of the Maven plugin FileObject xfo = folderNode.getLookup().lookup(FileObject.class); if (xfo == null) { DataObject dobj = folderNode.getLookup().lookup(DataObject.class); if (dobj != null) { xfo = dobj.getPrimaryFile(); } } if (xfo != null) { if ((xfo.equals(file))) { return folderNode; } else if (FileUtil.isParentOf(xfo, file)) { FileObject folder = file.isFolder() ? file : file.getParent(); String relPath = FileUtil.getRelativePath(xfo, folder); List<String> path = new ArrayList<>(); StringTokenizer strtok = new StringTokenizer(relPath, "/"); while (strtok.hasMoreTokens()) { String token = strtok.nextToken(); path.add(token); } try { Node parentNode = folder.equals(xfo) ? folderNode : NodeOp.findPath(folderNode, Collections.enumeration(path)); if (file.isFolder()) { return parentNode; } else { Node[] childs = parentNode.getChildren().getNodes(true); for (Node child: childs) { DataObject dobj = child.getLookup().lookup(DataObject.class); if (dobj != null && dobj.getPrimaryFile().getNameExt().equals(file.getNameExt())) { return child; } } } } catch (NodeNotFoundException e) { // OK, never mind } } } return null; } public static DataObject tryGetDataObject(FileObject fileObj) { try { if (fileObj.isFolder()) { return DataFolder.findFolder(fileObj); } else { return DataObject.find(fileObj); } } catch (DataObjectNotFoundException ex) { LOGGER.log(Level.INFO, "Failed to find DataObject for file object: " + fileObj.getPath(), ex); return null; } } public static SingleNodeFactory tryGetFileNode(FileObject file) { return tryGetFileNode(file, file.getNameExt()); } public static SingleNodeFactory tryGetFileNode(FileObject file, final String name) { return tryGetFileNode(file, name, null); } public static SingleNodeFactory tryGetFileNode(FileObject file, final String name, final Image icon) { final DataObject fileData = tryGetDataObject(file); if (fileData == null) { return null; } return new FileObjNodeFactory(file.toURI(), fileData, name, icon); } private static final class FileObjNodeFactory implements SingleNodeFactory { private final Object fileDataKey; private final DataObject fileData; private final String name; private final Image icon; public FileObjNodeFactory( Object fileDataKey, DataObject fileData, String name, Image icon) { this.fileDataKey = fileDataKey; this.fileData = fileData; this.name = name; this.icon = icon; } @Override public Node createNode() { return new FilterNode(fileData.getNodeDelegate().cloneNode()) { @Override public boolean canRename() { return false; } @Override public String getDisplayName() { return name; } @Override public Image getIcon(int type) { return icon != null ? icon : super.getIcon(type); } @Override public Image getOpenedIcon(int type) { return icon != null ? icon : super.getOpenedIcon(type); } }; } @Override public int hashCode() { int hash = 7; hash = 83 * hash + Objects.hashCode(this.fileDataKey); hash = 83 * hash + Objects.hashCode(this.name); hash = 83 * hash + Objects.hashCode(this.icon); return hash; } @Override public boolean equals(Object obj) { if (obj == null) return false; if (getClass() != obj.getClass()) return false; final FileObjNodeFactory other = (FileObjNodeFactory)obj; return this.icon == other.icon && Objects.equals(this.name, other.name) && Objects.equals(this.fileDataKey, other.fileDataKey); } } private enum AskChildrenPackageViewsFinder implements PathFinder { INSTANCE; @Override public Node findPath(Node root, Object target) { return askChildrenPackageViewsForTarget(root.getChildren(), target); } } private enum AskChildrenNodeFinder implements PathFinder { INSTANCE; @Override public Node findPath(Node root, Object target) { return askChildrenForTarget(root.getChildren(), target); } } private NodeUtils() { throw new AssertionError(); } private enum ChildrenFileFinder implements PathFinder { INSTANCE; @Override public Node findPath(Node root, Object target) { FileObject targetFile = tryGetFileSearchTarget(target); return targetFile != null ? findFileChildNode(root.getChildren(), targetFile) : null; } } @SuppressWarnings("serial") private static class RefreshNodeAction extends AbstractAction { private final Node node; public RefreshNodeAction(String name, Node node) { super(name); this.node = node; } @Override public void actionPerformed(ActionEvent e) { NodeRefresher nodeRefresher = node.getLookup().lookup(NodeRefresher.class); if (nodeRefresher != null) { nodeRefresher.refreshNode(); } } } }