開發 Eclipse 插件的最佳實踐

使用標記、註釋和修飾符

本教程着重介紹使用標記將信息標記爲資源的最佳實踐,接着介紹用於在工作臺內突出標記的註釋和修飾符。通過擴展擴展點,您可以重用和改編 Eclipse 插件的內置函數,並且執行高級資源標記,比如在編輯文本時移動一個文本標記。我們將討論利用插件模型的方法,創建一個有效、高性能且具有綜合外觀的插件。

Andy Flatt, 軟件開發人員, IBM

Mickael Maison, 軟件開發人員, IBM

2011 年 11 月 14 日

  • +內容

簡介

在爲 IDE Eclipse 環境開發插件時,您要考慮到幾個設計要素,這些要素確保您:

  • 不用鎖定用戶界面線程。
  • 在不影響性能的情況下修飾用戶界面。
  • 在後臺處理數據。

本教程將討論如何使用這些設計要素來處理和顯示那些與存儲在工作區中的資源相關的數據。我們將檢查 Eclipse 如何提供一個標記界面來存儲和處理與資源相關的信息。

我們將提供處理資源數據標記的最佳實踐。首先,我們展示如何標記數據,然後構建知識來在用戶界面上表示標記,最後在資源變更時更新標記。在本文中,資源爲 Eclipse 對象,可實現 IResource 界面,比如項目、文件、文件夾以及 Java ™ 對象(其中包括包、類以及源)。

本教程是針對那些可以編寫基本插件並且又想學習處理 Eclipse 資源的最佳實踐的開發人員。

Eclipse.org 記錄了許多獨特的擴展點和界面。本文將幫助您選擇結合使用這些擴展點和界面的最佳實踐。 進一步學習如何利用現有的 Eclipse 函數來提供新的功能。

第 1 部分:創建您自己的標記

標記是什麼?

標記用於在不更改資源的情況下將信息鏈接到資源上。被標記信息的常見示例有斷點、書籤和編譯錯誤。以編譯錯誤爲例,每一次執行編譯作業,作業會通過創建一個新的標記來瀏覽源並突出錯誤。

擴展標記

在本教程的第一部分,我們將創建我們自己的標記。只要通過標記擴展點,並且只要編寫一行代碼即可完成此項工作。

您可以通過擴展 IMarker 擴展點 org.eclipse.core.resources.markers 來創建您自己的標記。首先,在 plugin.xml 文件中添加 清單 1 中的代碼。也就是說,您將以 id 爲 com.ibm.mymarkers.mymarker 創建一個名爲 My Marker 的標記。它的超類型爲 org.eclipse.core.resources.marker。這是最基本的標記類型。您可以擴展其他提供稍微更具體的功能的超類型。其他的超類型有:

  • org.eclipse.core.resources.problemmarker
  • org.eclipse.core.resources.textmarker

注意:您可以隨需使用任意多的這些超類型。

清單 1. 清單 1 來自 plugin.xml 的標記擴展定義
<extension point="org.eclipse.core.resources.markers" id="com.ibm.mymarkers.mymarker"
  name="My Marker">
	<super type="org.eclipse.core.resources.marker"/>
	<persistent value="false"/><attribute name="description"/>
</extension>

注意清單 1 中的兩個要素 persistent 和 attribute。這些都是分配給 mymarker 標記的屬性。 Persistent 指明標記是否應該存儲在工作區中。還有另外一個分配給 mymarker 的新屬性 description

使用新標記

您可以通過調用所需資源上的 createMarker 方法來創建一個標記。同時,您也可以爲其設置屬性。

清單 2 中所示的方法也可以用來創建標記。只需輸入 IResource,將其鏈接到標記。創建後,您就可以設置其屬性。

清單 2. 清單 2 創建新標記類型的 Java 代碼
public static IMarker createMarker(IResource res)
throws CoreException {
       IMarker marker = null;
       //note: you use the id that is defined in your plugin.xml
       marker = res.createMarker("com.ibm.mymarkers.mymarker");
       marker.setAttribute("description," "this is one of my markers");
       //note: you can also use attributes from your supertype
       marker.setAttribute(IMarker.MESSAGE, "My Marker");
       return marker;
}

查找您的標記

要查找與 IResource 相關的標記,您可以查詢資源來獲取所有具有指定 id 的標記,並指定是否搜索相關資源。要搜索標記,調用資源上的findMarkers 方法。指定諸如標記類型和搜索深度的參數。

清單 3 中的代碼使用 IResource.DEPTH_ZERO 參數查找直接與該資源鏈接的標記。

清單 3. 查找新標記類型的 Java 代碼
public static final String MARKER = "com.ibm.mymarkers.mymarker";

public static List<IMarker> findMarkers(IResource resource) {
        try {
               return Arrays.asList(resource.findMarkers(MARKER, true, 
	IResource.DEPTH_ZERO));
        } catch (CoreException e) {
               return new ArrayList<IMarker>();
        }
    }

將資源深度更改爲 IResource.DEPTH_INFINITE 會返回與其相關的標記或任何子資源。例如,您可以傳入包,並獲取與包中資源相鏈接的所有標記。

