自己動手編寫Eclipse擴展點

  擴展(Extension)是Eclipse中一個關鍵的機制,plug-in利用擴展向Eclipse平臺添加新功能。但是擴展不能隨意地創建,必須按照擴展點(extension point)定義的規範進行明確的聲明,Eclipse才能認出這些擴展。我們不僅可以使用Eclipse提供的衆多現成的擴展點,而且還可以定義新的擴展點,並在該擴展點上進行擴展。
  當然,擴展點的定義比較複雜。不過Eclipse爲用戶提供了圖形化的編輯界面,我們只要輸入一些信息,Eclipse就會自動生成代碼,使擴展點的定義變得非常簡單。
  下面我們就來看看如何在Eclipse中創建一個新的擴展點,並在這個擴展點上進行擴展。
  我們需要做以下的工作:
1.設計該擴展點
2.定義擴展點,即編寫擴展點的清單文件
3.編寫代碼來載入該擴展點的擴展
  我們以創建workList擴展點爲例,進行詳細介紹。
  worklist完成的功能是:創建一個view,在其中以樹狀顯示系統中可用的功能模塊,通過雙擊某個模塊節點,執行該擴展定義的方法(method)。其實相當於一個控制檯,通過控制檯來運行不同的功能。
  由於Eclipse是由一個運行時核心(runtime core)和衆多插件組成的,我們也將workList擴展點定義在一個插件中,有關workList的代碼文件也放在這個插件中,這樣便於查找和修改,也不影響Eclipse本身的代碼。
 
1. 定義擴展點
  首先我們要創建一個存放新擴展點信息的插件net.softapp.worklist,這個插件對org.eclipse.ui.views進行擴展,以下是插件的plugin.xml文件在views擴展點的信息:
  <extension        
   point="org.eclipse.ui.views">
         <category
                     name="WorkListCategory"
                     id="WorkListCategory"/>
                           <view
                                       icon="icons/sample.gif"
                                       class="net.softapp.internal.worklist.WorkListView"
                                       category="WorkListCategory"
                                       name="WorkList視圖"
                                       id="net.softapp.internal.worklist.WorkListView"/>
  </extension>
  這樣就可以通過“window->show view->other”,在彈出的“Show view”對話框中選擇“WorkList視圖”,打開視圖,我們用這個視圖顯示workList擴展點的所有擴展信息。“Show View”對話框顯示了Eclipse中定義所有視圖,即所有org.eclipse.views擴展點的擴展。瞭解這一點很重要,因爲我們在編寫workList擴展點代碼時,就可以模仿甚至拷貝views擴展點的代碼。
  下面,我們要在net.softapp.worklist插件中定義workList擴展點。
  擴展點的定義文件按照Eclipse的存放方式,一般存放在schema目錄下,我們把文件命名爲worklist.exsd。內容如下,此內容由PDE生成:
