/**
* Aptana Studio
* Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the GNU Public License (GPL) v3 (with exceptions).
* Please see the license.html included with this distribution for details.
* Any modifications to this file must keep this entire header intact.
*/
package com.aptana.editor.php.internal.builder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import com.aptana.core.logging.IdeLog;
import com.aptana.editor.php.PHPEditorPlugin;
import com.aptana.editor.php.internal.core.builder.IBuildPathResource;
import com.aptana.editor.php.internal.core.builder.IDirectory;
import com.aptana.editor.php.internal.core.builder.IModule;
/**
* ProjectBuildPath
*
* @author Denis Denisenko
*/
public class ProjectBuildPath extends AbstractBuildPath
{
/**
* PHP elements delta visitor.
*
* @author Denis Denisenko
*/
private final class PHPElementsDeltaVisitor implements IResourceDeltaVisitor
{
/**
* Added modules to fill.
*/
private List<IModule> added;
/**
* Changed modules to fill.
*/
private List<IModule> changed;
/**
* Removed modules to fill.
*/
private List<IModule> removed;
/**
* Added modules to fill.
*/
private List<IDirectory> addedDirectories;
/**
* Removed modules to fill.
*/
private List<IDirectory> removedDirectories;
/**
* PHPElementsDeltaVisitor constructor.
*
* @param added
* - added modules list to fill.
* @param changed
* - changed modules list to fill.
* @param removed
* - removed modules list to fill.
*/
private PHPElementsDeltaVisitor(List<IModule> added, List<IModule> changed, List<IModule> removed,
List<IDirectory> addedDirectories, List<IDirectory> removedDirectories)
{
this.added = added;
this.changed = changed;
this.removed = removed;
this.addedDirectories = addedDirectories;
this.removedDirectories = removedDirectories;
}
/**
* {@inheritDoc}
*/
public boolean visit(IResourceDelta delta)
{
IResource resource = delta.getResource();
// ignoring inaccessible resources
if (!resource.isAccessible() && delta.getKind() != IResourceDelta.REMOVED)
{
return false;
}
if (resource instanceof IProject)
{
if (!resource.equals(project))
{
return false;
}
/*
* if (!project.isSynchronized(1)) { return false; }
*/
}
if (!(resource instanceof IFile || resource instanceof IFolder))
{
return true;
}
if (!resource.getProject().equals(project))
{
return false;
}
// we are not interested in flag changes.
if (delta.getFlags() == IResourceDelta.MARKERS)
{
return false;
}
if (resource instanceof IFile)
{
IModule module = null;
switch (delta.getKind())
{
case IResourceDelta.ADDED:
module = PHPLocalModuleFactory.getModule(resource, ProjectBuildPath.this);
if (module == null)
{
return true;
}
added.add(module);
if ((delta.getFlags() & IResourceDelta.MOVED_FROM) != 0)
{
IPath fromPath = delta.getMovedFromPath();
if (fromPath != null)
{
IFile fromFile = resource.getWorkspace().getRoot().getFile(fromPath);
if (fromFile != null)
{
IModule oldModule = PHPLocalModuleFactory.getModuleUnsafe(fromFile,
ProjectBuildPath.this);
if (oldModule != null)
{
removed.add(oldModule);
}
}
}
}
break;
case IResourceDelta.CHANGED:
module = PHPLocalModuleFactory.getModule(resource, ProjectBuildPath.this);
if (module == null)
{
return true;
}
changed.add(module);
break;
case IResourceDelta.REMOVED:
module = PHPLocalModuleFactory.getModuleUnsafe(resource, ProjectBuildPath.this);
if (module != null)
{
removed.add(module);
}
break;
default:
break;
}
}
else if (resource instanceof IFolder)
{
// skipping unsynchronized resources.
if (!resource.isSynchronized(1))
{
return true;
}
if (!FolderFilteringManager.acceptFolder((IFolder) resource))
{
return false;
}
IDirectory dir = new LocalDirectory((IFolder) resource, ProjectBuildPath.this);
switch (delta.getKind())
{
case IResourceDelta.ADDED:
addedDirectories.add(dir);
break;
case IResourceDelta.REMOVED:
removedDirectories.add(dir);
break;
default:
break;
}
}
return true;
}
}
/**
* Eclipse project.
*/
private IProject project;
/**
* Modules.
*/
private Map<IFile, IModule> modules = new HashMap<IFile, IModule>();
/**
* Directories.
*/
private Map<IContainer, IDirectory> directories = new HashMap<IContainer, IDirectory>();
/**
* Workspace listener.
*/
private IResourceChangeListener workspaceListener;
/**
* ProjectBuildPath constructor.
*
* @param project
* - eclipse project.
*/
public ProjectBuildPath(IProject project)
{
this.project = project;
IWorkspace workspace = ResourcesPlugin.getWorkspace();
indexLocalResources();
bindListeners(workspace);
}
/**
* {@inheritDoc}
*/
public List<IModule> getModules()
{
List<IModule> result = new ArrayList<IModule>();
result.addAll(modules.values());
return result;
}
/**
* {@inheritDoc}
*/
public void close()
{
IWorkspace workspace = ResourcesPlugin.getWorkspace();
if (workspace != null && workspaceListener != null)
{
workspace.removeResourceChangeListener(workspaceListener);
}
}
/**
* {@inheritDoc}
*/
public IModule getModule(Object moduleResource)
{
if (!(moduleResource instanceof IFile))
{
return null;
}
// this is possble in some cases
IModule module = modules.get(moduleResource);
if (module == null)
{
IFile f = (IFile) moduleResource;
if (f.getProject().equals(this.project))
{
IModule module2 = PHPLocalModuleFactory.getModule(f, this);
if (module2 != null)
{
modules.put(f, module2);
}
return module2;
}
}
return module;
}
/**
* {@inheritDoc}
*/
public IDirectory getDirectory(Object directoryResource)
{
if (directoryResource instanceof IProject && project.equals(directoryResource))
{
if (!((IProject) directoryResource).isAccessible())
{
return null;
}
return new LocalDirectory(project, this);
}
if (!(directoryResource instanceof IFolder))
{
return null;
}
return directories.get(directoryResource);
}
/**
* {@inheritDoc}
*/
public IPath getResourcePath(IBuildPathResource resource)
{
if (resource instanceof LocalModule)
{
IFile moduleFile = ((LocalModule) resource).getFile();
if (!project.equals(moduleFile.getProject()))
{
return null;
}
return moduleFile.getProjectRelativePath().makeAbsolute();
}
else if (resource instanceof LocalDirectory)
{
IResource fld = ((LocalDirectory) resource).getContainer();
if (!project.equals(fld.getProject()))
{
return null;
}
return fld.getProjectRelativePath().makeAbsolute();
}
return null;
}
/**
* {@inheritDoc}
*/
public IModule getModuleByPath(IPath path)
{
try
{
IResource resource = project.getFile(path);
if (resource == null)
{
return null;
}
return getModule(resource);
}
catch (Exception ex)
{
return null;
}
}
/**
* {@inheritDoc}
*/
public IDirectory getDirectoryByPath(IPath path)
{
if (path.segmentCount() == 0)
{
return new LocalDirectory(project, this);
}
// if (path.segmentCount() <= 2) {
// return null;
// }
IResource resource = project.getFolder(path);
if (resource == null)
{
return null;
}
return getDirectory(resource);
}
/**
* {@inheritDoc}
*/
public boolean isPassive()
{
return false;
}
/**
* Gets project.
*
* @return project.
*/
public IProject getProject()
{
return project;
}
/**
* {@inheritDoc}
*/
public List<IModule> getModulesByPath(IPath path)
{
IResource resource = null;
if (path.segmentCount() == 0)
{
resource = project;
}
else
{
resource = project.getFolder(path);
}
if (resource == null || !(resource instanceof IContainer) || !resource.exists())
{
return null;
}
IResource[] innerResources = null;
try
{
innerResources = ((IContainer) resource).members();
}
catch (CoreException e)
{
IdeLog.logWarning(PHPEditorPlugin.getDefault(),
"Error getting modules by path", e, PHPEditorPlugin.DEBUG_SCOPE); //$NON-NLS-1$
return null;
}
List<IFile> innerFiles = new ArrayList<IFile>();
for (IResource innerResource : innerResources)
{
if (innerResource instanceof IFile && ((IFile) innerResource).exists())
{
innerFiles.add((IFile) innerResource);
}
}
List<IModule> result = new ArrayList<IModule>();
for (IFile innerFile : innerFiles)
{
IModule currentModule = getModule(innerFile);
if (currentModule != null)
{
result.add(currentModule);
}
}
return result;
}
/**
* {@inheritDoc}
*/
public List<IDirectory> getSubdirectoriesByPath(IPath path)
{
IResource resource = null;
if (path.segmentCount() == 0)
{
resource = project;
}
else
{
resource = project.getFolder(path);
}
if (resource == null || !(resource instanceof IContainer) || !resource.exists())
{
return null;
}
IResource[] innerResources = null;
try
{
innerResources = ((IContainer) resource).members();
}
catch (CoreException e)
{
IdeLog.logWarning(PHPEditorPlugin.getDefault(),
"Error getting sub-directories by path", e, PHPEditorPlugin.DEBUG_SCOPE); //$NON-NLS-1$
return null;
}
List<IFolder> innerFolders = new ArrayList<IFolder>();
for (IResource innerResource : innerResources)
{
if (innerResource instanceof IFolder && ((IFolder) innerResource).exists())
{
innerFolders.add((IFolder) innerResource);
}
}
List<IDirectory> result = new ArrayList<IDirectory>();
for (IFolder innerFolder : innerFolders)
{
// ignoring inaccessible resources
if (!innerFolder.isAccessible())
{
continue;
}
IDirectory currentDir = new LocalDirectory(innerFolder, this);
result.add(currentDir);
}
return result;
}
/**
* {@inheritDoc}
*/
public boolean contains(IModule module)
{
if (!(module instanceof LocalModule))
{
return false;
}
return getModule(((LocalModule) module).getFile()) != null;
}
/**
* Binds required listeners.
*
* @param workspace
* - workspace.
*/
private void bindListeners(IWorkspace workspace)
{
workspaceListener = new IResourceChangeListener()
{
public void resourceChanged(IResourceChangeEvent event)
{
final List<IModule> added = new ArrayList<IModule>();
final List<IModule> changed = new ArrayList<IModule>();
final List<IModule> removed = new ArrayList<IModule>();
final List<IDirectory> addedDirectories = new ArrayList<IDirectory>();
final List<IDirectory> removedDirectories = new ArrayList<IDirectory>();
IResourceDelta delta = event.getDelta();
if (delta != null)
{
try
{
delta.accept(new PHPElementsDeltaVisitor(added, changed, removed, addedDirectories,
removedDirectories));
}
catch (CoreException e)
{
IdeLog.logWarning(PHPEditorPlugin.getDefault(),
"Error binding listeners", e, PHPEditorPlugin.DEBUG_SCOPE); //$NON-NLS-1$
}
}
Collection<IModule> modulesCollection = modules.values();
Collection<IDirectory> directoriesCollection = directories.values();
if (!added.isEmpty() || !removed.isEmpty() || !changed.isEmpty() || !addedDirectories.isEmpty()
|| !removedDirectories.isEmpty())
{
// List<IModule> emptyModules = Collections.emptyList();
// List<IDirectory> emptyDirectories = Collections.emptyList();
// first notifying about removed modules and directories BEFORE we actually remove
// them from the list
notifyChangedBefore(changed, removed, removedDirectories);
// removing modules
modulesCollection.removeAll(removed);
directoriesCollection.removeAll(removedDirectories);
// adding new modules
for (IModule currentModule : added)
{
if (currentModule instanceof LocalModule)
{
modules.put(((LocalModule) currentModule).getFile(), currentModule);
}
}
// adding directories
for (IDirectory dir : addedDirectories)
{
if (dir instanceof LocalDirectory)
{
directories.put(((LocalDirectory) dir).getContainer(), dir);
}
}
// notifying about added modules, added directories and changed modules after
// all additions are done
notifyChangedAfter(added, changed, removed, addedDirectories, removedDirectories);
}
}
};
workspace.addResourceChangeListener(workspaceListener);
}
/**
* Lists local modules.
*
* @param workspace
* - workspace.
*/
private void indexLocalResources()
{
try
{
project.accept(new IResourceVisitor()
{
public boolean visit(IResource resource)
{
// ignoring inaccessible resources
if (!resource.isAccessible())
{
return false;
}
if (resource instanceof IProject)
{
if (!resource.equals(project))
{
return false;
}
}
if (!resource.getProject().equals(project))
{
return false;
}
if (resource instanceof IFile)
{
IModule module = PHPLocalModuleFactory.getModule(resource, ProjectBuildPath.this);
if (module != null)
{
modules.put((IFile) resource, module);
}
}
else if (resource instanceof IFolder)
{
IDirectory dir = new LocalDirectory((IFolder) resource, ProjectBuildPath.this);
directories.put((IFolder) resource, dir);
}
return true;
}
});
}
catch (CoreException e)
{
IdeLog.logError(PHPEditorPlugin.getDefault(),
"Error indexing local resources", e, PHPEditorPlugin.INDEXER_SCOPE); //$NON-NLS-1$
}
}
public String getHandleIdentifier()
{
return 'P' + project.getName();
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj)
{
if (obj instanceof ProjectBuildPath)
{
return ((ProjectBuildPath) obj).project.equals(this.project);
}
return false;
}
/*
* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode()
{
return project.hashCode();
}
}