package org.netbeans.gradle.project.view; import java.awt.Image; import java.io.File; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Objects; import javax.swing.Action; import org.jtrim.utils.ExceptionHelper; import org.netbeans.gradle.project.NbGradleProject; import org.netbeans.gradle.project.NbIcons; import org.netbeans.gradle.project.api.nodes.SingleNodeFactory; import org.netbeans.gradle.project.model.NbGradleModel; import org.netbeans.gradle.project.script.CommonScripts; import org.netbeans.gradle.project.script.ScriptFileProvider; import org.netbeans.gradle.project.util.ListenerRegistrations; import org.netbeans.gradle.project.util.NbFileUtils; import org.netbeans.gradle.project.util.RefreshableChildren; import org.netbeans.gradle.project.util.StringUtils; import org.netbeans.spi.project.ui.PathFinder; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; import org.openide.nodes.AbstractNode; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.util.Lookup; import org.openide.util.lookup.Lookups; public final class ProjectScriptFilesNode extends AbstractNode { private final String caption; private final NbGradleProject project; public ProjectScriptFilesNode(String caption, NbGradleProject project) { this(caption, project, new ProjectScriptFilesChildFactory(project)); } private ProjectScriptFilesNode( String caption, NbGradleProject project, ProjectScriptFilesChildFactory childFactory) { this(caption, project, childFactory, Children.create(childFactory, true)); } private ProjectScriptFilesNode( String caption, NbGradleProject project, ProjectScriptFilesChildFactory childFactory, Children children) { super(children, createLookup(project.getScriptFileProvider(), childFactory, children)); ExceptionHelper.checkNotNullArgument(caption, "caption"); ExceptionHelper.checkNotNullArgument(project, "project"); this.caption = caption; this.project = project; setName(caption); } private static Lookup createLookup( ScriptFileProvider scriptProvider, ProjectScriptFilesChildFactory childFactory, Children children) { return Lookups.fixed( new ProjectScriptFileFinder(scriptProvider), NodeUtils.defaultNodeRefresher(children, childFactory)); } public static SingleNodeFactory getFactory(String caption, NbGradleProject project) { return new FactoryImpl(caption, project); } private Action openProjectFileAction(String name) { Path file = project.getProjectDirectoryAsPath().resolve(name); return new OpenAlwaysFileAction(file); } private static void addOpenFileAction(Path file, List<Action> actions) { if (file != null) { actions.add(new OpenAlwaysFileAction(file)); } } @Override public Action[] getActions(boolean context) { List<Action> actions = new ArrayList<>(5); NbGradleModel currentModel = project.currentModel().getValue(); if (currentModel.isRootProject()) { addOpenFileAction(currentModel.getSettingsFile(), actions); } addOpenFileAction(currentModel.getBuildFile().toPath(), actions); actions.add(openProjectFileAction(CommonScripts.GRADLE_PROPERTIES_NAME)); actions.add(null); actions.add(NodeUtils.getRefreshNodeAction(this)); return actions.toArray(new Action[actions.size()]); } @Override public Image getIcon(int type) { return NbIcons.getFolderIcon(); } @Override public Image getOpenedIcon(int type) { return NbIcons.getOpenFolderIcon(); } @Override public String getDisplayName() { return caption; } private static final class ProjectScriptFileFinder implements PathFinder { private final ScriptFileProvider scriptProvider; public ProjectScriptFileFinder(ScriptFileProvider scriptProvider) { ExceptionHelper.checkNotNullArgument(scriptProvider, "scriptProvider"); this.scriptProvider = scriptProvider; } private Node findNodeByFile(Node root, FileObject target) { String baseName = target.getNameExt(); boolean canBeFound = CommonScripts.GRADLE_PROPERTIES_NAME.equalsIgnoreCase(baseName) || scriptProvider.isScriptFileName(baseName); if (!canBeFound) { return null; } return NodeUtils.findFileChildNode(root.getChildren(), target); } @Override public Node findPath(Node root, Object target) { FileObject targetFile = NodeUtils.tryGetFileSearchTarget(target); return targetFile != null ? findNodeByFile(root, targetFile) : null; } } private static class ProjectScriptFilesChildFactory extends ChildFactory.Detachable<SingleNodeFactory> implements RefreshableChildren { private final NbGradleProject project; private final ListenerRegistrations listenerRefs; private volatile boolean createdOnce; public ProjectScriptFilesChildFactory(NbGradleProject project) { ExceptionHelper.checkNotNullArgument(project, "project"); this.project = project; this.listenerRefs = new ListenerRegistrations(); this.createdOnce = false; } @Override public void refreshChildren() { if (createdOnce) { refresh(false); } } @Override protected void addNotify() { Runnable refreshChildrenTask = new Runnable() { @Override public void run() { refreshChildren(); } }; listenerRefs.add(project.currentModel().addChangeListener(refreshChildrenTask)); listenerRefs.add(NbFileUtils.addDirectoryContentListener(project.getProjectDirectory(), refreshChildrenTask)); } @Override protected void removeNotify() { listenerRefs.unregisterAll(); } private void addFileObject( FileObject file, List<SingleNodeFactory> toPopulate) { SingleNodeFactory nodeFactory = NodeUtils.tryGetFileNode(file); if (nodeFactory != null) { toPopulate.add(nodeFactory); } } private void addGradleFile( FileObject file, List<SingleNodeFactory> toPopulate) { addGradleFile(file, file.getNameExt(), toPopulate); } private void addGradleFile( FileObject file, final String name, List<SingleNodeFactory> toPopulate) { SingleNodeFactory nodeFactory = NodeUtils.tryGetFileNode(file, name, NbIcons.getGradleIcon()); if (nodeFactory != null) { toPopulate.add(nodeFactory); } } private static File getLocalGradleProperties(NbGradleModel model) { return new File(model.getProjectDir(), CommonScripts.GRADLE_PROPERTIES_NAME); } private static FileObject tryGetLocalGradlePropertiesObj(NbGradleModel model) { File result = getLocalGradleProperties(model); return FileUtil.toFileObject(result); } private void readKeys(List<SingleNodeFactory> toPopulate) { NbGradleModel model = project.currentModel().getValue(); FileObject settingsGradle = model.tryGetSettingsFileObj(); if (settingsGradle != null && model.isRootProject()) { addGradleFile(settingsGradle, toPopulate); } FileObject buildGradle = model.tryGetBuildFileObj(); if (buildGradle != null) { addGradleFile(buildGradle, toPopulate); } FileObject propertiesFile = tryGetLocalGradlePropertiesObj(model); if (propertiesFile != null) { addFileObject(propertiesFile, toPopulate); } ScriptFileProvider scriptFileProvider = project.getScriptFileProvider(); List<FileObject> gradleFiles = new ArrayList<>(); for (FileObject file: project.getProjectDirectory().getChildren()) { if (file.equals(buildGradle) || file.equals(settingsGradle) || file.isFolder()) { continue; } if (scriptFileProvider.isScriptFileName(file.getNameExt())) { gradleFiles.add(file); } } Collections.sort(gradleFiles, new Comparator<FileObject>() { @Override public int compare(FileObject o1, FileObject o2) { return StringUtils.STR_CMP.compare(o1.getNameExt(), o2.getNameExt()); } }); for (FileObject file: gradleFiles) { addGradleFile(file, toPopulate); } } @Override protected boolean createKeys(List<SingleNodeFactory> toPopulate) { createdOnce = true; readKeys(toPopulate); return true; } @Override protected Node createNodeForKey(SingleNodeFactory key) { return key.createNode(); } } private static class FactoryImpl implements SingleNodeFactory { private final String caption; private final NbGradleProject project; private final File projectDir; public FactoryImpl(String caption, NbGradleProject project) { ExceptionHelper.checkNotNullArgument(caption, "caption"); ExceptionHelper.checkNotNullArgument(project, "project"); this.caption = caption; this.project = project; this.projectDir = project.getProjectDirectoryAsFile(); } @Override public Node createNode() { return new ProjectScriptFilesNode(caption, project); } @Override public int hashCode() { int hash = 5; hash = 61 * hash + Objects.hashCode(this.caption); hash = 61 * hash + Objects.hashCode(this.projectDir); return hash; } @Override public boolean equals(Object obj) { if (obj == null) return false; if (getClass() != obj.getClass()) return false; final FactoryImpl other = (FactoryImpl)obj; return Objects.equals(this.caption, other.caption) && Objects.equals(this.projectDir, other.projectDir); } } }