<?xml version='1.0' encoding='UTF-8'?>
<!-- Schema file written by PDE -->
<schema targetNamespace="mtn.esip.worklist">
<annotation>
      <appInfo>
         <meta.schema plugin="net.softapp.worklist" id="workList" name="workList"/>
         <!--通過這個定義,我們可以看出,定義的擴展點的id是 net.softapp.worklist.workList,以後引用時要注意,同時注意大小寫-->
      </appInfo>
      <documentation>
         [Enter description of this extension point.]
      </documentation>
   </annotation>

   <element name="extension">
      <complexType>
         <choice minOccurs="0" maxOccurs="unbounded">
            <element ref="category" minOccurs="0" maxOccurs="1"/>
            <element ref="worklist" minOccurs="0" maxOccurs="1"/>
         </choice>
         <attribute name="point" type="string" use="required"><!--定義point-->
            <annotation>
               <documentation>                 
               </documentation>
            </annotation>
         </attribute>
         <attribute name="id" type="string"><!--定義id-->
            <annotation>
               <documentation>                 
               </documentation>
            </annotation>
         </attribute>
         <attribute name="name" type="string"><!--定義name-->
            <annotation>
               <documentation>                 
               </documentation>
            </annotation>
         </attribute>
      </complexType>
   </element>
 
  <!--定義category-->
   <element name="category">
      <complexType>
         <attribute name="name" type="string"><!--定義category/name-->
            <annotation>
               <documentation>                 
               </documentation>
            </annotation>
         </attribute>
         <attribute name="id" type="string"><!--定義category/id。引用category時,必須指出應用的id,而name給出了一個可供顯示的直觀的名字-->
            <annotation>
               <documentation>                 
               </documentation>
            </annotation>
         </attribute>
         <attribute name="parentCategory" type="string"><!--定義父category,也就是說我們的category可以嵌套形成樹狀結構-->
            <annotation>
               <documentation>                 
               </documentation>
            </annotation>
         </attribute>
      </complexType>
   </element>

   <!--定義worklist,注意大小寫-->
   <element name="worklist">
      <complexType>
         <attribute name="name" type="string"><!--定義worklist/name,可供顯示的直觀的名字-->
            <annotation>
               <documentation>                 
               </documentation>
            </annotation>
         </attribute>
         <attribute name="icon" type="string"><!--定義worklist/icon,可供顯示的直觀的圖標-->
            <annotation>
               <documentation>                 
               </documentation>
            </annotation>
         </attribute>
         <attribute name="category" type="string">!--定義worklist/category,存放的category位置。如果引用嵌套形式的category,則採用 parent_id/child_id的形式 -->
            <annotation>
               <documentation>                 
               </documentation>
            </annotation>
         </attribute>
         <attribute name="class" type="string"><!--定義worklist/class,實現功能的類名稱-->
            <annotation>
               <documentation>                 
               </documentation>
               <appInfo>
                  <meta.attribute kind="java"/>
               </appInfo>
            </annotation>
         </attribute>
         <attribute name="id" type="string" use="required"><!--定義worklist/id,唯一標誌-->
            <annotation>
               <documentation>                 
               </documentation>
            </annotation>
         </attribute>
      </complexType>
   </element>
   <!--以下內容爲PDE自動生成,與我們的編程無關-->
   <annotation>
      <appInfo>
         <meta.section type="since"/>
      </appInfo>
      <documentation>
         [Enter the first release in which this extension point appears.]
      </documentation>
   </annotation>

   <annotation>
      <appInfo>
         <meta.section type="examples"/>
      </appInfo>
      <documentation>
         [Enter extension point usage example here.]
      </documentation>
   </annotation>

   <annotation>
      <appInfo>
         <meta.section type="apiInfo"/>
      </appInfo>
      <documentation>
         [Enter API information here.]
      </documentation>
   </annotation>

   <annotation>
      <appInfo>
         <meta.section type="implementation"/>
      </appInfo>
      <documentation>
         [Enter information about supplied implementation of this extension point.]
      </documentation>
   </annotation>

   <annotation>
      <appInfo>
         <meta.section type="copyright"/>
      </appInfo>
      <documentation>        
      </documentation>
   </annotation>

</schema>
  這樣我們就定義好了擴展的屬性。
  然後在plugin.xml加入:
     <extension-point id="workList" name="workList" schema="schema/workList.exsd"/>
  就定義好了!
 
2. 實現擴展
  定義完擴展之後,接下來要編寫解析此擴展的相關代碼。可喜的是,Eclipse爲我們提供了大量的API可以調用,省下了若干代碼的編寫。另外我們還可以借鑑Eclipse實現的其他代碼,通過模仿來編寫我們自己的解析代碼。本例參考了View的解析部分。同View,我們定義了WorkListDescriptor,WorkListRegistry,WorkListRegistryReader.其中WorkListDescriptor完成對上述定義的解析,WorkListRegistry存放了其他插件對workList擴展的相關信息,WorkListRegistryReader則從WorkListRegistry讀取信息供我們使用。
  此處代碼從略,具體請參考View實現部分的ViewDescriptor,ViewRegistry,ViewRegistryReader相關代碼。
 
