簡介:如果 Eclipse 中的默認插件模板能夠滿足用戶的需要,它們會非常有幫助。但是,如果需求超 出了默認模板的范圍,就需要定制模板。本文討論如何定制 Eclipse 中的插件項目模板,調整模板中的 多區段實現和控制,通過定制 UI 組件提高易用性,在 UI 端添加輸入檢驗功能,解釋如何自動地組織插 件項目的目錄結構。
如果您曾經在 Eclipse 中創建過插件項目,那麼應該熟悉現有的插件項目模板,這些模板可以為新項 目提供方便的起點。現有的插件模板可以節省大量時間,但是它們並不是萬能的。
使用插件模板 的一個難題是找到滿足用戶需求的模板。但是,模板只提供數量有限的功能,而用戶的需求各不相同,創 建模板的開發人員幾乎不可能事先預測出所有需求。在這種情況下,定制模板是一種簡便的方法,這可以 為用戶提供所需的插件,又能夠避免從頭編寫插件。
在本文中,學習:
如何定制 Eclipse 中的插件項目模板。
模板的高級特性,比如多區段實現和控制、UI 組件定制和檢驗。
自 動地組織項目目錄結構的工具。
先決條件
本文是為熟悉 Eclipse 並對構建插件感興趣的 Java™ 開發人員撰寫的。本文假設讀者基本了解插件和基於 Eclipse 的開發工具。為了構建插件 示例,您的計算機上需要安裝 Eclipse(V3.4 或更高版本)和 Java Runtime Environment (JRE)。
這裡的內容基於 developerWorks 文章 “使用 Eclipse 插件開發環境構建模板”。 如果您沒有使用過插件模板,建議您先閱讀這篇文章,它介紹了如何創建模板。因為這篇文章是入門級的 ,它介紹的模板缺少本文討論的高級特性,包括:
多區段實現和控制 在一般情況下,插件模板的 各個區段定義為功能模塊,其中包含已經建立的或根據用戶輸入生成的相互依賴的文件。一個區段中的文 件要麼都復制到目標項目中,要麼都不復制。用戶可以把一個區段定義為必需的或可選的。必需區段中的 文件必須包含在插件項目中,而可選區段中的文件應該根據選擇復制。如果插件模板提供功能的超集,但 是項目只需要功能的子集,多區段實現和控制會很有幫助。UI 組件定制 Eclipse 為插件項目模板提供幾 個默認的 UI 組件。這些基本的 UI 組件只提供有限的功能。為了提高易用性和功能性,有時候需要定制 復雜的組件。輸入檢驗功能 這可以增強數據檢驗控制。自動地組織插件項目的目錄結構 可以使用模板把 插件項目中的資源組織成特定的目錄結構。這可以減少手工工作量。
這些擴展特性可以提高插件模板 的可伸縮性、易用性和效率。在下面幾節中,我們要提供一個使用這些特性的模板示例。
示例研 究:深入討論插件模板
假設我們需要一組插件項目。它們用來構造各種 Eclipse 透視圖,比如 Java 和 Web 透視圖。一個項目用於一個透視圖的開發。每個透視圖可以有幾個視圖。每個視圖有相關的 資源,比如圖像和自動生成的 Java 源代碼文件,需要把這些資源復制到項目中。透視圖中的視圖數量和 每個視圖的名稱由各個透視圖決定。
定制插件模板是生成這些目標項目的好方法。
創建一 個簡單的模板
首先,創建一個新的插件項目(File > New > Project > Plug-in Project)。一定要選擇 This plug-in will make contribution to the UI 復選框。這是因為此示例中 的目標項目都用於透視圖開發,都要使用 UI。創建新項目之後,還應該在 plugin.xml 中添加一個擴展 org.eclipse.pde.ui.plugin.Content 的模板向導擴展。
新特性 A:多區段實現和控制
仔 細研究此示例的需求,就會發現在定制模板方面的一個問題。因為每個透視圖的視圖數量是可變的,所以 在視圖數量確定之前,不可能生成相關資源並復制到目標項目中。
為了解決此問題,我們來考慮 兩個解決方案。一種常用的方法是為每個透視圖類別創建一個模板,一個透視圖類別中的所有透視圖包含 相同數量的視圖。另一種方法更高效更高級。只為所有透視圖類別創建一個模板。通過區段控制管理視圖 和透視圖之間的鏈接。
添加用於透視圖和視圖區段的擴展
在此示例中,把所有資源分為兩 個部分。使用透視圖區段管理透視圖資源,使用視圖區段管理視圖資源。如果用戶需要沒有視圖的透視圖 ,就不會把視圖資源復制到目標項目中。同樣,如果用戶需要包含 9 個視圖的透視圖,那麼在透視圖中 注冊 9 個視圖,重復生成視圖資源並把資源復制到目標項目中。
為了生成這兩個區段,需要在 Manifest Editor 的 Extensions 選項卡中添加擴展。
圖 1. Extensions 選項卡 — 透視圖區段
圖 2. Extensions 選項卡 — 視圖區段
區段實現
圖 3 給出模板項目的結構。在此示例中,創建 5 個新文件(SampleWizard.java、 PerspectiveSection.java、ViewSection.java、$perspectiveClassName$.java 和 $viewClassName$.java)。它們構成項目的主要部分。
圖 3. 模板項目結構
PerspectiveSection 和 ViewSection 是 OptionTemplateSection 的子類,這個類代表模板向導的一 個區段。它們有三個主要功能:創建模板的 UI、保存從 UI 輸入的變量和更新模板模型。表 1 解釋區段 類的各個方法。
表 1. 區段類的方法
方法名 功能說明 initializeFields 使用輸入參數初始化向導頁面上的選項。一些選項可能取決於用戶在前面的向導步驟中做出的 選擇。 addPages 把與模板相關的頁面添加到向導中。 getStringOption 獲取選項名。 getSectionId 返回區段 ID。 updateModel 把必需的條目添加到插件模型中。$perspectiveClassName$.java 和 $viewClassName$.java 是模板文件,它們會自動轉換為目標項目 的 Java 源代碼文件。此示例中的模板文件非常簡單。我們僅僅創建所有視圖的列表,然後把這些視圖添 加到透視圖中。
接下來,在向導行為中添加區段控制。SampleWizard 類是 NewPluginTemplateWizard 類的子類,這 個類作為插件的向導模板。可以通過 SampleWizard 類把指定的區段分配給目標插件項目。 performFinish 方法是從超類繼承的。可以使用它在向導中執行特殊的最終處理,包括循環處理模板區段 並依次執行它們,從而為目標項目生成文件。清單 1 顯示如何在向導中注冊區段和 performFinish 方法 中的主要操作。
清單 1. SampleWizard.java
//register all related sections in wizard public ITemplateSection[] createTemplateSections() { return new ITemplateSection[] { new PerspectiveSection(), new ViewSection() }; } public boolean performFinish(final IProject project, IPluginModelBase model, IProgressMonitor monitor) { ... ITemplateSection[] sections = super.getTemplateSections(); //monitor finish action in this wizard monitor.beginTask("perform finish", sections.length); ... //get sections for (int i = 0; i <sections.length; i++) { if (sections[i].getClass().equals(PerspectiveSection.class)) { perspectiveSection = (PerspectiveSection) sections[i]; } else if (sections[i].getClass().equals(ViewSection.class)) { viewSection = (ViewSection) sections[i]; } } ... //set variables to sections and manage sections ... viewSection.setViewClassName(values[j]); viewSection.setSourcePath(sourceFolderName); viewSection.execute(project, model, new SubProgressMonitor(monitor, 1)); perspectiveSection.setSourcePath(sourceFolderName); perspectiveSection.setViewNames(viewNames); perspectiveSection.execute(project, model, new SubProgressMonitor(monitor, 1)); }
新特性 B:UI 組件定制
正如前面提到的,透視圖可以包含用戶所需的任意數量的視圖,用戶可以設置每個視圖的名稱。為了 收集一個透視圖中的所有視圖,我們設計了下面的輸入面板。它有一個 View Class Name 框和一個 View List 框。用戶可以輸入視圖類名,然後通過單擊 Add 把它添加到視圖列表中。用戶還可以使?? Remove 按鈕刪除視圖。
圖 4. 定制的模板選項
為了創建這個面板,在模板項目中添加 ViewOption,它擴展 TemplateOption(見圖 3)。我們使用 它設置 UI 組件並存儲用戶的輸入。清單 2 演示如何用一個視圖列表和兩個按鈕定制 UI 組件。
清單 2. ViewOption.java
//add UI components in this panel public void createControl(Composite parent, int span) { ... //create View List listLabel = new Label(parent, SWT.LEFT); listLabel.setText("View List:"); listViewerField = new ListViewer(parent); listField = (List) listViewerField.getControl(); GridData listGridData = new GridData(GridData.FILL_HORIZONTAL); listGridData.heightHint = 100; listField.setLayoutData(listGridData); ... //create add button addButton = new Button(parent, SWT.PUSH); addButton.setText("Add"); ... addButton.setLayoutData(addBtnData); addButton.addSelectionListener(...); //create remove button removeButton = new Button(parent, SWT.PUSH); ... removeButton.addSelectionListener(...); }
新特性 C:輸入檢驗功能
輸入檢驗功能是指在使用所有用戶輸入之前對它們進行檢驗的過程。輸入檢驗功能對於應用程序的安 全性是極其重要的。在我們的示例中,定義一條檢驗規則:對於一個透視圖中的所有視圖,視圖類名必須 是惟一的。如果違反此規則,就會在面板頂部顯示一條錯誤消息。
圖 5. 定制檢驗的模板選項
可以通過調用相應區段類中的 validateOptions 方法實現輸入檢驗功能。這個方法是從超類繼承的, 可以通過覆蓋它實現自己的檢驗功能。清單 3 給出此示例中的 validateOptions 方法。
清單 3. ViewSection.java 中的 validateOptions 方法
public void validateOptions(TemplateOption source) { this.getPage(0).setErrorMessage(null); ViewOption viewOption = (ViewOption) source; Text textField = viewOption.getTextField(); List listField = viewOption.getListField(); String[] items = listField.getItems(); if (items != null && items.length > 0) { //validation rule check for (int i = 0; i < items.length; i++) { if (items[i].equals(textField.getText())) { this.getPage(0).setErrorMessage("Class name '" + textField.getText() + "' already exists in View List."); break; } } } }
新特性 D:自動地組織插件項目的目錄結構
我們的目標之一是讓模板自動地組織目標插件項目的目錄結構。我們通過三個步驟實現此目標:
使用變量存儲目標項目的目錄結構。
編寫一個 Ant 腳本,它用於創建目標目錄結構並把資源分配到適當的目錄。
添加 IResourceChangeListener 以監視模板的工作空間。區段文件的生成過程完成之後,觸發 Ant 腳本的執行。
實現
為了簡化,我們假設所有 Java 文件都復制到一個包中,包名與項目名相同。例如,如果項目名為 com.ibm.template,那麼所有 Java 文件都復制到 com.ibm.template 包中。對此過程的討論超出了本文 的范圍,詳細信息請參見 “使用 Eclipse 插件開發環境構建模板”。
清單 4 給出此示例中使用的 Ant 腳本。它包含三個 target。第一個 target 根據源代碼路徑和包路 徑創建一個目錄結構。第二個 target 把所有 Java 文件復制到適當的目錄。最後一個 target 從新的插 件項目中刪除這個腳本文件。
在 SampleWizard 類的 performFinish 方法中添加 IResourceChangeListener。清單 5 給出這個監 聽器的實現。
清單 4. CreatePackage.xml
<?xml version="1.0"?> <project name="template project" default="clean" basedir="."> <property name="package" value=".\$sourcePath$\$packagePath$"></property> <target name="create"> <mkdir dir="$dollarMark${package}"/> </target> <target name="move" depends="create"> <move todir="$dollarMark${package}"> <fileset dir="."> <include name="*.java"/> </fileset> </move> </target> <target name="clean" depends="move"> <delete dir="."> <include name="CreatePackage.xml"/> </delete> </target> </project>
清單 5. SampleWizard.java — 監聽器
public boolean performFinish(final IProject project, IPluginModelBase model, IProgressMonitor monitor) { ... //get workspace final IWorkspace workspace = ResourcesPlugin.getWorkspace(); //get Ant file String antFilePath = "CreatePackage.xml"; final IFile file = project.getFile(antFilePath); //add Listener to monitor resource changing IResourceChangeListener listener = new IResourceChangeListener() { public void resourceChanged(IResourceChangeEvent event) { try { if (event.getType() == IResourceChangeEvent.POST_CHANGE) { IResourceDelta rootDelta = event.getDelta(); IPath filePath = file.getFullPath(); IResourceDelta targetDelta = rootDelta.findMember(filePath); if (targetDelta != null) { URI uri = file.getLocationURI(); File antFile = new File(uri); //run Ant script Project project = new Project(); project.fireBuildStarted(); project.init(); ProjectHelper helper = ProjectHelper.getProjectHelper(); helper.parse(project, antFile); project.executeTarget(project.getDefaultTarget()); project.fireBuildFinished(null); workspace.removeResourceChangeListener(this); } } } catch (Exception e) { e.printStackTrace(); } } }; workspace.addResourceChangeListener(listener); ... }
使用模板
創建了新的模板項目之後,需要刷新此項目。右鍵單擊此項目並選擇 Refresh 菜單項。這是因為我們 的 Ant 腳本是在生成項目之後執行的。我們需要在 Eclipse IDE 中手工刷新此項目。圖 6 是通過 “示 例研究:深入討論插件模板” 中討論的模板示例生成的插件項目。
圖 6. 新的項目結構
需要把這個新項目導出到 [eclipse_home]\plugins 目錄,然後用 -clean 參數重新啟動 Eclipse。 在 Eclipse 啟動之後,檢查我們的透視圖是否已經添加到透視圖列表中(見圖 7)。選擇 myplugin perspective,然後單擊 OK。這個透視圖就會打開。
圖 7. 透視圖列表
結束語
讀完本文之後,您應該對 Eclipse 插件模板有了更深入的認識。您學習了如何創建定制的輸入組件、 如何控制模板文件的生成以及如何用一個模板生成具有不同目錄結構的插件項目。通過使用這些模板特性 ,可以更輕松地創建插件項目。
本文配套源碼:http://www.bianceng.net/java/201212/824.htm