Live a simple life

          沉默(zhu_xing@live.cn)
          隨筆 - 48, 文章 - 0, 評論 - 132, 引用 - 0
          數(shù)據(jù)加載中……

          【Eclipse插件開發(fā)】基于WTP開發(fā)自定義的JSP編輯器(四):Strucutured Document分析視圖

                  在上一篇中,我們詳細(xì)闡述了WTP中最重要的數(shù)據(jù)模型之一IStructuredDocument(我們就稱之為WTP Document吧,和另外一個核心數(shù)據(jù)模型WTP Model----IStructuredModel對應(yīng)),本節(jié)中我們將自己開發(fā)一個工具來分析IStrucutredDocument。

                  PS:千萬別著急,后面的文章會對WTP StructuredTextEditor進行功能特征定制的,在真正定制之前一定要搞清楚WTP Document(IStructuredDocument)和WTP Model(IStructuredModel),連核心數(shù)據(jù)模型都不熟悉,后面談何定制^_^

                  【W(wǎng)TP提供的Properteis視圖擴展】
                  說明:Properteis視圖是Eclipse固有的,允許用戶通過相應(yīng)的類型擴展機制來定制Properties視圖中的內(nèi)容,涉及到的主要知識點包括:
                  1、Eclipse的Adapter機制(IAdaptable、IAdapterFactory、AdapterManager),關(guān)于Eclipse中的類型適配擴展機制,博客中的另外一篇文章做了分析:
                      【Eclipse插件開發(fā)】Eclipse中類型擴展機制分析
                  2、Properties視圖相關(guān)的幾個重要接口:
                         org.eclipse.ui.views.properties.IPropertySource.class
                         org.eclipse.ui.views.properties.PropertySheetPage
                          ...
                  3、WTP就是借助于Eclipse類型擴展機制,實現(xiàn)了對應(yīng)的功能。我們看一下在WTP的StructuredTextEditor中的getAdapter方法中提供了擴展服務(wù)(IWorkbenchPart本身就是聲明為IAdaptable):
                      
           1 /*
           2      * (non-Javadoc)
           3      * 
           4      * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
           5      */
           6     public Object getAdapter(Class required) {
           7       //
           8       else if (IPropertySheetPage.class.equals(required) && isEditable()) {
           9             if (fPropertySheetPage == null || fPropertySheetPage.getControl() == null || fPropertySheetPage.getControl().isDisposed()) {
          10                 PropertySheetConfiguration cfg = createPropertySheetConfiguration();
          11                 if (cfg != null) {
          12                     ConfigurablePropertySheetPage propertySheetPage = new ConfigurablePropertySheetPage();
          13                     propertySheetPage.setConfiguration(cfg);
          14                     fPropertySheetPage = propertySheetPage;
          15                 }
          16             }
          17             result = fPropertySheetPage;
          18         }
          19          //.
          20 }
                   ConfigurablePropertySheetPage^_^(org.eclipse.wst.sse.ui.internal.properties.ConfigurablePropertySheetPage)。

                  WTP的properties視圖的主要功能就是,根據(jù)用戶在編輯器中光標(biāo)的位置,在Properties視圖中展示對應(yīng)的標(biāo)簽內(nèi)容,并支持用戶編輯,例如:

               當(dāng)前編輯器中,用戶光標(biāo)位于jsp:directive.page標(biāo)簽內(nèi),屬性視圖就列舉了對應(yīng)的標(biāo)簽內(nèi)容,允許用戶編輯。

                  【我們自己的Stuctured Document View】
                    如果有一個視圖來將當(dāng)前編輯器中的內(nèi)容對應(yīng)的IStrucuturedDocument以樹狀結(jié)構(gòu)的方式展示出來,再提供一定的用戶交互,那對認(rèn)清楚IStructuredDocument的本質(zhì)是有作用的哈

                      【需求】
                      1、提供一個Structured Document View視圖,以樹狀方式將當(dāng)前編輯器中的IStructuredDocument展示出來
                      2、交互(編輯器 ---> Structured Document View視圖):
                             激活WTP JSP編輯器(或者是我們前面自己定制的編輯器),即時更新Structured Document View視圖
                             當(dāng)用戶光在編輯器中標(biāo)移動時,自動選中Structured Document View視圖中對應(yīng)的節(jié)點
                             當(dāng)編輯器中的內(nèi)容改變時,即時更新Structured Document View視圖
                             當(dāng)前激活編輯器關(guān)閉時,清空Structured Document View視圖內(nèi)容
                      3、交互(Structured Document View視圖 ---> 編輯器)
                             雙擊視圖中樹狀控件中特定節(jié)點,對應(yīng)內(nèi)容在編輯器中被選中
                      4、顯示內(nèi)容:
                             對于IStructuredDocument,則顯示對應(yīng)的具體實現(xiàn)類(對應(yīng)于JSP類型則為JobSafeStructuredDocument)
                              對于IStrucutredDocumentRegion(ITextRegionCollection),則顯示實現(xiàn)類名稱、節(jié)點類型、位置范圍、文本等
                              對于葉子節(jié)點的ITextRegion,則顯示實現(xiàn)類名稱、節(jié)點類型、位置范圍(說明:相對于父ITextRegionCollection的相對位置,非對于整個文檔的相對位置!!!)

                      【效果預(yù)覽】

                          如上圖所示,雙擊視圖中的節(jié)點,編輯器中對應(yīng)的內(nèi)容被選中^_^。

                       【實現(xiàn)摘要(文章后面會附上完整代碼)】
                          1、創(chuàng)建插件工程wtp.stuctureddocument,創(chuàng)建視圖,不用多說,利用擴展點org.eclipse.ui.views,對應(yīng)內(nèi)容如下:        
           1 <?xml version="1.0" encoding="UTF-8"?>
           2 <?eclipse version="3.2"?>
           3 <plugin>
           4    <extension
           5          point="org.eclipse.ui.views">
           6       <category
           7             id="wtp.structureddocument.category"
           8             name="Structured Document分析"/>
           9       <view
          10             category="wtp.structureddocument.category"
          11             class="wtp.structureddocument.view.StructuredDocumentView"
          12             id="wtp.structureddocument.view"
          13             name="Structured Document分析"/>
          14    </extension>
          15 </plugin>
                          wtp.structureddocument.view.StructuredDocumentView為視圖對應(yīng)的ViewPart實現(xiàn),里面創(chuàng)建了一個tree viewer控件,并給其配置了對應(yīng)的content provider和label provider,具體參加附件中的源碼。

                         2、利用workbench中的選擇服務(wù)(seleciton service)。前面需求中說過,我們要監(jiān)聽光標(biāo)在編輯器中的位置選擇,所以使用此服務(wù),所以我們的StructuredDocumentView要實現(xiàn)org.eclipse.ui.ISelectionListener接口。
                          (PS:selection service是workbench的一個重要特性,也是我們常用的,Eclipse官方網(wǎng)站上有一篇專題文章,看看撒兩眼^_^)
              
                            注冊selection listener: 
          1 /* (non-Javadoc)
          2      * @see org.eclipse.ui.part.ViewPart#init(org.eclipse.ui.IViewSite)
          3      */
          4     public void init(IViewSite site) throws PartInitException {
          5         super.init(site);
          6         
          7         this.getSite().getPage().getWorkbenchWindow().getSelectionService().addPostSelectionListener(this);
          8         this.getSite().getPage().getWorkbenchWindow().getPartService().addPartListener(partListener);
          9     }
                          
                          實現(xiàn)selection事件處理:
           1 /* (non-Javadoc)
           2      * @see org.eclipse.ui.ISelectionListener#selectionChanged(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
           3      */
           4     public void selectionChanged(IWorkbenchPart part, ISelection selection) {
           5         if (part instanceof TextEditor) {
           6             IEditorInput editorInput = ((TextEditor)part).getEditorInput();
           7             IDocument document = ((TextEditor)part).getDocumentProvider().getDocument(editorInput);
           8             
           9             if (!(document instanceof IStructuredDocument)) {
          10                 this.viewer.setInput(new Object[0]);
          11                 return ;
          12             }
          13         
          14             IStructuredDocument structuredDocument = (IStructuredDocument)document;
          15             
          16             if (this.needUpdateInput(document)) {
          17                 this.viewer.setInput(new Object[]{document});
          18                 this.viewer.expandAll();
          19                 this.viewer.collapseAll();
          20                 
          21                 //set source workbench part, will be used in part listener
          22                 this.sourcePart = part;
          23                 
          24                 //注冊監(jiān)聽器,便于同步刷新tree viewer
          25                 structuredDocument.addDocumentListener(documentListener);
          26             }
          27             
          28             if (selection instanceof ITextSelection) {
          29                 int offset = ((ITextSelection)selection).getOffset();
          30                 IStructuredDocumentRegion structuredDocumentRegion = structuredDocument.getRegionAtCharacterOffset(offset);
          31                 ITextRegion textRegion = structuredDocumentRegion.getRegionAtCharacterOffset(offset);
          32                 
          33                 this.viewer.collapseAll();
          34                 this.viewer.expandToLevel(structuredDocumentRegion, 2);
          35                 this.viewer.setSelection(new StructuredSelection(textRegion));
          36             }
          37         }
          38     }
                      
           1 /**
           2      * 判斷當(dāng)前document和tree viewer中輸入的document是否一致
           3      * 
           4      * @param document
           5      * @return
           6      */
           7     private boolean needUpdateInput(IDocument document) {
           8         if (this.viewer.getInput() != null) {
           9             Object[] oldInput = (Object[])this.viewer.getInput();
          10             if (oldInput.length == 1)
          11                 return oldInput[0!= document;
          12         }
          13         
          14         return true;
          15     }

                      看的出來,我們的selection處理邏輯如下:
                      1、如果當(dāng)前選擇事件來自TextEditor類型的編輯器中(文本編輯器的共同超類),則去獲取編輯器對應(yīng)的IDocument,如果是IStrucuturedDocument則判斷是否需要更新;如果不是,則不是我們的目標(biāo)(例如如果打開的是java源碼編輯器,那對應(yīng)的IDocument實現(xiàn)肯定不是WTP的IStrucuturedDocument了哈^_^)
                      2、如果是IStrucuturedDocument,則確定是否需要更新(也就是判斷我們的Structured Document分析視圖中現(xiàn)有的input是否就是當(dāng)前編輯器中內(nèi)容對應(yīng)的IStrucuturedDocument)。如果需要更新,則重新設(shè)置tree viewer輸入
                      3、我們根據(jù)光標(biāo)在編輯器中的位置信息(參加org.eclipse.jface.text.ITexSelection),首先利用IStructuredDocument.getRegionAtCharacterOffset(int)來定位對應(yīng)的IStructuredDocumentRegion樹枝節(jié)點,然后在利用IStructuredDocumentRegion.getRegionAtCharacterOffset(int)來定位對應(yīng)的ITextRegion樹葉節(jié)點,在我們視圖的樹狀控件中選中對應(yīng)的樹葉節(jié)點。
                          回顧:對于IStructuredDocument來說,它的孩子就是IStructuredDoucmentRegion,并沒有提供對應(yīng)的接口允許用戶直接去獲取特定offset對應(yīng)的具體ITextRegion。再看一下前面用到的一幅圖吧:
                          

                          3、處理視圖中tree viewer雙擊,定位編輯器中對應(yīng)內(nèi)容
                              
           1 this.viewer.addDoubleClickListener(new IDoubleClickListener() {
           2             public void doubleClick(DoubleClickEvent event) {
           3                 TreeSelection treeSelection = (TreeSelection)event.getSelection();
           4                 TreePath treePath = treeSelection.getPaths()[0];
           5                 
           6                 if (treePath.getSegmentCount() == 1) {
           7                     //選擇的是IStructuredDocument
           8                     IStructuredDocument structuredDocument = (IStructuredDocument)treeSelection.getFirstElement();
           9                     
          10                     //處理編輯器選中,選中整個文檔
          11                     ((StructuredTextEditor)sourcePart).getTextViewer().setSelectedRange(0, structuredDocument.getLength());
          12                 }
          13                 else if (treePath.getSegmentCount() == 2) {
          14                     //選擇的是IStructuredDocumentRegion
          15                     IStructuredDocumentRegion structuredDocumentRegion = (IStructuredDocumentRegion)treePath.getLastSegment();
          16                     int selectionOffset = structuredDocumentRegion.getStart();
          17                     int selectionLength = structuredDocumentRegion.getLength();
          18                     
          19                     //處理編輯器選中,選中structured document region區(qū)域
          20                     ((StructuredTextEditor)sourcePart).getTextViewer().setSelectedRange(selectionOffset, selectionLength);
          21                 }
          22                 else if (treePath.getSegmentCount() == 3) {
          23                     //選擇的是非container的ITextRegion,其父節(jié)點為IStructuredDocumentRegion
          24                     IStructuredDocumentRegion structuredDocumentRegion = (IStructuredDocumentRegion)treePath.getSegment(1);
          25                     ITextRegion textRegion = (ITextRegion)treePath.getLastSegment();
          26                     
          27                     int selectionOffset = structuredDocumentRegion.getStartOffset(textRegion);
          28                     int selectionLength = textRegion.getLength();
          29                     
          30                     //處理編輯器選中,選中的是葉子節(jié)點的text region區(qū)域
          31                     ((StructuredTextEditor)sourcePart).getTextViewer().setSelectedRange(selectionOffset, selectionLength);
          32                 }
          33             }
          34         });
                          TreePath(org.eclipse.jface.viewers.TreePath)中的seg count信息其實確定了我們的雙擊的控件位于整個樹狀控件的位置,具體自己看吧^_^
                      
                      4、利用IDocumentListener同步更新視圖。邏輯非常簡單,如下:          
          1 private class StructuredDocumentListener implements IDocumentListener {
          2         public void documentChanged(DocumentEvent event) {
          3             viewer.refresh();
          4         }
          5         
          6         public void documentAboutToBeChanged(DocumentEvent event) {
          7             // nothing to do
          8         }
          9     }
                      我們的listener實在前面handle selection的過程注冊的,再決定用一個新的IStructuredDocument作為tree viewer輸入的時候,同步注冊對應(yīng)的監(jiān)聽器。
                      注意:我們這邊并沒有wtp自己的document listener,它自己都不建議使用了^_^

                  5、處理編輯器關(guān)閉行為,利用workbench的part service特性。當(dāng)對應(yīng)的編輯器關(guān)閉時,視圖中的tree viewer
           1 private class PartListener implements IPartListener {
           2         public void partActivated(IWorkbenchPart part) {
           3             // TODO Auto-generated method stub
           4             
           5         }
           6         
           7         public void partBroughtToTop(IWorkbenchPart part) {
           8             // TODO Auto-generated method stub
           9             
          10         }
          11         
          12         /* 
          13          * 如果被關(guān)閉的workbench part是提供document信息的source part,則情況tree viewer
          14          * 
          15          * @see org.eclipse.ui.IPartListener#partClosed(org.eclipse.ui.IWorkbenchPart)
          16          */
          17         public void partClosed(IWorkbenchPart part) {
          18             if (sourcePart == part) {
          19                 sourcePart = null;
          20                 viewer.setInput(new Object[0]);
          21             }
          22         }
          23         
          24         public void partDeactivated(IWorkbenchPart part) {
          25             // TODO Auto-generated method stub
          26             
          27         }
          28         
          29         public void partOpened(IWorkbenchPart part) {
          30             // TODO Auto-generated method stub
          31         }
          32     }
                      注意:上面代碼的source part是我們的handle selection過程中緩存的,這邊就派上用場了啊,能夠判斷當(dāng)前關(guān)閉的part是否就提供當(dāng)前IStructuredDocument的text eidtor 了^_^
                      注冊代碼再上面的init方法代碼中有,注冊了對應(yīng)的selection listener和part listener
              

                      上面基本上就是我們的視圖主類wtp.structureddocument.view.StructuredDocumentView的所有代碼了,我們開發(fā)這樣一個視圖也只用了200多行代碼...

                      最后強調(diào)一下,我們的這個插件工程需要依賴的插件列表為:
                       org.eclipse.ui,
                       org.eclipse.core.runtime,
                       org.eclipse.core.resources,
                       org.eclipse.wst.sse.core,
                       org.eclipse.wst.xml.core,
                       org.eclipse.wst.sse.ui,
                       org.eclipse.jface.text,
                       org.eclipse.ui.workbench.texteditor


                     【源碼下載】
                       源碼為實際工程以Export ---> Archive File方式導(dǎo)出的,下載鏈接:source.zip 。

          本博客中的所有文章、隨筆除了標(biāo)題中含有引用或者轉(zhuǎn)載字樣的,其他均為原創(chuàng)。轉(zhuǎn)載請注明出處,謝謝!

          posted on 2008-09-11 16:16 zhuxing 閱讀(3183) 評論(3)  編輯  收藏 所屬分類: Eclipse Plug-in & OSGIWTP(Web Tools Platform)

          評論

          # re: 【Eclipse插件開發(fā)】基于WTP開發(fā)自定義的JSP編輯器(四):Strucutured Document分析視圖  回復(fù)  更多評論   

          不要只觀察規(guī)則的jsp內(nèi)容對應(yīng)的document是怎樣的
          也要看看不規(guī)則的(不符合jsp語法的)jsp內(nèi)容對應(yīng)的document是怎樣的

          這很重要!!!直接影響后面你定制的行為是否健壯!!!
          2008-09-11 16:36 | zhuxing

          # re: 【Eclipse插件開發(fā)】基于WTP開發(fā)自定義的JSP編輯器(四):Strucutured Document分析視圖  回復(fù)  更多評論   

          明白,謝謝!
          2008-09-12 07:16 | srdrm

          # re: 【Eclipse插件開發(fā)】基于WTP開發(fā)自定義的JSP編輯器(四):Strucutured Document分析視圖[未登錄]  回復(fù)  更多評論   

          IStructuredDocument structuredDocument = (IStructuredDocument)document; 這一句報錯啊,請問樓主Eclipse是哪個版本的呢?
          2015-01-21 15:18 | ddd
          主站蜘蛛池模板: 通州市| 上栗县| 新巴尔虎右旗| 内丘县| 呼伦贝尔市| 翁牛特旗| 德阳市| 清水河县| 德清县| 稻城县| 慈利县| 文山县| 莱西市| 会宁县| 大理市| 通山县| 利川市| 云梦县| 南丰县| 卢湾区| 凌源市| 准格尔旗| 乾安县| 桑日县| 桐梓县| 遵义县| 舒城县| 常州市| 于田县| 大竹县| 大洼县| 郴州市| 塔城市| 陈巴尔虎旗| 元朗区| 闸北区| 吉安县| 仙桃市| 叙永县| 都江堰市| 夏河县|