3. 編寫界面部分
  根據1對View的擴展,我們需要編寫界面部分。此處請參考View插件的編寫。我們在此對WorkListPlugin添加了一個方法用以從註冊表中讀取擴展信息:
   public IWorkListRegistry getWorkListRegistry() {
  if (workListRegistry == null) {
   workListRegistry = new WorkListRegistry();
   try {
    WorkListRegistryReader reader = new WorkListRegistryReader();
    reader.readWorkList(Platform.getExtensionRegistry(), workListRegistry);
   } catch (CoreException e) {
    // cannot safely show a dialog so log it
    WorkbenchPlugin.log("Unable to read workList registry.", e.getStatus()); //$NON-NLS-1$
   }
  }
  return workListRegistry;
 }
其中WorkListRegistryReader.readWorkList定義如下:
/**
 * Read the workList extensions within a registry.
 */
public void readWorkList(IExtensionRegistry in, WorkListRegistry out)
 throws CoreException {
 // this does not seem to really ever be throwing an the exception
 workListRegistry = out;
 readRegistry(in, WorkListPlugin.getDefault().getPluginId(), "workList");
 out.mapWorkListToCategories();
}
可見,我們不需要編寫複雜的代碼就可以讀取註冊表中存放的擴展信息!
  我們對workList擴展的顯示是採用了TreeView,代碼如下(WorkListView):
   protected TreeViewer createViewer(Composite parent) {
  TreeViewer viewer =
   new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
   viewer.setUseHashlookup(true);
   viewer.setContentProvider(new WorkListContentProvider());
   viewer.setLabelProvider(new WorkListLabelProvider());
   workListReg = WorkListPlugin.getDefault().getWorkListRegistry(); 
   viewer.setInput(workListReg);
   initListeners(viewer);
   return viewer;
 }
這樣,就可以實現顯示了。
  那麼,怎樣實現選擇某個擴展後,通過雙擊執行其功能呢?我們對TreeViewer添加了鼠標雙擊事件支持,關鍵代碼如下:
    protected void handleDoubleClick(DoubleClickEvent event) {
   IStructuredSelection selection = (IStructuredSelection) event.getSelection();
   Object element = selection.getFirstElement();

   TreeViewer viewer = getWorkListViewer();
   if (viewer.isExpandable(element)) {
    viewer.setExpandedState(element, !viewer.getExpandedState(element));   
   }else {
    WorkListDescriptor workList = (WorkListDescriptor)element;
    try {
      IWorkListPart workListPart = (IWorkListPart) workList.createWorkList();
      workListPart.run();
    } catch (CoreException e) {
     // should add something to handle the exception
    }
   }

  }
其中IWorkListPart很簡單,使所有實現workList擴展必須實現的接口:
public interface IWorkListPart {
 
 public void run();

}
只有一個run方法(可以自行添加其他的支持)。
  其中WorkListDescriptor.createWorkList方法實現根據class的字符串創建一個對象,也是超級簡單,因爲Eclipse已經爲我們編好了:
   public Object createWorkList() throws CoreException {
  Object obj = WorkbenchPlugin.createExtension(configElement, "class");
  return  obj;
 }
  這樣就可以執行擴展的功能了。
  但是別忘了,還要編寫pluin.xml,否則Eclipse可不認吆:
     <extension
         point="net.softapp.worklist.workList">
      <category
            name="HelloTest"
            id="HelloTest"/>
      <worklist
            icon="icons/example.ico"
            class="net.softapp.internal.worklist.Hello"
            category="HelloTest"
            name="Hello"
            id="net.softapp.internal.worklist.Hello"/>
   </extension>
  
4.測試新擴展點
  
   OK,開始運行Eclipse的plugin調試環境,打開WorkList視圖,看看在樹狀列表裏是不是有一個HelloTest目錄,下面有Hello。雙擊它,你編寫的代碼出來了吧!

發佈了32 篇原創文章 · 獲贊 5 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章