?
????????【打開editor的接口討論】
??????? 先來看一下workbench吧,workbench從靜態劃分應該大致如下:
???????
????????????從結構圖我們大致就可以猜測出來,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?}
??????????
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?}
????????????那到這邊,可能很多人已經知道了怎么調用這些接口了:
?????????? ?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中提供了其他的接口:
????????????
?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會自動為你準備IEditorInput實例,并動態綁定合適的編輯器類型。對于下面的兩個操作,Eclipse會為你自動準備IEditorInput實例,但是需要用戶自己指定editor id。
?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?
????????????
???????????接下來我們看兩個問題,一是如何創建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()接口的:
1?public?class?FileEditorInput?implements?IFileEditorInput,IPathEditorInput,IPersistableElement?{
2?????private?IFile?file;
3?
4?????public?boolean?exists()?{
5?????????return?file.exists();
6?????}
7?}
????????? 我們看到內部的實現是持有了IFile句柄,如果IFile代表的資源沒有存在于工作區之內,那么就會返回false。(疑問:如果我們打開工作區外部的文件呢???顯然,FileEditorInput并不合適,稍后看...)
2?????private?IFile?file;
3?
4?????public?boolean?exists()?{
5?????????return?file.exists();
6?????}
7?}
????????
????????【動態計算editor id】
???????? 下面,我們再來看一下IDE類是如何計算所謂的默認eidtor id的。追蹤實現,我們看到了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?????}
????????????上面的代碼大致趕了如下兩件事情:
?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、如果對應的資源設定了一個特定的持久化屬性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):
<!--?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>
<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>
????????????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允許你配置,往下看:
????????????
????????????
????????????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。對應創建代碼如下:
????????????
?1?try?{
?2?????????????//創建工程
?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?????????????//創建文件
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,?false,?null);
14?????????}?catch?(CoreException?e)?{
15?????????????IStatus?status?=?new?Status(IStatus.ERROR,?"myplugin",?101,?"創建資源失敗",?e);
16?????????????Activator.getDefault().getLog().log(status);
17?????????}
?2?????????????//創建工程
?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?????????????//創建文件
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,?false,?null);
14?????????}?catch?(CoreException?e)?{
15?????????????IStatus?status?=?new?Status(IStatus.ERROR,?"myplugin",?101,?"創建資源失敗",?e);
16?????????????Activator.getDefault().getLog().log(status);
17?????????}
????????????
????????
????????打開方式一:Eclipse默認計算對應的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,?"打開工作區內文件出錯",?e);
?9?????????????Activator.getDefault().getLog().log(status);
10?????????}
?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,?"打開工作區內文件出錯",?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,?"打開工作區內文件出錯",?e);
?9?????????????Activator.getDefault().getLog().log(status);
10?????????}
?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,?"打開工作區內文件出錯",?e);
?9?????????????Activator.getDefault().getLog().log(status);
10?????????}
?????????
?????????? 打開方式三:設定editor id屬性,該文件以后默認都用此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,?"打開工作區內文件出錯",?e);
10?????????????Activator.getDefault().getLog().log(status);
11?????????}
?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,?"打開工作區內文件出錯",?e);
10?????????????Activator.getDefault().getLog().log(status);
11?????????}
????????說明:對于工作區工程內的資源,可以有兩種方式:一是local的,那就是物理存在與工程之內;二是link進入的。打開編輯器的時候,不需要做區分。
????????【打開工作區外部的資源】
????????說明:既存在于工作區外部,同時又沒有被link進工程。
????????
??????? 在Eclipse中有個功能,就是File->Open File,可以打開一個外部文件。那我們看一下它是怎么實現的。我們只需要打開對應的對話框,然后掛起主線程,就可以找到對應的action了(掛起線程可以幫我們很方便的調試很多類型的問題,以后細說~_~):
??????????????????????
?????????? 分析一下OpenExternalFileAction的實現,我們發現它自己構建了一個editor input