在上一節(jié)中我們分析了WTP TLD Content Model的關(guān)鍵特性,并簡要介紹了WTP Content Model的整體結(jié)構(gòu)。在本節(jié)中,我們將開發(fā)一個(gè)WTP TLD Content Model分析視圖,幫助我們更直觀的了解所謂的WTP TLD內(nèi)容模型。本視圖的開發(fā)和前面開發(fā)過的WTP StructuredDocument分析視圖和WTP Structured Model分析視圖非常類似,有些技術(shù)實(shí)現(xiàn)細(xì)節(jié)的分析可以參見前面相應(yīng)的章節(jié)。
【需求】
1、提供一個(gè)TLD Content Model分析視圖,以樹狀方式將當(dāng)前編輯器中JSP文檔對應(yīng)的TLD內(nèi)容模型顯示出來,每個(gè)TLDDocument為一個(gè)獨(dú)立節(jié)點(diǎn),TLDDocument下面持有TLD Element和TLD Attribute兩級子節(jié)點(diǎn)
2、交互(編輯器 ---> TLD Content Model分析視圖):
激活 JSP編輯器,即時(shí)更新TLD Content Model分析視圖
當(dāng)編輯器中的內(nèi)容改變時(shí),即時(shí)更新TLD Content Model分析視圖
當(dāng)前激活編輯器關(guān)閉時(shí),清空TLD Content Model分析視圖內(nèi)容
3、交互(TLD Content Model分析視圖 ---> 編輯器)
雙擊視圖中TLD Document節(jié)點(diǎn)時(shí),打開對應(yīng)的TLD定義文件
4、進(jìn)一步需求,當(dāng)編輯器中的光標(biāo)位置變化時(shí),即時(shí)更新TLD Content Model分析視圖。(說明:在上一節(jié)中我們分析過,一個(gè)TLD Document有位置相關(guān)的特性,獲取光標(biāo)位置相關(guān)的TLD Document列表,也就是光標(biāo)位置之前可以被識別的TLD導(dǎo)入^_^)
【效果預(yù)覽】
1、位置無關(guān)的TLD Content Model分析效果預(yù)覽 
如圖所示,不管光標(biāo)位于編輯器中的任何位置,都會(huì)列舉出所有的TLD Content Document。
2、位置相關(guān)的TLD Content Model分析效果預(yù)覽

