在 RCP 应用程序中更改项目性质

Change project nature in a RCP application

我的 RCP 应用程序中有一个扩展 CommonNavigator 的视图 class。我的应用程序工作区中的项目应根据它们在磁盘上的位置具有不同的图标:工作区本地存在的项目应与导入的项目具有不同的图标。

我通过在 plugin.xml 中定义两个项目性质来实现这一点:MyProjectNature 和 MyProjectNatureImported 具有不同的图标,并使用以下方法在性质之间相应地改变:

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());
        }
    }
}

当我从添加到工作区的 ResourceChangeListener 调用此方法时,我收到每个项目的错误消息,指出它已被锁定且无法编辑:

final IWorkspace lf_workspace = ResourcesPlugin.getWorkspace();
    lf_workspace.addResourceChangeListener(new IResourceChangeListener()
    {
        @Override
        public void resourceChanged(IResourceChangeEvent event)
        {
            updateProjectNature(lf_workspace);
        }
    });

但是当我创建一个每隔几秒运行一次的作业时,它就起作用了:

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);

我想仅在对工作区进行更改时调用该方法,而不是每秒调用该方法(以节省资源),但我不明白为什么会出现错误并且无法更改监听器的性质而工作没有问题。

有什么想法吗?

发送资源更改事件时工作区被锁定,因此侦听器无法进行任何更改。

您应该能够从您的侦听器提交单个作业,并使用计划规则延迟作业,直到工作区可用。您应该使用 WorkspaceJob 来确保更新是原子的。

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;
  }
} 

你在滥用项目性质。虽然您的实际问题可以通过额外的工作来解决,但它表明项目性质可能是实现不同图像的错误方法。

强调本地项目和导入项目等差异的指定方式是装饰器。装饰器允许您(几乎)装饰或交换元素的图像和文本,而不管它显示在何处。