/*******************************************************************************
* Copyright (c) 2004, 2008 John Krasnay and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* John Krasnay - initial API and implementation
*******************************************************************************/
package net.sf.vex.editor.config;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.Map;
import net.sf.vex.editor.VexPlugin;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.ui.IDecoratorManager;
import org.eclipse.ui.PlatformUI;
import org.xml.sax.SAXParseException;
/**
* Parses and registers Vex configuration objects in a Vex Plug-in project.
*/
public class PluginProjectBuilder extends IncrementalProjectBuilder {
public static final String ID = "net.sf.vex.editor.pluginBuilder"; //$NON-NLS-1$
public PluginProjectBuilder() {
}
protected IProject[] build(int kind, Map args, IProgressMonitor monitor)
throws CoreException {
IProject project = this.getProject();
final PluginProject pluginProject = PluginProject.get(project);
if (pluginProject == null) {
String message = MessageFormat.format(
Messages.getString("PluginProjectBuilder.notConfigSource"), //$NON-NLS-1$
new Object[] { project.getName() });
VexPlugin.getInstance().log(IStatus.ERROR, message);
return null;
}
boolean parseConfigXml;
IResourceDelta delta = this.getDelta(project);
if (kind == FULL_BUILD || delta == null) {
//System.out.println("PluginProjectBuilder.build (full) starts for project " + project.getName());
this.clean(null);
parseConfigXml = true;
} else { // incremental or auto build
//System.out.println("PluginProjectBuilder.build (incremental) starts for project " + project.getName());
parseConfigXml = (delta.findMember(new Path(PluginProject.PLUGIN_XML)) != null);
// If a resource is deleted, renamed, or moved, we'll update the
// config, but only if we're not going to parse it.
final boolean canUpdateConfig = !parseConfigXml;
IResourceDeltaVisitor visitor = new IResourceDeltaVisitor() {
public boolean visit(IResourceDelta delta) throws CoreException {
IResource resource = delta.getResource();
String path = resource.getProjectRelativePath().toString();
pluginProject.removeResource(path);
if (delta.getKind() == IResourceDelta.REMOVED) {
ConfigItem item = pluginProject.getItemForResource(path);
if (item == null) {
return true;
}
if (canUpdateConfig && (delta.getFlags() & IResourceDelta.MOVED_TO) > 0) {
// Resource was moved.
String newPath = delta.getMovedToPath().removeFirstSegments(1).toString();
item.setResourcePath(newPath);
} else {
// Resource deleted, so let's nuke the item from the config
pluginProject.remove(item);
}
try {
pluginProject.writeConfigXml();
} catch (Exception ex) {
String message = MessageFormat.format(
Messages.getString("PluginProjectBuilder.cantSaveFile"), //$NON-NLS-1$
new Object[] { PluginProject.PLUGIN_XML });
VexPlugin.getInstance().log(IStatus.ERROR, message, ex);
}
try {
// If auto-build is on this is unnecessary since
// another build will be triggered by us saving
// vex-plugin.xml above. This is just here in case
// we're not auto-building
pluginProject.saveState();
} catch (Exception ex) {
String message = MessageFormat.format(
Messages.getString("PluginProjectBuilder.cantSaveFile"), //$NON-NLS-1$
new Object[] { PluginProject.PROJECT_CONFIG_SER });
VexPlugin.getInstance().log(IStatus.WARNING, message, ex);
}
}
return true;
}
};
delta.accept(visitor);
}
IMarker[] oldMarkers = project.findMarkers(IMarker.PROBLEM, true, IResource.DEPTH_INFINITE);
IResource[] markedResources = new IResource[oldMarkers.length];
for (int i = 0; i < markedResources.length; i++) {
markedResources[i] = oldMarkers[i].getResource();
}
project.deleteMarkers(IMarker.PROBLEM, true, IResource.DEPTH_INFINITE);
this.getBuildProblemDecorator().update(markedResources);
ConfigRegistry registry = ConfigRegistry.getInstance();
try {
registry.lock();
if (parseConfigXml) {
IResource pluginXmlResource = this.getProject().getFile(PluginProject.PLUGIN_XML);
try {
if (pluginXmlResource.exists()) {
pluginProject.parseConfigXml();
} else {
pluginProject.removeAllItems();
String message = MessageFormat.format(
Messages.getString("PluginProjectBuilder.missingFile"), //$NON-NLS-1$
new Object[] { PluginProject.PLUGIN_XML });
this.flagError(this.getProject(), message);
}
} catch (SAXParseException ex) {
this.flagError(pluginXmlResource, ex.getLocalizedMessage(), ex.getLineNumber());
} catch (Exception ex) {
String message = MessageFormat.format(
Messages.getString("PluginProjectBuilder.parseError"), //$NON-NLS-1$
new Object[] { PluginProject.PLUGIN_XML });
VexPlugin.getInstance().log(IStatus.ERROR, message, ex); //$NON-NLS-1$
this.flagError(pluginXmlResource, ex.getLocalizedMessage());
}
}
IBuildProblemHandler problemHandler = new IBuildProblemHandler() {
public void foundProblem(BuildProblem problem) {
try {
IResource resource = getProject().getFile(problem.getResourcePath());
flagError(resource, problem.getMessage(), problem.getLineNumber());
} catch (CoreException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
pluginProject.parseResources(problemHandler);
// Write new config to SER file.
try {
pluginProject.saveState();
} catch (IOException ex) {
String message = MessageFormat.format(
Messages.getString("PluginProjectBuilder.cantSaveConfig"), //$NON-NLS-1$
new Object[] { project.getName() });
VexPlugin.getInstance().log(IStatus.WARNING, message, ex);
}
} finally {
registry.unlock();
}
registry.fireConfigChanged(new ConfigEvent(this));
return null;
}
protected void clean(IProgressMonitor monitor) throws CoreException {
ConfigRegistry registry = ConfigRegistry.getInstance();
try {
registry.lock();
PluginProject pluginProject = PluginProject.get(this.getProject());
if (pluginProject != null) {
pluginProject.cleanState();
pluginProject.removeAllItems();
pluginProject.removeAllResources();
registry.fireConfigChanged(new ConfigEvent(this));
}
} finally {
registry.unlock();
}
}
//======================================================== PRIVATE
private BuildProblemDecorator buildProblemDecorator;
private void flagError(IResource resource, String message) throws CoreException {
flagError(resource, message, -1);
}
private void flagError(IResource resource, String message, int lineNumber) throws CoreException {
IMarker marker = resource.createMarker(IMarker.PROBLEM);
if (marker.exists()) {
marker.setAttribute(IMarker.MESSAGE, message);
marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH);
marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
if (lineNumber > 0) {
marker.setAttribute(IMarker.LINE_NUMBER, lineNumber);
}
this.getBuildProblemDecorator().update(resource);
}
}
private BuildProblemDecorator getBuildProblemDecorator() {
if (this.buildProblemDecorator == null) {
IDecoratorManager dm = PlatformUI.getWorkbench().getDecoratorManager();
this.buildProblemDecorator = (BuildProblemDecorator) dm.getBaseLabelProvider(BuildProblemDecorator.ID);
}
return this.buildProblemDecorator;
}
}