如圖所示,光標(biāo)位于test1 tld和test2 tld之間,這時(shí)候分析視圖中只列舉除了當(dāng)前位置可以識別的TLD信息。在此位置,test2 tld還不能夠獲取到,所以使用test2中的標(biāo)簽會(huì)得到WTP的一個(gè)錯(cuò)誤提示:不能識別的標(biāo)簽。(我想,理解了TLD Content Document位置相關(guān)的特性,也就理解了WTP中對特定標(biāo)簽在特定位置是否可以被識別是怎么實(shí)現(xiàn)的了^_^)
【實(shí)現(xiàn)摘要(文章后門會(huì)附上對應(yīng)的源碼)】
說明:有關(guān)視圖實(shí)現(xiàn)類創(chuàng)建、如何利用Eclipse工作臺的selection service和part service等代碼實(shí)現(xiàn),請參照前面章節(jié)中的兩個(gè)分析視圖的實(shí)現(xiàn):
基于WTP開發(fā)自定義的JSP編輯器(四):Strucutured Document分析視圖
基于WTP開發(fā)自定義的JSP編輯器(六):IStructuredModel(DOM Document)分析視圖
1、
位置無關(guān)場景下TLD Content Document列表的獲取代碼:
/**
* 獲取指定文檔對應(yīng)的TLD Content Document列表
*
* @param structuredDocument jsp structured document
* @return
*/
private TLDDocument[] getTLDDocuments(IStructuredDocument structuredDocument) {
TLDCMDocumentManager tldDocumentManager = TaglibController.getTLDCMDocumentManager(structuredDocument);
List taglibTrackers = tldDocumentManager.getTaglibTrackers();
TLDDocument[] tldDocuments = new TLDDocument[taglibTrackers.size()];
for (int i = 0; i < tldDocuments.length; i++) {
TaglibTracker taglibTracker = (TaglibTracker)taglibTrackers.get(i);
tldDocuments[i] = (TLDDocument)taglibTracker.getDocument();
}
return tldDocuments;
}
上一節(jié)中,我們闡述過taglib tracker的獲取方式,TLDCMDocumentManager.getTaglibTrackers()就是位置無關(guān)的獲取方式,具體細(xì)節(jié)請參見上一節(jié)中的內(nèi)容。
2、
位置相關(guān)場景下TLD Content Document列表的獲取代碼:
/**
* 獲取指定文檔中特定位置對應(yīng)的TLD Content Document列表
*
* @param structuredDocument jsp structured document
* @param offset 文檔中的位置
* @return
*/
private TLDDocument[] getTLDDocuments(IStructuredDocument structuredDocument, int offset) {
TLDCMDocumentManager tldDocumentManager = TaglibController.getTLDCMDocumentManager(structuredDocument);
List taglibTrackers = tldDocumentManager.getCMDocumentTrackers(offset);
TLDDocument[] tldDocuments = new TLDDocument[taglibTrackers.size()];
for (int i = 0; i < tldDocuments.length; i++) {
TaglibTracker taglibTracker = (TaglibTracker)taglibTrackers.get(i);
tldDocuments[i] = (TLDDocument)taglibTracker.getDocument();
}
return tldDocuments;
}
taglib tracker列表的獲取方式:TLDCMDocumentManager.getCMDocumentTrackers(int offset),位置相關(guān)。
3、
對用戶選擇事件的處理:
/* (non-Javadoc)
* @see org.eclipse.ui.ISelectionListener#selectionChanged(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
*/
public void selectionChanged(IWorkbenchPart part, ISelection selection) {
if (!(part instanceof TextEditor))
return ;
IEditorInput editorInput = ((TextEditor)part).getEditorInput();
IDocument document = ((TextEditor)part).getDocumentProvider().getDocument(editorInput);
if (!(document instanceof IStructuredDocument)) {
this.viewer.setInput(null);
return ;
}
//記錄source part和source document
this.sourcePart = part;
this.sourceDocument = document;
//注冊對應(yīng)的document change listener
document.addDocumentListener(this.documentListener);
// //獲取TLD Content Document列表(位置無關(guān)方式),并更新tree viewer輸入
// TLDDocument[] tldDocuments = this.getTLDDocuments((IStructuredDocument)document);
// this.viewer.setInput(tldDocuments);
// this.viewer.expandToLevel(2);
//獲取TLD Content Document列表(位置相關(guān)方式),并更新tree viewer輸入
int offset = ((ITextSelection)selection).getOffset();
TLDDocument[] tldDocuments = this.getTLDDocuments((IStructuredDocument)document, offset);
this.viewer.setInput(tldDocuments);
this.viewer.expandToLevel(2);
}
在處理用戶選擇事件時(shí)候,根據(jù)只需要調(diào)用不同的TLD Content Document獲取方式(1、2點(diǎn)中闡述的)就可以了^_^。
4、
視圖中TLD Document節(jié)點(diǎn)的雙擊事件的處理:
//添加雙擊支持
this.viewer.addDoubleClickListener(new IDoubleClickListener() {
public void doubleClick(DoubleClickEvent event) {
ITreeSelection treeSelection = (ITreeSelection)event.getSelection();
Object selectedElement = treeSelection.getFirstElement();
if (!(selectedElement instanceof TLDDocument))
return ;
//獲取TLD Document對應(yīng)的TLD文件
String baseLocation = ((TLDDocument)selectedElement).getBaseLocation();
IFile file = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(new Path(baseLocation));
if (!file.exists())
return ;
//打開TLD定義文件
try {
IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
IDE.openEditor(page, file);
} catch (PartInitException e) {
IStatus status = new Status(IStatus.ERROR, "wtp.tldcontentdocument", 1111, "打開TLD定義文件失敗", e);
Activator.getDefault().getLog().log(status);
}
}
});
主要步驟如下:
1、利用TLDDocument接口中的getBaseLocation獲取該TLDDocument對應(yīng)的頁面資源的絕對路徑信息
2、定位工作區(qū)中對應(yīng)的TLD資源文件,打開
5、
視圖tree viewer對應(yīng)的content provider:
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java.lang.Object)
*/
public Object[] getChildren(Object parentElement) {
if (parentElement == null)
return new Object[0];
if (parentElement instanceof TLDDocument[])
return (TLDDocument[])parentElement;
//如果是tld content document, 則獲取對應(yīng)的tld element列表
if (parentElement instanceof TLDDocument) {
CMNamedNodeMap tagMap = ((TLDDocument)parentElement).getElements();
Object[] children = new Object[tagMap.getLength()];
for (int i = 0; i < children.length; i++) {
children[i] = tagMap.item(i);
}
return children;
}
//如果是tld element(tag),則獲取對應(yīng)的attrbute列表
if (parentElement instanceof TLDElementDeclaration) {
CMNamedNodeMap attributeMap = ((TLDElementDeclaration)parentElement).getAttributes();
Object[] children = new Object[attributeMap.getLength()];
for (int i = 0; i < children.length; i++) {
children[i] = attributeMap.item(i);
}
return children;
}
return new Object[0];
}
如果輸入是tld content document(TLDDocument),則獲取對應(yīng)的tld element列表,也就是tld中定義的tag列表;如果輸入是tld element(TLDElementDeclaration),則獲取對應(yīng)的tld attribute列表,也就是特定tag下面定義的標(biāo)簽屬性列表。
其他具體代碼實(shí)現(xiàn)細(xì)節(jié),參見附件中的源碼。^_^
【后記】
本插件工程需要依賴的插件列表為:
org.eclipse.ui,
org.eclipse.core.runtime,
org.eclipse.jface.text,
org.eclipse.ui.editors,
org.eclipse.ui.workbench.texteditor,
org.eclipse.wst.sse.core,
org.eclipse.jst.jsp.core,
org.eclipse.wst.xml.core,
org.eclipse.core.resources,
org.eclipse.ui.ide
源碼為實(shí)際工程以Export ---> Archive File方式導(dǎo)出的,
下載鏈接:
TLD Content Model分析視圖源碼
本博客中的所有文章、隨筆除了標(biāo)題中含有引用或者轉(zhuǎn)載字樣的,其他均為原創(chuàng)。轉(zhuǎn)載請注明出處,謝謝!