第 2 部分:使用註釋來顯示和更新標記

註釋是什麼?

註釋用於標記編輯器內的一個文本區域。它們廣泛用於在 Eclipse 中顯示信息,比如錯誤、警告、構建問題、任務或斷點。註釋在編輯器標尺上和文本上都可看到。圖 1 列出顯示語法錯誤的註釋。

圖 1. 圖 1 註釋的示例
屏幕截圖顯示編輯窗口中一些 Java 代碼左邊的註釋欄有一個綠色三角形,一個裏面帶有白色 X 符號的紅色圓圈

常見的註釋實現是,在解析文件並且挑選出諸如錯誤和 “todo” 標籤時生成標記。這通常在構建時完成。將其他的鏈接到持久標記,如斷點。該示例所使用的是持久標記。

用戶查看註釋的方法可以使用菜單 General > Editors > Text Editors > Annotations 下的首選項面板進行定製。也就是說用戶自定義註釋不需要執行額外的工作。

圖 2. 圖 2 註釋首選項面板的屏幕截圖
屏幕截圖顯示了註釋首選項列表,其中包含符號及其含義

查看 大圖

標記擴展點的屬性

在本教程的第 1 部分中,標記只擴展了默認的標記類型。在第 2 部分,我們將擴展文本標記類型,以標記文本位置。此類型定義了兩個關鍵屬性: charStart 和 charEnd。我們也希望標記在會話間能持久,所以我們將 persistent 值改爲 true。爲此,我們需要更新 清單 4 中所定義的標記。

清單 4. 清單 4 來自 plugin.xml 的標記擴展定義
<extension point="org.eclipse.core.resources.markers" id="com.ibm.mymarkers.mymarker"
  name="My Marker">
	<super type="org.eclipse.core.resources.textmarker"/>
	<super type="org.eclipse.core.resources.marker"/>
	<persistent value="true"/>
</extension>

定義您的註釋規範擴展

要創建您自己的註釋,使用擴展點 org.eclipse.ui.editors.markerAnnotationSpecification(參見 清單 5)。它定義了註釋的屬性以及其默認顯示選項。

清單 5. 清單 5 來自 plugin.xml 的註釋擴展定義
<extension point="org.eclipse.ui.editors.markerAnnotationSpecification"
		id="myannotationspecification" name="MyAnnotation">
	<specification annotationType="com.ibm.example.myannotation"
			label="MyAnnotation"
			icon="icons/sample.gif"
			overviewRulerPreferenceKey="clruler"
			overviewRulerPreferenceValue="true"
			colorPreferenceKey="clcolor"
			colorPreferenceValue="255,255,0"
			textPreferenceKey="cltext"
			textPreferenceValue="true"
			verticalRulerPreferenceKey="clvertical"
			verticalRulerPreferenceValue="true"
			textStylePreferenceKey="clstyle"
			textStylePreferenceValue="BOX">
	</specification>
</extension>

XML 中我們將用來鏈接到規範的部分是 id 和 annotationType 屬性。Eclipse.org 記錄了用於自定義的其他屬性(參見 參考資料)。

下一步是使用擴展點 org.eclipse.ui.editors.annotationTypes 把現有的標記鏈接到新的註釋規範中。我們使用來自規範的註釋類型和來自標記定義的 id 來鏈接規範。

清單 6. 清單 6 來自 plugin.xml 的註釋類型定義

點擊查看代碼清單

請參閱 參考資料,在 Eclipse.org 上查找更多關於此擴展點的信息。

創建並添加一個註釋到編輯器

清單 7 中的代碼用於創建並添加註釋到編輯器。

清單 7. 清單 7 向編輯器添加一個新的註釋
public static void addAnnotation(IMarker marker, ITextSelection selection, 
							ITextEditor editor) {
      //The DocumentProvider enables to get the document currently loaded in the editor
      IDocumentProvider idp = editor.getDocumentProvider();

      //This is the document we want to connect to. This is taken from 
      //the current editor input.
      IDocument document = idp.getDocument(editor.getEditorInput());

      //The IannotationModel enables to add/remove/change annotation to a Document 
      //loaded in an Editor
      IAnnotationModel iamf = idp.getAnnotationModel(editor.getEditorInput());

      //Note: The annotation type id specify that you want to create one of your 
      //annotations
      SimpleMarkerAnnotation ma = new SimpleMarkerAnnotation(
				“com.ibm.example.myannotation”,marker);

      //Finally add the new annotation to the model
      iamf.connect(document);
      iamf.addAnnotation(ma,newPosition(selection.getOffset(),selection.getLength()));
      iamf.disconnect(document);
}

保持標記和註釋同步

註釋模式負責在文檔被編輯時移動註釋。然而,在註釋移動時,它並不更新標記的屬性。在這種情況下,我們要更新標記的 charStart 和charEnd 屬性。最後的擴展點爲標記更新器(updater)。它定義了一個類,用於在移動註釋時更新標記。

