Live a simple life

          沉默(zhu_xing@live.cn)
          隨筆 - 48, 文章 - 0, 評論 - 132, 引用 - 0
          數(shù)據(jù)加載中……

          【Eclipse插件開發(fā)】打開編輯器


                  今天終于可以閑一天,想來想去就亂寫點東西吧,說不定對有些新人有點幫助呢~_~
                  用Eclipse API的方式來打開編輯器,可能對任何一個插件開發(fā)者都不是很陌生的操作了。但是,還是建議你忍著看一下,全當(dāng)是復(fù)習(xí)吧~_~。
                 
                  【打開editor的接口討論】
                  先來看一下workbench吧,workbench從靜態(tài)劃分應(yīng)該大致如下:
                 
                      從結(jié)構(gòu)圖我們大致就可以猜測出來,workbench page作為一個IWorkbenchPart(無論是eidtor part還是view part)的容器,肯定會接受workbench page的管理。看了一下,IWorkbenchPage接口定義中確實提供給了如下打開編輯器的操作:

                       【IWokbenchPage提供的接口】
          1 public interface IWorkbenchPage extends IPartService, ISelectionService,ICompatibleWorkbenchPage {
          2     
          3      public IEditorPart openEdito(IEditorInput input, String editorId)throws PartInitException;
          4      
          5      public IEditorPart openEdito(IEditorInput input, String editorId, boolean activate) throws PartInitException;
          6    
          7      public IEditorPart openEditor(final IEditorInput input, final String editorId, final boolean activate, final int matchFlags)throws PartInitException;
          8 }
                    
                      那到這邊,可能很多人已經(jīng)知道了怎么調(diào)用這些接口了:
                     PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().openEditor(...)
                    (說明:PlatformUI可以看作是整個eclipse ui框架的門面類,當(dāng)然最核心的作用就是讓用戶獲取到workbench。Eclipse中存在的其他一些門面類如:ResourcesPlugin、Platform、JavaCore、JavaUI等)

                      我們再仔細(xì)看一下IWorkbenchPage對應(yīng)的實現(xiàn)類(org.eclipse.ui.internal.WorkbenchPage)中的以上接口的實現(xiàn)代碼,真正在管理Editor的是一個叫做EditorManager的東東(同理,view part對應(yīng)的管理器角色類是叫做ViewFactory的東東)。這里的EditorManager和View Factory是workbench實現(xiàn)中非常精華的部分,看一下里面的實現(xiàn)就會很大程度上理解workbench所謂懶加載、懶初始化是如何實現(xiàn)的了,如何實現(xiàn)part 復(fù)用的...等等。 
                      
                     上圖就用來說明workbench是如何來管理各種part的,其中descriptor角色的核心作用是延遲加載擴(kuò)展(延遲加載用戶通過editors或者views提供的擴(kuò)展),reference角色的核心作用是用來延遲初時化具體的part(例如避免過早的創(chuàng)建對應(yīng)的control等等)。再說下去有點偏離主題了,這部分,以后有時間再寫
                      
                     【IDE工具類提供的接口】
                      上面IWorkbenchPage提供接口都需要用戶準(zhǔn)備兩樣?xùn)|西:一是創(chuàng)建IEditorInput實例,二是指定editor id。有些用戶可能不想干這兩件事情,所以在工具類org.eclipse.ui.ide.IDE中提供了其他的接口:
                      
           1 public static IEditorPart openEditor(IWorkbenchPage page, IFile input) throws PartInitException { }
           2 
           3 public static IEditorPart openEditor(IWorkbenchPage page, IFile input, boolean activate) throws PartInitException {  }
           4 
           5 public static IEditorPart openEditor(IWorkbenchPage page, IFile input, boolean activate, boolean determineContentType) { }
           6 
           7 public static IEditorPart openEditor(IWorkbenchPage page, IFile input, String editorId) throws PartInitException {  }
           8 
           9 public static IEditorPart openEditor(IWorkbenchPage page, IFile input, String editorId, boolean activate) throws PartInitException {  }
          10 
          11 
                     上面5個接口操作中, 對于上面的三個操作,Eclipse會自動為你準(zhǔn)備IEditorInput實例,并動態(tài)綁定合適的編輯器類型。對于下面的兩個操作,Eclipse會為你自動準(zhǔn)備IEditorInput實例,但是需要用戶自己指定editor id。
                      
                     接下來我們看兩個問題,一是如何創(chuàng)建IEditorInput實例的;而是如何動態(tài)計算對應(yīng)的editor id的。
                     
                    【有關(guān)FileEditorInput】
                     在IDE工具類中提供的5個接受IFile對象的openEditor接口中,在對應(yīng)的實現(xiàn)中都是默認(rèn)構(gòu)造了一個FileEditorInput(org.eclipse.ui.part.FileEditorInput)實例,這個實例也是org.eclipse.ui.IFileEditorInput接口的默認(rèn)實現(xiàn)類(注意:Eclipse中很多地方都使用這種Interface/Default Impl的方式,Interface會暴露,Default Impl則根據(jù)情況選擇是否暴露,一般是如果Interface希望用戶來擴(kuò)展繼承,則會暴露對應(yīng)的Default Impl,如果Interface不希望用戶來擴(kuò)展繼承,例如IResource系列接口,則一般會將Default Impl丟如對應(yīng)的internal包中)。
                      我們看一下org.eclipse.ui.part.FileEditorInput中是如何實現(xiàn)IEditorInput.exists()接口的:
          1 public class FileEditorInput implements IFileEditorInput,IPathEditorInput,IPersistableElement {
          2     private IFile file;
          3 
          4     public boolean exists() {
          5         return file.exists();
          6     }
          7 }
                    我們看到內(nèi)部的實現(xiàn)是持有了IFile句柄,如果IFile代表的資源沒有存在于工作區(qū)之內(nèi),那么就會返回false。(疑問:如果我們打開工作區(qū)外部的文件呢???顯然,F(xiàn)ileEditorInput并不合適,稍后看...)
                  
                  【動態(tài)計算editor id】
                   下面,我們再來看一下IDE類是如何計算所謂的默認(rèn)eidtor id的。追蹤實現(xiàn),我們看到了IDE.getDefaultEditor
                    
           1  public static IEditorDescriptor getDefaultEditor(IFile file, boolean determineContentType) {
           2         // Try file specific editor.
           3         IEditorRegistry editorReg = PlatformUI.getWorkbench()
           4                 .getEditorRegistry();
           5         try {
           6             String editorID = file.getPersistentProperty(EDITOR_KEY);
           7             if (editorID != null) {
           8                 IEditorDescriptor desc = editorReg.findEditor(editorID);
           9                 if (desc != null) {
          10                     return desc;
          11                 }
          12             }
          13         } catch (CoreException e) {
          14             // do nothing
          15         }
          16         
          17         IContentType contentType = null;
          18         if (determineContentType) {
          19             contentType = getContentType(file);
          20         }    
          21         // Try lookup with filename
          22         return editorReg.getDefaultEditor(file.getName(), contentType);
          23     }
                      上面的代碼大致趕了如下兩件事情:
                      1、如果對應(yīng)的資源設(shè)定了一個特定的持久化屬性EDITOR_KEY,則會使用EDITOR_KEY屬性值所代表的編輯器(說明:有關(guān)Eclipse資源的屬性支持,請參閱其他文檔)。那如果一個資源不在工作區(qū)之內(nèi),又如何設(shè)定EDITOR_KEY屬性呢???  (~_~確實沒法設(shè)定)
                     2、查找對應(yīng)的content type,用戶通過org.eclipse.core.runtime.contentTypes擴(kuò)展點來注冊自定義的內(nèi)容類型,在內(nèi)容類型中會指定對應(yīng)的文件擴(kuò)展名和默認(rèn)編碼,例如JDT中注冊了如下內(nèi)容類型(摘自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>
                       那如果我們在注冊編輯器的時候和對應(yīng)的content type綁定,這不就聯(lián)系起來了嗎~_~。那我們看一下java源碼編輯器擴(kuò)展描述(摘自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。

                      那如果我們在注冊編輯器的時候,沒有綁定對應(yīng)的content type呢?Eclipse允許你配置,往下看:

                      
                      

                      我想看到這邊對eclipse如何動態(tài)計算一個文件對應(yīng)的editor應(yīng)該是明白了吧,再回顧一下吧:
                      1、查看資源本身是否有EIDTOR_ID持久屬性(注意:一、只有工作區(qū)中存在的資源才允許設(shè)置持久屬性;二、資源屬性知識針對特定資源,不會影響同類型資源,即你對工作區(qū)中特定的.java文件設(shè)定了EIDTOR_ID持久屬性,并不會影響工作區(qū)中其他.java文件資源的編輯器綁定操作)
                      2、查找對應(yīng)的content type,然后查找對應(yīng)的editor擴(kuò)展或者查找Eclipse中的Content Types和File Associations配置
                      3、如果都找不到,則直接給一個默認(rèn)的編輯器。例如,我們經(jīng)常碰到是"org.eclipse.ui.DefaultTextEditor"

                      【IDE工具類提供的接口 VS  IWorkbenchPage提供的接口】
                        看一下以上提到的各個角色之間的調(diào)用關(guān)系圖吧:
                        

                  【使用Eclipse提供的打開editor的接口】
                  還是那句話,需求決定一切。我們看一下打開編輯器的需求:
                  1、打開工作區(qū)中工程內(nèi)的文件資源
                  2、打開工作區(qū).metadata目錄中的文件資源
                  3、打開工作區(qū)外部的文件資源

                  【說明】Eclipse工作區(qū)實際上是有數(shù)據(jù)區(qū)和元數(shù)據(jù)區(qū)兩個區(qū)域組成的,示意如下:
                  
                      
                      對于Eclipse來說,.metadata目錄下存放的是插件運(yùn)行時的關(guān)鍵狀態(tài)數(shù)據(jù),不建議用戶再工作區(qū)實例運(yùn)行期間做相應(yīng)修改,為此eclipse干了兩件事情:1、運(yùn)行期間會自動在.metadata目錄下產(chǎn)生一個進(jìn)程鎖定的.lock文件;2、Eclipse不允許用戶通過IResource系列接口直接訪問或修改.meatadata目錄下的資源

                     【打開工作區(qū)工程內(nèi)的資源】
                      
          假設(shè)工作區(qū)中有測試工程TestProject,工程下有文本文件java_file.txt。對應(yīng)創(chuàng)建代碼如下:
                      
           1 try {
           2             //創(chuàng)建工程
           3             IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject("TestProject");
           4             if (!project.exists())
           5                 project.create(null);
           6             if (!project.isOpen())
           7                 project.open(null);
           8             
           9             //創(chuàng)建文件
          10             IFile java_file = project.getFile(new Path("/java_file.txt"));
          11             InputStream inputStreamJava = new ByteArrayInputStream("class MyType{}".getBytes());
          12             if (!java_file.exists())
          13                 java_file.create(inputStreamJava, falsenull);
          14         } catch (CoreException e) {
          15             IStatus status = new Status(IStatus.ERROR, "myplugin"101"創(chuàng)建資源失敗", e);
          16             Activator.getDefault().getLog().log(status);
          17         }

                      
                  
                  打開方式一:Eclipse默認(rèn)計算對應(yīng)的editor id,會用default text editor打開 
           1 try {
           2             IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
           3             IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject("TestProject");
           4             
           5             IFile java_file = project.getFile(new Path("/java_file.txt"));
           6             IDE.openEditor(page, java_file);            
           7         } catch (CoreException e) {
           8             IStatus status = new Status(IStatus.ERROR, "myplugin"102"打開工作區(qū)內(nèi)文件出錯", e);
           9             Activator.getDefault().getLog().log(status);
          10         }

                  打開方式二:指定java源碼編輯器打開,會用java源碼編輯器打開
           1 try {
           2             IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
           3             IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject("TestProject");
           4             
           5             IFile java_file = project.getFile(new Path("/java_file.txt"));
           6             IDE.openEditor(page, java_file, "org.eclipse.jdt.ui.CompilationUnitEditor");
           7         } catch (CoreException e) {
           8             IStatus status = new Status(IStatus.ERROR, "myplugin"102"打開工作區(qū)內(nèi)文件出錯", e);
           9             Activator.getDefault().getLog().log(status);
          10         }

                   
                     打開方式三:設(shè)定editor id屬性,該文件以后默認(rèn)都用此editor id打開
           1 try {
           2             IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
           3             IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject("TestProject");
           4             
           5             IFile java_file = project.getFile(new Path("/java_file.txt"));
           6             java_file.setPersistentProperty(IDE.EDITOR_KEY, "org.eclipse.jdt.ui.CompilationUnitEditor");
           7             IDE.openEditor(page, java_file);
           8         } catch (CoreException e) {
           9             IStatus status = new Status(IStatus.ERROR, "myplugin"102"打開工作區(qū)內(nèi)文件出錯", e);
          10             Activator.getDefault().getLog().log(status);
          11         }

                  說明:對于工作區(qū)工程內(nèi)的資源,可以有兩種方式:一是local的,那就是物理存在與工程之內(nèi);二是link進(jìn)入的。打開編輯器的時候,不需要做區(qū)分。

                  【打開工作區(qū)外部的資源】
                  說明:既存在于工作區(qū)外部,同時又沒有被link進(jìn)工程。
                  
                  在Eclipse中有個功能,就是File->Open File,可以打開一個外部文件。那我們看一下它是怎么實現(xiàn)的。我們只需要打開對應(yīng)的對話框,然后掛起主線程,就可以找到對應(yīng)的action了(掛起線程可以幫我們很方便的調(diào)試很多類型的問題,以后細(xì)說~_~):
                                

                     分析一下OpenExternalFileAction的實現(xiàn),我們發(fā)現(xiàn)它自己構(gòu)建了一個editor input


          本博客中的所有文章、隨筆除了標(biāo)題中含有引用或者轉(zhuǎn)載字樣的,其他均為原創(chuàng)。轉(zhuǎn)載請注明出處,謝謝!

          posted on 2008-08-27 14:54 zhuxing 閱讀(14836) 評論(7)  編輯  收藏 所屬分類: Eclipse Plug-in & OSGI

          評論

          # re: 【Eclipse插件開發(fā)】打開編輯器  回復(fù)  更多評論   

          我說Eclipse怎么能記住文件最后使用的編輯器,原來是有這個EDITOR_KEY屬性。

          講的很明白,能不能稍微將將EditorSite?
          2008-08-28 10:27 | Always BaNg.

          # re: 【Eclipse插件開發(fā)】打開編輯器  回復(fù)  更多評論   

          將得很細(xì)致。
          可是我不明白,如果我不想用默認(rèn)的IFileEditorInput的話,如何使用別的IEditorInput的子類的??或者使用我自己定義的Input的類?
          zhoucheng1985@vip.qq.com
          2009-03-06 16:36 | zhoucheng

          # re: 【Eclipse插件開發(fā)】打開編輯器  回復(fù)  更多評論   

          非常感謝,我找這個東西找了兩天,終于找到了!很有用,繼續(xù)關(guān)注!
          2009-11-03 14:17 | MeJustMe

          # re: 【Eclipse插件開發(fā)】打開編輯器  回復(fù)  更多評論   

          文中 IDE.openEditor(page, java_file); 的IDE類是怎么來的,謝謝
          2011-10-09 10:15 | usur

          # re: 【Eclipse插件開發(fā)】打開編輯器  回復(fù)  更多評論   

          @MeJustMe
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          @usur
          做的真爛,這頁面

          # re: 【Eclipse插件開發(fā)】打開編輯器  回復(fù)  更多評論   

          為什么寫到打開工作區(qū)外的文件,后面就沒有了啊,我現(xiàn)在正是在想怎么打開工作區(qū)外面的文件,希望補(bǔ)全啊
          2013-07-12 09:53 | baker

          # re: 【Eclipse插件開發(fā)】打開編輯器[未登錄]  回復(fù)  更多評論   

          Cannot determine URI for 這個錯誤是什么原因啊
          2014-12-05 10:18 | xw
          主站蜘蛛池模板: 确山县| 高安市| 彝良县| 双桥区| 商南县| 永仁县| 黄冈市| 石柱| 保山市| 抚州市| 尉氏县| 进贤县| 铜鼓县| 分宜县| 宜章县| 泸水县| 天等县| 徐闻县| 宁安市| 农安县| 交城县| 定日县| 宣恩县| 龙山县| 泰来县| 饶河县| 称多县| 新乡县| 衡水市| 中西区| 吴川市| 东丰县| 毕节市| 仙桃市| 乌苏市| 鹤峰县| 九寨沟县| 深泽县| 莆田市| 洱源县| 通海县|