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)容(準(zhǔn)確的說應(yīng)該是即將來臨的Document修改^_^)做即時編輯,然后又會透明的將用戶的修改付諸于實(shí)現(xiàn)(即應(yīng)用到當(dāng)前文檔)。在本節(jié),我們將在前兩節(jié)有關(guān)TLD Content Model的基礎(chǔ)上開發(fā)一個自動編輯策略。

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

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

                      【自動編輯流程和主要角色】
                                          
                          上圖就演示了自動編輯過程:
                          1、用戶編輯,鍵盤事件
                          2、根據(jù)鍵盤事件,對事件信息進(jìn)行分析,拼裝到名為DocumentCommand的數(shù)據(jù)結(jié)構(gòu)中,該數(shù)據(jù)結(jié)構(gòu)中包含了用戶的輸入內(nèi)容(text)、光標(biāo)位置(offset)等信息,例如,上面JDT的例子中用戶的輸入內(nèi)容為“\r\n”。這一步JFace Text Framework幫用戶解決了
                          3、調(diào)用自動編輯策略,對應(yīng)DocumentCommand中數(shù)據(jù)進(jìn)行自定義矯正,例如,JDT Java源碼編輯器的自動編輯策略將輸入內(nèi)容矯正為“\r\n\t\t\r\n\t}”。用戶自己負(fù)責(zé),JDT Java源碼編輯器在這邊干活了,提供了自己的IAutoEditStrategy^_^
                          4、將用戶矯正后的DocumentCommand應(yīng)用到對應(yīng)編輯器(說白了,就是轉(zhuǎn)化為一個Document replace動作執(zhí)行)。這一步JFace Text Framework幫用戶解決了
                          
                          我們可以看到,JFace Text Framework已經(jīng)替我們干了大部分活,我們需要關(guān)心的是如下兩個角色:    
                          org.eclipse.jface.text.DocumentCommand:數(shù)據(jù)載體,封裝了一個文本變化(text modification)的信息,例如輸入內(nèi)容(text)、光標(biāo)位置(offset)、長度(length)等等。我們要做的恰恰就是在我們自己的自動編輯策略中對DocumentCommand中的內(nèi)容做矯正,然后JFace Text Framework會自動幫我們應(yīng)用到目標(biāo)IDocument中。
                          org.eclipse.jface.text.IAutoEditStrategy:自動編輯編輯策略,根據(jù)不同應(yīng)用場景對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實(shí)現(xiàn)需要被配置到對應(yīng)的SourceViewerConfiguration中,并和對應(yīng)的內(nèi)容類型(很多時候也可以理解為分區(qū)類型)綁定。JFace Text Framework會在初始化編輯器實(shí)例的時候讀取用戶的配置,然后根據(jù)不同的內(nèi)容類型去查找對應(yīng)的自動編輯器策略。 
          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、有關(guān)內(nèi)容類型(分區(qū)類型)可以參考前面章節(jié)的內(nèi)容; 2、原有的IAutoIndentStrategy接口Eclipse已經(jīng)不推薦使用^_^

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

                          【開發(fā)自定義的IAutoEditStrategy實(shí)現(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、用戶正在標(biāo)簽名區(qū)域編輯;2、用戶編輯位置位于標(biāo)簽名末端
                  if (currentRegion.getType() == DOMRegionContext.XML_TAG_NAME 
                          
          && command.offset >= startOffset +
           textLength) {
                      
          if (!
          hasBody(structuredDocumentRegion))
                          command.text 
          = "/>"
          ;
                  }
              }

              
          /**
               * 查詢對應(yīng)的TLD內(nèi)容模型,判斷該標(biāo)簽在TLD中定義的時候是否含有標(biāo)簽體
               * 
               * 
          @param structuredDocumentRegion
               * 
          @return
               
          */
              
          private boolean hasBody(IStructuredDocumentRegion structuredDocumentRegion) {
                  
          //獲取標(biāo)簽名稱
                  IStructuredDocument structuredDocument = structuredDocumentRegion.getParentDocument();
                  IStructuredModel structuredModel 
          = StructuredModelManager.getModelManager().getModelForRead(structuredDocument);
                  IDOMElement domElement 
          = (IDOMElement)structuredModel.getIndexedRegion(structuredDocumentRegion.getStartOffset());
                  String tagName 
          = domElement.getNodeName();
                  
                  
          /**
                   * 1、獲取位置相關(guān)的TLD Document列表
                   * 2、查找對應(yīng)的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í)行條件判斷,我這邊假設(shè)用戶正在標(biāo)簽名區(qū)域編輯(通過判斷編輯區(qū)域region的region type來判斷),并且編輯位置位于標(biāo)簽名內(nèi)容末端           
                          2、查詢和當(dāng)前文檔中特定位置相關(guān)的WTP TLD內(nèi)容模型,判斷該標(biāo)簽在TLD文件中定義的時候是否聲明允許有標(biāo)簽體
                          3、如果標(biāo)簽在TLD中定義為不含有標(biāo)簽體,則矯正為自動閉合,“>”--->“/>”

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

                      【配置SourceViewerConfiguration】
                        將我們上面的開發(fā)的自動編輯策略配置到我們的SourceViewerConfiguration實(shí)現(xiàn)中:   
          /**
           * 自定義StructuredTextViewerConfiguration,基于WTP jst提供的StructuredTextViewerConfigurationJSP,
           * 后面會提供自定義的自動提示策略等擴(kuò)展。
           *
           * 
          @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標(biāo)簽屬性值自動提示的情況,所以針對的分區(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標(biāo)簽名有關(guān)的自動編輯策略,所以針對的分區(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實(shí)現(xiàn)JSPStructuredTextViewerConfiguration中覆寫了getAutoEditStrategies方法。由于我們只是演示定制標(biāo)簽名輸入時候的自動編輯策略,所以針對的分區(qū)類型為IJSPPartitions.JSP_DIRECTIVE。

                      【效果演示】

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

                     我們看一下test1:test標(biāo)簽對應(yīng)的TLD定義,定位為不允許有標(biāo)簽體:

          <?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ù)需求,當(dāng)我們在圖中光標(biāo)位置輸入“>”的時候,我們前面開發(fā)的自動編輯策略會自動將其矯正為合法的結(jié)束符“/>”,效果如下:

                      
                      對比如下,如果沒有應(yīng)用自動編輯策略,則會得到如下源碼校驗(yàn)錯誤:


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

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

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

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

          評論

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

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

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

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

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

          如果想實(shí)現(xiàn)驗(yàn)證后對編輯器屬性文字進(jìn)行相關(guān)顏色、字體樣式設(shè)置,應(yīng)該怎么做呢?
          2013-08-29 10:38 | cat
          主站蜘蛛池模板: 石林| 昆明市| 新和县| 汉中市| 郁南县| 关岭| 三门县| 安丘市| 平原县| 广河县| 鄯善县| 仲巴县| 米脂县| 奉节县| 新和县| 城口县| 弋阳县| 清苑县| 临汾市| 蒙城县| 柏乡县| 六枝特区| 田阳县| 寿宁县| 正安县| 建阳市| 德阳市| 太谷县| 远安县| 武邑县| 渑池县| 乐亭县| 宁海县| 兴文县| 黔南| 新疆| 禹州市| 利川市| 潜江市| 黄梅县| 虞城县|