Live a simple life

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

          【Eclipse插件開發(fā)】基于WTP開發(fā)自定義的JSP編輯器(十二):定制自動編輯策略(Auto Edit Strategy)

                      JFace Text Framework框架的一個重要的功能特征就是自動編輯策略,它允許用戶對輸入的內(nèi)容(準確的說應該是即將來臨的Document修改^_^)做即時編輯,然后又會透明的將用戶的修改付諸于實現(xiàn)(即應用到當前文檔)。在本節(jié),我們將在前兩節(jié)有關TLD Content Model的基礎上開發(fā)一個自動編輯策略。

                  【JFace Text Framework 自動編輯策略原理介紹】

                   【JDT Java源碼編輯器自動編輯策略演示】
                    我們每個使用Eclipse JDT進行Java編程的開發(fā)者都會對JDT中Java源碼編輯器的自動編輯策略印象深刻,它給編碼人員帶來了很大的方便。舉例如下:
               
                      如上圖所示,我們在編寫一個新的函數(shù),圖中黑色豎線“|”就是光標所在處,當我們按下回車鍵的時候,效果變?yōu)槿缦拢?br />      
                          如上圖所示,當我們輸入回車鍵之后,JDT Java源碼編輯器自動幫我們矯正了內(nèi)容(text)和位置(offset):原來的輸入內(nèi)容應該是“\r\n”,JDT Java源碼編輯器自動幫我們矯正為“\r\n\t\t\r\n\t}”;根據(jù)“\r\n”內(nèi)容推算,輸入后光標位置應該位于28行的起始處,JDT Java源碼編輯器自動幫我們矯正為離28行其實處兩個“\t”的距離。

                      【自動編輯流程和主要角色】
                                          
                          上圖就演示了自動編輯過程:
                          1、用戶編輯,鍵盤事件
                          2、根據(jù)鍵盤事件,對事件信息進行分析,拼裝到名為DocumentCommand的數(shù)據(jù)結構中,該數(shù)據(jù)結構中包含了用戶的輸入內(nèi)容(text)、光標位置(offset)等信息,例如,上面JDT的例子中用戶的輸入內(nèi)容為“\r\n”。這一步JFace Text Framework幫用戶解決了
                          3、調(diào)用自動編輯策略,對應DocumentCommand中數(shù)據(jù)進行自定義矯正,例如,JDT Java源碼編輯器的自動編輯策略將輸入內(nèi)容矯正為“\r\n\t\t\r\n\t}”。用戶自己負責,JDT Java源碼編輯器在這邊干活了,提供了自己的IAutoEditStrategy^_^
                          4、將用戶矯正后的DocumentCommand應用到對應編輯器(說白了,就是轉(zhuǎn)化為一個Document replace動作執(zhí)行)。這一步JFace Text Framework幫用戶解決了
                          
                          我們可以看到,JFace Text Framework已經(jīng)替我們干了大部分活,我們需要關心的是如下兩個角色:    
                          org.eclipse.jface.text.DocumentCommand:數(shù)據(jù)載體,封裝了一個文本變化(text modification)的信息,例如輸入內(nèi)容(text)、光標位置(offset)、長度(length)等等。我們要做的恰恰就是在我們自己的自動編輯策略中對DocumentCommand中的內(nèi)容做矯正,然后JFace Text Framework會自動幫我們應用到目標IDocument中。
                          org.eclipse.jface.text.IAutoEditStrategy:自動編輯編輯策略,根據(jù)不同應用場景對DocumentCommand中的信息做不同的矯正。我們看一下其接口定義就知道了:
          package org.eclipse.jface.text;


          /**
           * An auto edit strategy can adapt changes that will be applied to
           * a text viewer's document. The strategy is informed by the text viewer
           * about each upcoming change in form of a document command. By manipulating
           * this document command, the strategy can influence in which way the text
           * viewer's document is changed. Clients may implement this interface.
           *
           * 
          @since 2.1
           
          */
          public interface IAutoEditStrategy {

              
          /**
               * Allows the strategy to manipulate the document command.
               *
               * 
          @param document the document that will be changed
               * 
          @param command the document command describing the change
               
          */
              
          void customizeDocumentCommand(IDocument document, DocumentCommand command);
          }
                      
                      【配置IAutoEditStrategy到SourceViewer】
                      
          上面我們已經(jīng)講了自動編輯的流程和主要角色,可以大家都有個疑問:IAutoEditStrategy到底是如何被自動調(diào)用的?IAutoEditStrategy實現(xiàn)需要被配置到對應的SourceViewerConfiguration中,并和對應的內(nèi)容類型(很多時候也可以理解為分區(qū)類型)綁定。JFace Text Framework會在初始化編輯器實例的時候讀取用戶的配置,然后根據(jù)不同的內(nèi)容類型去查找對應的自動編輯器策略。 
          package org.eclipse.jface.text.source;

          public class SourceViewerConfiguration {
              
          /**
               * Returns the auto edit strategies ready to be used with the given source viewer
               * when manipulating text of the given content type. For backward compatibility, this implementation always
               * returns an array containing the result of {
          @link #getAutoIndentStrategy(ISourceViewer, String)}.
               *
               * 
          @param sourceViewer the source viewer to be configured by this configuration
               * 
          @param contentType the content type for which the strategies are applicable
               * 
          @return the auto edit strategies or <code>null</code> if automatic editing is not to be enabled
               * 
          @since 3.1
               
          */
              
          public IAutoEditStrategy[] getAutoEditStrategies(ISourceViewer sourceViewer, String contentType) {
                  
          //
              }
          }
                      
                      附加說明:1、有關內(nèi)容類型(分區(qū)類型)可以參考前面章節(jié)的內(nèi)容; 2、原有的IAutoIndentStrategy接口Eclipse已經(jīng)不推薦使用^_^

                      【定制WTP StructuredTextEditor的自動編輯策略】
                   
          【需求】
                          當用戶輸入標簽結束符“>”時,如果標簽在TLD中定義為不含有標簽體(即bodycontent屬性值為empty),則自動將用戶的輸入內(nèi)容矯正為“/>”。
                          
                          【前提知識】
                            對WTP基本數(shù)據(jù)模型不很了解的可以參見一下前面的相關章節(jié):
                            【Eclipse插件開發(fā)】基于WTP開發(fā)自定義的JSP編輯器(三) :WTP Structured Document     
                            【Eclipse插件開發(fā)】基于WTP開發(fā)自定義的JSP編輯器(五) :WTP Structured Model     
                            【Eclipse插件開發(fā)】基于WTP開發(fā)自定義的JSP編輯器(七):WTP數(shù)據(jù)模型總結和模型管理    
                            【Eclipse插件開發(fā)】基于WTP開發(fā)自定義的JSP編輯器(十):WTP TLD內(nèi)容模型介紹     

                          【開發(fā)自定義的IAutoEditStrategy實現(xiàn)】    
          /**
           * 針對JSP_DIRECTIVE分區(qū)的自動編輯策略
           *
           * 
          @author zhuxing (mailto:zhu_xing@live.cn)
           
          */
          /*
           * 修改歷史
           * $Log$ 
           
          */
          public class JSPDirectivePartitionAutoEditStrategy implements IAutoEditStrategy {
              
              
          /* (non-Javadoc)
               * @see org.eclipse.jface.text.IAutoEditStrategy#customizeDocumentCommand(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.DocumentCommand)
               
          */
              
          public void customizeDocumentCommand(IDocument document, DocumentCommand command) {
                  String text 
          = command.text;
                  
          if (!">".equals(text))
                      
          return ;
                  
                  IStructuredDocument structuredDocument 
          = (IStructuredDocument)document;
                  IStructuredDocumentRegion structuredDocumentRegion 
          = structuredDocument.getRegionAtCharacterOffset(command.offset);
                  ITextRegion currentRegion 
          = structuredDocumentRegion.getRegionAtCharacterOffset(command.offset);
                  
                  
          int startOffset = structuredDocumentRegion.getStartOffset(currentRegion);
                  
          int textLength = currentRegion.getTextLength();
                  
                  
          //執(zhí)行前提條件:1、用戶正在標簽名區(qū)域編輯;2、用戶編輯位置位于標簽名末端
                  if (currentRegion.getType() == DOMRegionContext.XML_TAG_NAME 
                          
          && command.offset >= startOffset +
           textLength) {
                      
          if (!
          hasBody(structuredDocumentRegion))
                          command.text 
          = "/>"
          ;
                  }
              }

              
          /**
               * 查詢對應的TLD內(nèi)容模型,判斷該標簽在TLD中定義的時候是否含有標簽體
               * 
               * 
          @param structuredDocumentRegion
               * 
          @return
               
          */
              
          private boolean hasBody(IStructuredDocumentRegion structuredDocumentRegion) {
                  
          //獲取標簽名稱
                  IStructuredDocument structuredDocument = structuredDocumentRegion.getParentDocument();
                  IStructuredModel structuredModel 
          = StructuredModelManager.getModelManager().getModelForRead(structuredDocument);
                  IDOMElement domElement 
          = (IDOMElement)structuredModel.getIndexedRegion(structuredDocumentRegion.getStartOffset());
                  String tagName 
          = domElement.getNodeName();
                  
                  
          /**
                   * 1、獲取位置相關的TLD Document列表
                   * 2、查找對應的TLD Element(Tag)定義
                   * 3、判斷TLD Element(Tag)定義中定義的bodycontent屬性是否為“empty”
                   
          */
                  TLDCMDocumentManager manager 
          = TaglibController.getTLDCMDocumentManager(structuredDocument);
                  List list 
          = manager.getCMDocumentTrackers(structuredDocumentRegion.getStartOffset());
                  
          for (Iterator iter = list.iterator(); iter.hasNext();) {
                      TaglibTracker tracker 
          = (TaglibTracker) iter.next();
                      TLDDocument tlDocument 
          = (TLDDocument)tracker.getDocument();
                      CMNode cmnode 
          = tlDocument.getElements().getNamedItem(tagName);
                      
          if (cmnode == null)
                          
          continue ;
                      
                      String bodyType 
          = ((TLDElementDeclaration)cmnode).getBodycontent();
                      
          if ("empty".equals(bodyType))
                          
          return false;
                      
          return true;
                  }
                  
          return false;
              }
              
          }

                          基本流程如下:
                          1、執(zhí)行條件判斷,我這邊假設用戶正在標簽名區(qū)域編輯(通過判斷編輯區(qū)域region的region type來判斷),并且編輯位置位于標簽名內(nèi)容末端           
                          2、查詢和當前文檔中特定位置相關的WTP TLD內(nèi)容模型,判斷該標簽在TLD文件中定義的時候是否聲明允許有標簽體
                          3、如果標簽在TLD中定義為不含有標簽體,則矯正為自動閉合,“>”--->“/>”

                          PS:有關語法Document、語義Doucment、WTP TLD Content Document等數(shù)據(jù)類型相關內(nèi)容請參見前面的章節(jié)。

                      【配置SourceViewerConfiguration】
                        將我們上面的開發(fā)的自動編輯策略配置到我們的SourceViewerConfiguration實現(xiàn)中:   
          /**
           * 自定義StructuredTextViewerConfiguration,基于WTP jst提供的StructuredTextViewerConfigurationJSP,
           * 后面會提供自定義的自動提示策略等擴展。
           *
           * 
          @author zhuxing (mailto:zhu_xing@live.cn)
           
          */
          /*
           * 修改歷史
           * $Log$ 
           
          */
          public class JSPStructuredTextViewerConfiguration extends
                  StructuredTextViewerConfigurationJSP {
              
          /* 
               * 提供自定義的自動提示策略
               * 
               * @see org.eclipse.jst.jsp.ui.StructuredTextViewerConfigurationJSP#getContentAssistProcessors(org.eclipse.jface.text.source.ISourceViewer, java.lang.String)
               
          */
              
          protected IContentAssistProcessor[] getContentAssistProcessors(ISourceViewer sourceViewer, String partitionType) {
                  
          //我們目前只自定義JSP標簽屬性值自動提示的情況,所以針對的分區(qū)類型為IJSPPartitions.JSP_DIRECTIVE
                  if (partitionType == IJSPPartitions.JSP_DIRECTIVE) {
                      
          return new IContentAssistProcessor[]{new CustomizedJSPContentAssistantProcessor(), new JSPContentAssistProcessor()};
                  }
                  
                  
          return super.getContentAssistProcessors(sourceViewer, partitionType);
              }
              
              
          /* 
               * 提供自定義的自動編輯策略
               * 
               * @see org.eclipse.jst.jsp.ui.StructuredTextViewerConfigurationJSP#getAutoEditStrategies(org.eclipse.jface.text.source.ISourceViewer, java.lang.String)
               
          */
              
          public IAutoEditStrategy[] getAutoEditStrategies(ISourceViewer sourceViewer, String contentType) {
                  
          //我們目前只自定義JSP標簽名有關的自動編輯策略,所以針對的分區(qū)類型為IJSPPartitions.JSP_DIRECTIVE
                  if (contentType == IJSPPartitions.JSP_DIRECTIVE) {
                      List
          <IAutoEditStrategy> strategies = new ArrayList<IAutoEditStrategy>();
                      
                      
          //WTP已配置的自動編輯策略
                      IAutoEditStrategy[] existingStrategies = super.getAutoEditStrategies(sourceViewer, contentType);
                      Collections.addAll(strategies, existingStrategies);
                      
                      
          //自定義的自動編輯策略
                      IAutoEditStrategy customizedStrategies = new JSPDirectivePartitionAutoEditStrategy();
                      strategies.add(customizedStrategies);
                      
                      
          return strategies.toArray(new IAutoEditStrategy[strategies.size()]);
                  }
                  
                  
          return super.getAutoEditStrategies(sourceViewer, contentType);
              }
              
          }

                      我們在我們自己的SourceViewerConfiguration實現(xiàn)JSPStructuredTextViewerConfiguration中覆寫了getAutoEditStrategies方法。由于我們只是演示定制標簽名輸入時候的自動編輯策略,所以針對的分區(qū)類型為IJSPPartitions.JSP_DIRECTIVE。

                      【效果演示】

                     
          如上圖所示,我們輸入了標簽名test1:test,而且光標位于標簽名文本內(nèi)容之后,此時WTP的源碼校驗器給出了錯誤提示,說我們的標簽缺少對應的閉合符號。

                     我們看一下test1:test標簽對應的TLD定義,定位為不允許有標簽體:

          <?xml version="1.0" encoding="UTF-8"?>
          <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN" "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">
          <taglib>
              
          <tlibversion>1.0</tlibversion>
              
          <jspversion>1.0</jspversion>
              
          <shortname>test1</shortname>
              
          <uri>http://www.aygfsteel.com/zhuxing/tags/test1</uri>
              
          <tag>
                  
          <name>test</name>
                  
          <tagclass>any</tagclass>
                  
          <bodycontent>empty</bodycontent>
                  <attribute>
                      
          <name>scope</name>
                      
          <required>true</required>
                      
          <rtexprvalue>true</rtexprvalue>
                  
          </attribute>
              
          </tag>
          </taglib>
                     
                      根據(jù)需求,當我們在圖中光標位置輸入“>”的時候,我們前面開發(fā)的自動編輯策略會自動將其矯正為合法的結束符“/>”,效果如下:

                      
                      對比如下,如果沒有應用自動編輯策略,則會得到如下源碼校驗錯誤:


                  【后記】
                      提醒:從需求上講,我們示例中開發(fā)的自動編輯策略其實是非常簡單的。但是將其放置到一個定制WTP StructuredTextEditor的場景中,就不可避免的和我們前面介紹的WTP基礎數(shù)據(jù)模型的知識打交道,在這里再次強調(diào),前面介紹的WTP各種數(shù)據(jù)模型一定要熟練搞清楚,基礎中的基礎!!!

                       源碼為實際工程以Export ---> Archive File方式導出的,下載鏈接:WTP StructuredTextEditor自動編輯策略定制示例源碼

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

          posted on 2008-10-20 15:50 zhuxing 閱讀(3354) 評論(3)  編輯  收藏 所屬分類: Eclipse Plug-in & OSGIWTP(Web Tools Platform)

          評論

          # re: 【Eclipse插件開發(fā)】基于WTP開發(fā)自定義的JSP編輯器(十二):定制自動編輯策略(Auto Edit Strategy)  回復  更多評論   

          有個問題想請教一下,我想導入org.eclipse.wst.dtd.core這個插件,但是發(fā)現(xiàn)在RCP中無法加載該插件,我想是應該該插件一些依賴沒有加進來,那么我該怎么知道需要再添加那些插件作為依賴啊?
          2008-10-20 19:32 | 飛揚的麥子

          # re: 【Eclipse插件開發(fā)】基于WTP開發(fā)自定義的JSP編輯器(十二):定制自動編輯策略(Auto Edit Strategy)  回復  更多評論   

          1、首先確定是否是你說的缺少依賴的問題
          2、簡單的插件依賴關系缺少,結合編譯錯誤稍微看一下應該就可以解決了
          3、如果真的插件依賴關系比較復雜,可以借助Plug-in Dependencies視圖
          2008-10-21 09:39 | zhuxing

          # re: 【Eclipse插件開發(fā)】基于WTP開發(fā)自定義的JSP編輯器(十二):定制自動編輯策略(Auto Edit Strategy)  回復  更多評論   

          如果想實現(xiàn)驗證后對編輯器屬性文字進行相關顏色、字體樣式設置,應該怎么做呢?
          2013-08-29 10:38 | cat
          主站蜘蛛池模板: 铜陵市| 嘉荫县| 乌拉特前旗| 武清区| 普定县| 济阳县| 改则县| 新郑市| 南开区| 崇仁县| 长沙县| 扶绥县| 甘泉县| 达尔| 灌云县| 镇远县| 张掖市| 读书| 延庆县| 沙田区| 八宿县| 成武县| 青岛市| 丰台区| 富阳市| 桑日县| 青浦区| 措勤县| 成安县| 府谷县| 汉中市| 布尔津县| 扎鲁特旗| 延长县| 曲松县| 迁西县| 周口市| 墨竹工卡县| 东源县| 阜城县| 库伦旗|