清單 8. 清單 8 來自 plugin.xml 的標記更新器定義
<extension point="org.eclipse.ui.editors.markerUpdaters"> 
               <updater
                       id="com.ibm.example.MarkerUpdater"
                       class="com.ibm.example.mymarker.MarkerUpdater"
                       markerType="com.ibm.mymarkers.mymarker">
               </updater>
</extension>:

我們使用 IMarkerUpdater 界面來提供我們在移動註釋時想要執行的代碼。清單 9 中顯示的類是我們的標記更新器。我們感興趣的代碼在updateMarker 方法中。 此處,我們用它來更新標記的 charStart 和 charEnd 屬性。

清單 9. 清單 9 標記更新器代碼
public class MarkerUpdater implements IMarkerUpdater {
       /*
       *Returns the attributes for which this updater is responsible.
       *If the result is null, the updater assumes responsibility for any attributes.
       */
       @Override
       public String[] getAttribute() {
            return null;
       }

       @Override
       public String getMarkerType() {
             //returns the marker type that we are interested in updating
            return "com.ibm.mymarkers.mymarker";
       }

       @Override
       public boolean updateMarker(IMarker marker, IDocument doc, Position position) {
             try {
                 int start = position.getOffset();
                   int end = position.getOffset() + position.getLength();
                   marker.setAttribute(IMarker.CHAR_START, start);
                   marker.setAttribute(IMarker.CHAR_END, end);
                   return true;
             } catch (CoreException e) {
                   return false;
             }
       }
}

修飾符是什麼?

在 Eclipse 中,修飾符用於爲工作區中的對象添加視覺信息。他們通常顯示對象類型以及目前與該對象相關的任何重要屬性。圖 3 顯示瞭如何在包資源管理器中將修飾符顯示給用戶。該修飾符顯示了哪些項爲 Java 源文件,或哪些項爲包,並且顯示了包含警告或錯誤的源和包的標記圖標。這裏,修飾符也用來添加細節,比如文件是否與存儲庫同步。

圖 3. 圖 3 用符號圖標修飾的包和源
屏幕截圖顯示一些小符號,比如黃色圓圈和藍色箭頭,被添加到了文件圖標

定義您自己的修飾符

添加我們的修飾符的第一步是擴展 org.eclipse.ui.decorators 擴展點。它啓用新修飾符的定義,並且選擇它將要修飾哪種對象。

此處重要的字段是:

  • class,它必須是實現 ILightweightLabelDecorator 的類的完全限定名(將 lightweight 設置爲 true)。
  • enablement,它包含修飾符所應用的 Eclipse 對象列表。
清單 10. 清單 10 來自 plugin.xml 的修飾符定義
<extension point="org.eclipse.ui.decorators">  
	<decorator   id="com.ibm.example.filedecorator"   
			label="MyMarker Decorator"   
			state="true"   
			class= "com.ibm.example.mymarker.FileDecorator"   
			adaptable="true"   
			lightweight="true">   
		<enablement>
			<objectClass name="org.eclipse.core.resources.IResource"/>   
		</enablement>  
	</decorator>
</extension>

請參閱 參考資料,在 Eclipse.org 上查找更多關於擴展點的文件。

注意:輕量級與非輕量級:根據 API, 非輕量級修飾符可能會在新版本的 Eclipe 中被棄用。

我們的文件修飾符類

我們需要實現 FileDecorator 類來決定修飾符的行爲。這一類必須實現 ILightweightLabelDecorator。用它來擴展 LabelProvider的想法非常好,因爲它可以讓我們只重寫我們感興趣的方法,即 decorate()

decorate() 的基本實現如 清單 11 所示。

清單 11. 清單 11 decorate() 的簡單實現
public void decorate(Object resource, IDecoration decoration)  {
	decoration.addOverlay(ImageDescriptor.createFromFile(FileDecorator.class, 
					"/icons/sample.gif"), IDecoration.TOP_RIGHT);
	decoration.addPrefix("My Prefix ");
	decoration.addSuffix(" My Suffix");
}

IDecoration 對象也可用於自定義字體、文本或背景顏色。

圖 4. 圖 4 清單 11 中用來修飾 IResources 的代碼屏幕截圖
屏幕截圖顯示了已執行代碼的結果,將修飾符放置於文件圖標上。

decorate() 的第一個參數可以用來篩選我們要修飾的資源。如果我們只想要修飾包含指定標記的資源,就使用如 清單 12 所示的代碼。

清單 12. 清單 12 使用指定標記修飾資源
public void decorate(Object resource, IDecoration decoration) {
	if(resource instanceof IResource){
		List<IMarker> markers = MyMarkerFactory.findMarkers((IResource) resource);
		if (markers.size() > 0) {
			decoration.addSuffix("  Marker !!");
		}
	}
}

您已經遵循了本教程的步驟,接下來該做什麼?

進一步的改進包括:

  • 爲標記添加可編輯的屬性。允許用戶更改標記的狀態。
  • 自動創建和刪除標記。 使用後臺處理作業來自動創建、更新和刪除標記。
  • 自定義標記的 hover。使用高級標記 hover 來支持 HTML 或多媒體內容。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章