I have in my RCP application a View that extends the CommonNavigator class. The projects in the workspace of my application should have different icons depending on their location on the disk: the projects that exist locally in the workspace should have a different icon from the projects that were imported.
I realised this by defining in the plugin.xml two project natures: MyProjectNature and MyProjectNatureImported with different icons and changing between the natures accordingly with the following method:
private void updateProjectNature(final IWorkspace lf_workspace)
{
String l_workspacePath = lf_workspace.getRoot().getLocation().toString();
IProject[] l_projectsInWorkspace = lf_workspace.getRoot().getProjects();
for (IProject l_project : l_projectsInWorkspace)
{
try
{
File l_projectFile = new File(l_workspacePath + l_project.getFullPath().toString());
final IProjectDescription l_projectDescription = l_project.getDescription();
final String[] l_currentNatures = l_projectDescription.getNatureIds();
final String[] l_newNatures = new String[l_currentNatures.length];
int l_index = 0;
if (l_projectFile.exists())
{
for (String l_nature : l_currentNatures)
{
if (l_nature.equals(MyProjectNatureImported.NATURE_ID))
{
l_newNatures[l_index] = MyProjectNature.NATURE_ID;
}
else
{
l_newNatures[l_index] = l_nature;
}
l_index++;
}
}
else
{
for (String l_nature : l_currentNatures)
{
if (l_nature.equals(MyProjectNature.NATURE_ID))
{
l_newNatures[l_index] = MyProjectNatureImported.NATURE_ID;
}
else
{
l_newNatures[l_index] = l_nature;
}
l_index++;
}
}
l_projectDescription.setNatureIds(l_newNatures);
l_project.setDescription(l_projectDescription, null);
}
catch (CoreException e)
{
LOGGER.warning("Error when setting the project nature of the project " + l_project.getName() + ": " + e.getMessage());
}
}
}
When I call this method from the ResourceChangeListener that I added to the workspace, I get an error for each project that it is locked and cannot be editted:
final IWorkspace lf_workspace = ResourcesPlugin.getWorkspace();
lf_workspace.addResourceChangeListener(new IResourceChangeListener()
{
@Override
public void resourceChanged(IResourceChangeEvent event)
{
updateProjectNature(lf_workspace);
}
});
But when I create a Job that runs each few seconds, then it works:
Job l_testJob = new Job("Update navigator")
{
@Override
protected IStatus run(IProgressMonitor monitor)
{
updateProjectNature(lf_workspace);
schedule(1000);
return Status.OK_STATUS;
}
@Override
public boolean shouldSchedule()
{
// Check if the job should be scheduled / executed or not
return !PlatformUI.getWorkbench().isClosing();
}
};
l_testJob.schedule(1000);
I would like to call the method only when changes are made to the workspace and not each second (to save the resources), but I don't understand why I get the error and cannot change the nature from the listener while from the job there is no problem.
Any ideas?
The workspace is locked while the resource change event is sent so that listeners can't make any more changes.
You should be able to submit a single Job from your listener with a scheduling rule to delay the job until the workspace is available. You should use a WorkspaceJob
to make sure the update is atomic.
class UpdateNatureJob extends WorkspaceJob
{
UpdateNatureJob()
{
// Scheduling rule
setRule(ResourcesPlugin.getWorkspace().getRoot());
}
@Override
public IStatus runInWorkspace(final IProgressMonitor monitor)
{
... your nature update
return Status.OK_STATUS;
}
}