blob: b9f3f2d522e4bf7cd586a866301d70dd809b995c [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.groovy.grailsproject;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import javax.swing.Icon;
import javax.swing.event.ChangeListener;
import org.netbeans.api.java.project.JavaProjectConstants;
import org.netbeans.api.project.ProjectManager;
import org.netbeans.api.project.Sources;
import org.netbeans.api.project.SourceGroup;
import org.netbeans.api.queries.SharabilityQuery;
import org.netbeans.api.queries.VisibilityQuery;
import org.netbeans.modules.groovy.support.api.GroovySources;
import org.openide.filesystems.FileChangeAdapter;
import org.openide.filesystems.FileEvent;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileRenameEvent;
import org.openide.filesystems.FileStateInvalidException;
import org.openide.filesystems.FileSystem;
import org.openide.filesystems.FileUtil;
import org.openide.util.ChangeSupport;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
/**
*
* @author Martin Adamek
*/
public class GrailsSources extends FileChangeAdapter implements Sources {
// those are dirs in project root we already know and create specific source groups
public static final List KNOWN_FOLDERS = Arrays.asList(
"docs", // NOI18N
"grails-app", // NOI18N
"lib", // NOI18N
"scripts", // NOI18N
"src", // NOI18N
"test", // NOI18N
"web-app" // NOI18N
);
// those are dirs in grails-app root we already know and create specific source groups
public static final List KNOWN_FOLDERS_IN_GRAILS_APP = Arrays.asList(
"conf", // NOI18N
"controllers", // NOI18N
"domain", // NOI18N
"i18n", // NOI18N
"services", // NOI18N
"taglib", // NOI18N
"utils", // NOI18N
"views" // NOI18N
);
public static final List KNOWN_OR_IGNORED_FOLDERS_IN_TEST = Arrays.asList(
"unit", // NOI18N
"integration", // NOI18N
"reports" // NOI18N
);
// these are working folders that we should hide from the project tree:
public static final List IGNORED_FOLDERS_IN_GRAILS_APP = Arrays.asList(
"target", // NOI18N
"gradle" // NOI18N
);
private final FileObject projectDir;
private final GrailsProject project;
private final ChangeSupport changeSupport = new ChangeSupport(this);
private GrailsSources(GrailsProject project) {
this.project = project;
this.projectDir = project.getProjectDirectory();
}
static GrailsSources create(GrailsProject project) {
GrailsSources sources = new GrailsSources(project);
sources.startFSListener();
return sources;
}
private void startFSListener () {
try {
FileSystem fs = projectDir.getFileSystem();
fs.addFileChangeListener(FileUtil.weakFileChangeListener(this, fs));
} catch (FileStateInvalidException x) {
Exceptions.printStackTrace(x);
}
}
public SourceGroup[] getSourceGroups(String type) {
List<Group> result = new ArrayList<Group>();
if (Sources.TYPE_GENERIC.equals(type)) {
addGroup(projectDir, projectDir.getName(), result);
} else if (JavaProjectConstants.SOURCES_TYPE_JAVA.equals(type)) {
addGroup(SourceCategoryType.SRC_JAVA, "LBL_SrcJava", result);
} else if (GroovySources.SOURCES_TYPE_GROOVY.equals(type)) {
addGroup(SourceCategoryType.GRAILSAPP_CONF, "LBL_grails-app_conf", result);
addGroup(SourceCategoryType.GRAILSAPP_CONTROLLERS, "LBL_grails-app_controllers", result);
addGroup(SourceCategoryType.GRAILSAPP_DOMAIN, "LBL_grails-app_domain", result);
addGroup(SourceCategoryType.GRAILSAPP_SERVICES, "LBL_grails-app_services", result);
addGroup(SourceCategoryType.GRAILSAPP_TAGLIB, "LBL_grails-app_taglib", result);
addGroup(SourceCategoryType.GRAILSAPP_UTILS, "LBL_grails-app_utils", result);
addGroup(SourceCategoryType.SCRIPTS, "LBL_scripts", result);
addGroup(SourceCategoryType.SRC_GROOVY, "LBL_SrcGroovy", result);
addGroup(SourceCategoryType.TEST_INTEGRATION, "LBL_IntegrationTests", result);
addGroup(SourceCategoryType.TEST_UNIT, "LBL_UnitTests", result);
} else if (GroovySources.SOURCES_TYPE_GRAILS.equals(type)) {
addGroup(SourceCategoryType.LIB, "LBL_lib", result);
addGroup(SourceCategoryType.GRAILSAPP_I18N, "LBL_grails-app_i18n", result);
addGroup(SourceCategoryType.WEBAPP, "LBL_web-app", result);
addGroup(SourceCategoryType.GRAILSAPP_VIEWS, "LBL_grails-app_views", result);
addGroup(SourceCategoryType.TEMPLATES, "LBL_grails-templates", result);
} else if (GroovySources.SOURCES_TYPE_GRAILS_UNKNOWN.equals(type)) {
// plugins may reside in project dir
File pluginsDirFile = project.getBuildConfig().getProjectPluginsDir();
FileObject pluginsDir = pluginsDirFile == null ? null : FileUtil.toFileObject(
FileUtil.normalizeFile(pluginsDirFile));
File globalPluginsDirFile = project.getBuildConfig().getGlobalPluginsDir();
FileObject globalPluginsDir = globalPluginsDirFile == null ? null : FileUtil.toFileObject(
FileUtil.normalizeFile(globalPluginsDirFile));
for (FileObject child : projectDir.getChildren()) {
if (child.isFolder()
&& VisibilityQuery.getDefault().isVisible(child)
&& !KNOWN_FOLDERS.contains(child.getName())
&& !IGNORED_FOLDERS_IN_GRAILS_APP.contains(child.getName())
&& child != pluginsDir
&& child != globalPluginsDir) {
String name = child.getName();
addGroup(child, Character.toUpperCase(name.charAt(0)) + name.substring(1), result);
}
}
addGroup(SourceCategoryType.SRC_GWT, "LBL_SrcGwt", result);
addUnknownGroups(KNOWN_FOLDERS_IN_GRAILS_APP, result, "grails-app", null);
addUnknownGroups(KNOWN_OR_IGNORED_FOLDERS_IN_TEST, result, "test", "LBL_SomeTests");
}
return result.toArray(new SourceGroup[result.size()]);
}
public void addChangeListener(ChangeListener listener) {
changeSupport.addChangeListener(listener);
}
public void removeChangeListener(ChangeListener listener) {
changeSupport.removeChangeListener(listener);
}
@Override
public void fileDeleted(FileEvent fe) {
changeSupport.fireChange();
}
@Override
public void fileFolderCreated(FileEvent fe) {
changeSupport.fireChange();
}
@Override
public void fileRenamed(FileRenameEvent fe) {
changeSupport.fireChange();
}
private void addUnknownGroups(Collection<String> alreadyKnown, List<Group> result,
String relativePath, String bundleKey) {
FileObject folder = projectDir.getFileObject(relativePath);
if (folder != null) {
for (FileObject child : folder.getChildren()) {
if (child.isFolder()
&& VisibilityQuery.getDefault().isVisible(child)
&& !alreadyKnown.contains(child.getName())) {
String name = child.getName();
String localizedName = Character.toUpperCase(name.charAt(0)) + name.substring(1);
if (bundleKey != null) {
localizedName = NbBundle.getMessage(GrailsSources.class, bundleKey, localizedName);
}
addGroup(child, localizedName, result);
}
}
}
}
private void addGroup(FileObject fileObject, String displayName, List<Group> list) {
if (fileObject != null) {
list.add(new Group(fileObject, displayName));
}
}
private void addGroup(SourceCategoryType sourceCategory, String bundleLabel, List<Group> list) {
FileObject fileObject = projectDir.getFileObject(
project.getSourceCategoriesFactory().getSourceCategory(sourceCategory).getRelativePath()
);
if (fileObject != null) {
list.add(new Group(fileObject, NbBundle.getMessage(GrailsSources.class, bundleLabel)));
}
}
private final class Group implements SourceGroup {
private final FileObject loc;
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
private final String displayName;
public Group(FileObject loc, String displayName) {
this.loc = loc;
this.displayName = displayName;
}
public FileObject getRootFolder() {
return loc;
}
public String getName() {
String location = loc.getPath();
return location.length() > 0 ? location : "generic"; // NOI18N
}
public String getDisplayName() {
return displayName;
}
public Icon getIcon(boolean opened) {
return null;
}
public boolean contains(FileObject file) throws IllegalArgumentException {
if (file == loc) {
return true;
}
String path = FileUtil.getRelativePath(loc, file);
if (path == null) {
throw new IllegalArgumentException();
}
if (file.isFolder()) {
path += File.separator; // NOI18N
}
if (file.isFolder() && file != projectDir && ProjectManager.getDefault().isProject(file)) {
// #67450: avoid actually loading the nested project.
return false;
}
File f = FileUtil.toFile(file);
if (f != null && SharabilityQuery.getSharability(f) == SharabilityQuery.NOT_SHARABLE) {
return false;
} // else MIXED, UNKNOWN, or SHARABLE; or not a disk file
return true;
}
public void addPropertyChangeListener(PropertyChangeListener l) {
pcs.addPropertyChangeListener(l);
}
public void removePropertyChangeListener(PropertyChangeListener l) {
pcs.removePropertyChangeListener(l);
}
@Override
public String toString() {
return "GrailsSources.Group[name=" + getName() + ",rootFolder=" + getRootFolder() + "]"; // NOI18N
}
}
}