zoukankan      html  css  js  c++  java
  • Eclipse插件打开编辑器

       今天终于可以闲一天,想来想去就乱写点东西吧,说不定对有些新人有点帮助呢~_~


            用Eclipse API的方式来打开编辑器,可能对任何一个插件开发者都不是很陌生的操作了。但是,还是建议你忍着看一下,全当是复习吧~_~。
           
            【打开editor的接口讨论】
            先来看一下workbench吧,workbench从静态划分应该大致如下:
           
                从结构图我们大致就可以猜测出来,workbench page作为一个IWorkbenchPart(无论是eidtor part还是view part)的容器,肯定会接受workbench page的管理。看了一下,IWorkbenchPage接口定义中确实提供给了如下打开编辑器的操作:

                 【IWokbenchPage提供的接口】

     public interface IWorkbenchPage extends IPartService, ISelectionService,ICompatibleWorkbenchPage {
         
          public IEditorPart openEdito(IEditorInput input, String editorId)throws PartInitException;
          
          public IEditorPart openEdito(IEditorInput input, String editorId, boolean activate) throws PartInitException;
        
          public IEditorPart openEditor(final IEditorInput input, final String editorId, final boolean activate, final int matchFlags)throws PartInitException;
     }
              

                那到这边,可能很多人已经知道了怎么调用这些接口了:
               PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().openEditor(...)
              (说明:PlatformUI可以看作是整个eclipse ui框架的门面类,当然最核心的作用就是让用户获取到workbench。Eclipse中存在的其他一些门面类如:ResourcesPlugin、Platform、JavaCore、JavaUI等)

                我们再仔细看一下IWorkbenchPage对应的实现类(org.eclipse.ui.internal.WorkbenchPage)中的以上接口的实现代码,真正在管理Editor的是一个叫做EditorManager的东东(同理,view part对应的管理器角色类是叫做ViewFactory的东东)。这里的EditorManager和View Factory是workbench实现中非常精华的部分,看一下里面的实现就会很大程度上理解workbench所谓懒加载、懒初始化是如何实现的了,如何实现part 复用的...等等。 
                
               上图就用来说明workbench是如何来管理各种part的,其中descriptor角色的核心作用是延迟加载扩展(延迟加载用户通过editors或者views提供的扩展),reference角色的核心作用是用来延迟初时化具体的part(例如避免过早的创建对应的control等等)。再说下去有点偏离主题了,这部分,以后有时间再写
                
               【IDE工具类提供的接口】
                上面IWorkbenchPage提供接口都需要用户准备两样东西:一是创建IEditorInput实例,二是指定editor id。有些用户可能不想干这两件事情,所以在工具类org.eclipse.ui.ide.IDE中提供了其他的接口:
                

      public static IEditorPart openEditor(IWorkbenchPage page, IFile input) throws PartInitException { }
      
      public static IEditorPart openEditor(IWorkbenchPage page, IFile input, boolean activate) throws PartInitException {  }
      
      public static IEditorPart openEditor(IWorkbenchPage page, IFile input, boolean activate, boolean determineContentType) { }
      
      public static IEditorPart openEditor(IWorkbenchPage page, IFile input, String editorId) throws PartInitException {  }
      
      public static IEditorPart openEditor(IWorkbenchPage page, IFile input, String editorId, boolean activate) throws PartInitException {  }
     

               上面5个接口操作中, 对于上面的三个操作,Eclipse会自动为你准备IEditorInput实例,并动态绑定合适的编辑器类型。对于下面的两个操作,Eclipse会为你自动准备IEditorInput实例,但是需要用户自己指定editor id。
                
               接下来我们看两个问题,一是如何创建IEditorInput实例的;而是如何动态计算对应的editor id的。
               
              【有关FileEditorInput】
               在IDE工具类中提供的5个接受IFile对象的openEditor接口中,在对应的实现中都是默认构造了一个FileEditorInput(org.eclipse.ui.part.FileEditorInput)实例,这个实例也是org.eclipse.ui.IFileEditorInput接口的默认实现类(注意:Eclipse中很多地方都使用这种Interface/Default Impl的方式,Interface会暴露,Default Impl则根据情况选择是否暴露,一般是如果Interface希望用户来扩展继承,则会暴露对应的Default Impl,如果Interface不希望用户来扩展继承,例如IResource系列接口,则一般会将Default Impl丢如对应的internal包中)。
                我们看一下org.eclipse.ui.part.FileEditorInput中是如何实现IEditorInput.exists()接口的:

     public class FileEditorInput implements IFileEditorInput,IPathEditorInput,IPersistableElement {
         private IFile file;
     
         public boolean exists() {
             return file.exists();
         }
     }

              我们看到内部的实现是持有了IFile句柄,如果IFile代表的资源没有存在于工作区之内,那么就会返回false。(疑问:如果我们打开工作区外部的文件呢???显然,FileEditorInput并不合适,稍后看...)
            
            【动态计算editor id】
             下面,我们再来看一下IDE类是如何计算所谓的默认eidtor id的。追踪实现,我们看到了IDE.getDefaultEditor
              

       public static IEditorDescriptor getDefaultEditor(IFile file, boolean determineContentType) {
              // Try file specific editor.
              IEditorRegistry editorReg = PlatformUI.getWorkbench()
                      .getEditorRegistry();
              try {
                  String editorID = file.getPersistentProperty(EDITOR_KEY);
                  if (editorID != null) {
                     IEditorDescriptor desc = editorReg.findEditor(editorID);
                     if (desc != null) {
                         return desc;
                     }
                 }
             } catch (CoreException e) {
                 // do nothing
             }
             
             IContentType contentType = null;
             if (determineContentType) {
                 contentType = getContentType(file);
             }    
             // Try lookup with filename
             return editorReg.getDefaultEditor(file.getName(), contentType);
         }

                上面的代码大致赶了如下两件事情:
                1、如果对应的资源设定了一个特定的持久化属性EDITOR_KEY,则会使用EDITOR_KEY属性值所代表的编辑器(说明:有关Eclipse资源的属性支持,请参阅其他文档)。那如果一个资源不在工作区之内,又如何设定EDITOR_KEY属性呢???  (~_~确实没法设定)
               2、查找对应的content type,用户通过org.eclipse.core.runtime.contentTypes扩展点来注册自定义的内容类型,在内容类型中会指定对应的文件扩展名和默认编码,例如JDT中注册了如下内容类型(摘自org.eclipse.jdt.core/plugin.xml):

    <!-- =================================================================================== -->
    <!-- Extension: Java Content Types                                                       -->
    <!-- =================================================================================== -->
    <extension point="org.eclipse.core.runtime.contentTypes">
        <!-- declares a content type for Java Properties files -->
        <content-type id="javaProperties" name="%javaPropertiesName" 
            base-type="org.eclipse.core.runtime.text"
            priority="high"                
            file-extensions="properties"
            default-charset="ISO-8859-1"/>
        <!-- Associates .classpath to the XML content type -->
        <file-association 
            content-type="org.eclipse.core.runtime.xml" 
            file-names=".classpath"/>  
        <!-- declares a content type for Java Source files -->
        <content-type id="javaSource" name="%javaSourceName" 
            base-type="org.eclipse.core.runtime.text"
            priority="high"                
            file-extensions="java"/>
        <!-- declares a content type for Java class files -->
        <content-type id="javaClass" name="%javaClassName" 
            priority="high"                
            file-extensions="class">        
            <describer
                class="org.eclipse.core.runtime.content.BinarySignatureDescriber">
                <parameter name="signature" value="CA, FE, BA, BE"/>
            </describer>
        </content-type>        
        <!-- declares a content type for JAR manifest files -->
        <content-type id="JARManifest" name="%jarManifestName" 
            base-type="org.eclipse.core.runtime.text"
            priority="high"                
            file-names="MANIFEST.MF"
            default-charset="UTF-8"/>
    </extension>

                 那如果我们在注册编辑器的时候和对应的content type绑定,这不就联系起来了吗~_~。那我们看一下java源码编辑器扩展描述(摘自org.eclipse.jdt.ui/plugin.xml):

        <editor
                name="%JavaEditor.label"
                default="true"
                icon="$nl$/icons/full/obj16/jcu_obj.gif"
                contributorClass="org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitEditorActionContributor"
                class="org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitEditor"
                symbolicFontName="org.eclipse.jdt.ui.editors.textfont"
                id="org.eclipse.jdt.ui.CompilationUnitEditor">
                <contentTypeBinding
                   contentTypeId="org.eclipse.jdt.core.javaSource"
                /> 
          </editor>

               我们看到上面的xml中有contentTypeBinding元素,里面指定了绑定java源码content type。

                那如果我们在注册编辑器的时候,没有绑定对应的content type呢?Eclipse允许你配置,往下看:

                
                

                我想看到这边对eclipse如何动态计算一个文件对应的editor应该是明白了吧,再回顾一下吧:
                1、查看资源本身是否有EIDTOR_ID持久属性(注意:一、只有工作区中存在的资源才允许设置持久属性;二、资源属性知识针对特定资源,不会影响同类型资源,即你对工作区中特定的.java文件设定了EIDTOR_ID持久属性,并不会影响工作区中其他.java文件资源的编辑器绑定操作)
                2、查找对应的content type,然后查找对应的editor扩展或者查找Eclipse中的Content Types和File Associations配置
                3、如果都找不到,则直接给一个默认的编辑器。例如,我们经常碰到是"org.eclipse.ui.DefaultTextEditor"

                【IDE工具类提供的接口 VS  IWorkbenchPage提供的接口】
                  看一下以上提到的各个角色之间的调用关系图吧:
                  

            【使用Eclipse提供的打开editor的接口】
            还是那句话,需求决定一切。我们看一下打开编辑器的需求:
            1、打开工作区中工程内的文件资源
            2、打开工作区.metadata目录中的文件资源
            3、打开工作区外部的文件资源

            【说明】Eclipse工作区实际上是有数据区和元数据区两个区域组成的,示意如下:
            
                
                对于Eclipse来说,.metadata目录下存放的是插件运行时的关键状态数据,不建议用户再工作区实例运行期间做相应修改,为此eclipse干了两件事情:1、运行期间会自动在.metadata目录下产生一个进程锁定的.lock文件;2、Eclipse不允许用户通过IResource系列接口直接访问或修改.meatadata目录下的资源

               【打开工作区工程内的资源】
                 假设工作区中有测试工程TestProject,工程下有文本文件java_file.txt。对应创建代码如下:

          try {
                  //创建工程
                  IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject("TestProject");
                  if (!project.exists())
                      project.create(null);
                  if (!project.isOpen())
                      project.open(null);
                  
                  //创建文件
                 IFile java_file = project.getFile(new Path("/java_file.txt"));
                 InputStream inputStreamJava = new ByteArrayInputStream("class MyType{}".getBytes());
                 if (!java_file.exists())
                     java_file.create(inputStreamJava, false, null);
             } catch (CoreException e) {
                 IStatus status = new Status(IStatus.ERROR, "myplugin", 101, "创建资源失败", e);
                 Activator.getDefault().getLog().log(status);
             }

                
            
            打开方式一:Eclipse默认计算对应的editor id,会用default text editor打开 

           try {
                  IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
                  IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject("TestProject");
                  
                  IFile java_file = project.getFile(new Path("/java_file.txt"));
                  IDE.openEditor(page, java_file);            
              } catch (CoreException e) {
                  IStatus status = new Status(IStatus.ERROR, "myplugin", 102, "打开工作区内文件出错", e);
                  Activator.getDefault().getLog().log(status);
              }


            打开方式二:指定java源码编辑器打开,会用java源码编辑器打开

          try {
                  IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
                  IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject("TestProject");
                  
                  IFile java_file = project.getFile(new Path("/java_file.txt"));
                  IDE.openEditor(page, java_file, "org.eclipse.jdt.ui.CompilationUnitEditor");
              } catch (CoreException e) {
                  IStatus status = new Status(IStatus.ERROR, "myplugin", 102, "打开工作区内文件出错", e);
                  Activator.getDefault().getLog().log(status);
              }

               打开方式三:设定editor id属性,该文件以后默认都用此editor id打开

         try {
                 IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
                 IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject("TestProject");
                 
                 IFile java_file = project.getFile(new Path("/java_file.txt"));
                 java_file.setPersistentProperty(IDE.EDITOR_KEY, "org.eclipse.jdt.ui.CompilationUnitEditor");
                 IDE.openEditor(page, java_file);
             } catch (CoreException e) {
                 IStatus status = new Status(IStatus.ERROR, "myplugin", 102, "打开工作区内文件出错", e);
                 Activator.getDefault().getLog().log(status);
             }


            说明:对于工作区工程内的资源,可以有两种方式:一是local的,那就是物理存在与工程之内;二是link进入的。打开编辑器的时候,不需要做区分。

            【打开工作区外部的资源】
            说明:既存在于工作区外部,同时又没有被link进工程。
            
            在Eclipse中有个功能,就是File->Open File,可以打开一个外部文件。那我们看一下它是怎么实现的。我们只需要打开对应的对话框,然后挂起主线程,就可以找到对应的action了(挂起线程可以帮我们很方便的调试很多类型的问题,以后细说~_~):
                          

               分析一下OpenExternalFileAction的实现,我们发现它自己构建了一个editor input

  • 相关阅读:
    解决ListView异步加载数据之后不能点击的问题
    android点击实现图片放大缩小 java技术博客
    关于 数据文件自增长 的一点理解
    RAC 实例不能启动 ORA1589 signalled during ALTER DATABASE OPEN
    Linux 超级用户的权利
    RAC 实例 迁移到 单实例 使用导出导入
    Shell 基本语法
    Linux 开机引导与关机过程
    RAC 实例不能启动 ORA1589 signalled during ALTER DATABASE OPEN
    Oracle RAC + Data Guard 环境搭建
  • 原文地址:https://www.cnblogs.com/Soy-technology/p/11383174.html
Copyright © 2011-2022 走看看