Live a simple life

沉默(zhu_xing@live.cn)
随笔 - 48, 文章 - 0, 评论 - 132, 引用 - 0
数据加载中……

【Eclipse插件开发】基于WTP开发自定义的JSP编辑器(十二):定制自动编辑策略(Auto Edit Strategy)

            JFace Text Framework框架的一个重要的功能特征就是自动编辑策略,它允许用户对输入的内容(准确的说应该是即将来临的Document修改^_^)做即时编辑,然后又会透明的将用户的修改付诸于实现(即应用到当前文档)。在本节,我们将在前两节有关TLD Content Model的基础上开发一个自动编辑策略。

        【JFace Text Framework 自动编辑策略原理介绍】

         【JDT Java源码编辑器自动编辑策略演示】
          我们每个使用Eclipse JDT进行Java编程的开发者都会对JDT中Java源码编辑器的自动编辑策略印象深刻,它给编码人员带来了很大的方便。举例如下:
     
            如上图所示,我们在编写一个新的函数,图中黑色竖线“|”就是光标所在处,当我们按下回车键的时候,效果变为如下:
     
                如上图所示,当我们输入回车键之后,JDT Java源码编辑器自动帮我们矫正了内容(text)和位置(offset):原来的输入内容应该是“\r\n”,JDT Java源码编辑器自动帮我们矫正为“\r\n\t\t\r\n\t}”;根据“\r\n”内容推算,输入后光标位置应该位于28行的起始处,JDT Java源码编辑器自动帮我们矫正为离28行其实处两个“\t”的距离。

            【自动编辑流程和主要角色】
                                
                上图就演示了自动编辑过程:
                1、用户编辑,键盘事件
                2、根据键盘事件,对事件信息进行分析,拼装到名为DocumentCommand的数据结构中,该数据结构中包含了用户的输入内容(text)、光标位置(offset)等信息,例如,上面JDT的例子中用户的输入内容为“\r\n”。这一步JFace Text Framework帮用户解决了
                3、调用自动编辑策略,对应DocumentCommand中数据进行自定义矫正,例如,JDT Java源码编辑器的自动编辑策略将输入内容矫正为“\r\n\t\t\r\n\t}”。用户自己负责,JDT Java源码编辑器在这边干活了,提供了自己的IAutoEditStrategy^_^
                4、将用户矫正后的DocumentCommand应用到对应编辑器(说白了,就是转化为一个Document replace动作执行)。这一步JFace Text Framework帮用户解决了
                
                我们可以看到,JFace Text Framework已经替我们干了大部分活,我们需要关心的是如下两个角色:    
                org.eclipse.jface.text.DocumentCommand:数据载体,封装了一个文本变化(text modification)的信息,例如输入内容(text)、光标位置(offset)、长度(length)等等。我们要做的恰恰就是在我们自己的自动编辑策略中对DocumentCommand中的内容做矫正,然后JFace Text Framework会自动帮我们应用到目标IDocument中。
                org.eclipse.jface.text.IAutoEditStrategy:自动编辑编辑策略,根据不同应用场景对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】
            
上面我们已经讲了自动编辑的流程和主要角色,可以大家都有个疑问:IAutoEditStrategy到底是如何被自动调用的?IAutoEditStrategy实现需要被配置到对应的SourceViewerConfiguration中,并和对应的内容类型(很多时候也可以理解为分区类型)绑定。JFace Text Framework会在初始化编辑器实例的时候读取用户的配置,然后根据不同的内容类型去查找对应的自动编辑器策略。 
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、有关内容类型(分区类型)可以参考前面章节的内容; 2、原有的IAutoIndentStrategy接口Eclipse已经不推荐使用^_^

            【定制WTP StructuredTextEditor的自动编辑策略】
         
【需求】
                当用户输入标签结束符“>”时,如果标签在TLD中定义为不含有标签体(即bodycontent属性值为empty),则自动将用户的输入内容矫正为“/>”。
                
                【前提知识】
                  对WTP基本数据模型不很了解的可以参见一下前面的相关章节:
                  【Eclipse插件开发】基于WTP开发自定义的JSP编辑器(三) :WTP Structured Document     
                  【Eclipse插件开发】基于WTP开发自定义的JSP编辑器(五) :WTP Structured Model     
                  【Eclipse插件开发】基于WTP开发自定义的JSP编辑器(七):WTP数据模型总结和模型管理    
                  【Eclipse插件开发】基于WTP开发自定义的JSP编辑器(十):WTP TLD内容模型介绍     

                【开发自定义的IAutoEditStrategy实现】    
/**
 * 针对JSP_DIRECTIVE分区的自动编辑策略
 *
 * 
@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();
        
        
//执行前提条件:1、用户正在标签名区域编辑;2、用户编辑位置位于标签名末端
        if (currentRegion.getType() == DOMRegionContext.XML_TAG_NAME 
                
&& command.offset >= startOffset +
 textLength) {
            
if (!
hasBody(structuredDocumentRegion))
                command.text 
= "/>"
;
        }
    }

    
/**
     * 查询对应的TLD内容模型,判断该标签在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、执行条件判断,我这边假设用户正在标签名区域编辑(通过判断编辑区域region的region type来判断),并且编辑位置位于标签名内容末端           
                2、查询和当前文档中特定位置相关的WTP TLD内容模型,判断该标签在TLD文件中定义的时候是否声明允许有标签体
                3、如果标签在TLD中定义为不含有标签体,则矫正为自动闭合,“>”--->“/>”

                PS:有关语法Document、语义Doucment、WTP TLD Content Document等数据类型相关内容请参见前面的章节。

            【配置SourceViewerConfiguration】
              将我们上面的开发的自动编辑策略配置到我们的SourceViewerConfiguration实现中:   
/**
 * 自定义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标签属性值自动提示的情况,所以针对的分区类型为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标签名有关的自动编辑策略,所以针对的分区类型为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实现JSPStructuredTextViewerConfiguration中覆写了getAutoEditStrategies方法。由于我们只是演示定制标签名输入时候的自动编辑策略,所以针对的分区类型为IJSPPartitions.JSP_DIRECTIVE。

            【效果演示】

           
如上图所示,我们输入了标签名test1:test,而且光标位于标签名文本内容之后,此时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.blogjava.net/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>
           
            根据需求,当我们在图中光标位置输入“>”的时候,我们前面开发的自动编辑策略会自动将其矫正为合法的结束符“/>”,效果如下:

            
            对比如下,如果没有应用自动编辑策略,则会得到如下源码校验错误:


        【后记】
            提醒:从需求上讲,我们示例中开发的自动编辑策略其实是非常简单的。但是将其放置到一个定制WTP StructuredTextEditor的场景中,就不可避免的和我们前面介绍的WTP基础数据模型的知识打交道,在这里再次强调,前面介绍的WTP各种数据模型一定要熟练搞清楚,基础中的基础!!!

             源码为实际工程以Export ---> Archive File方式导出的,下载链接:WTP StructuredTextEditor自动编辑策略定制示例源码

本博客中的所有文章、随笔除了标题中含有引用或者转载字样的,其他均为原创。转载请注明出处,谢谢!

posted on 2008-10-20 15:50 zhuxing 阅读(3216) 评论(3)  编辑  收藏 所属分类: Eclipse Plug-in & OSGIWTP(Web Tools Platform)

评论

# re: 【Eclipse插件开发】基于WTP开发自定义的JSP编辑器(十二):定制自动编辑策略(Auto Edit Strategy)  回复  更多评论   

有个问题想请教一下,我想导入org.eclipse.wst.dtd.core这个插件,但是发现在RCP中无法加载该插件,我想是应该该插件一些依赖没有加进来,那么我该怎么知道需要再添加那些插件作为依赖啊?
2008-10-20 19:32 | 飞扬的麦子

# re: 【Eclipse插件开发】基于WTP开发自定义的JSP编辑器(十二):定制自动编辑策略(Auto Edit Strategy)  回复  更多评论   

1、首先确定是否是你说的缺少依赖的问题
2、简单的插件依赖关系缺少,结合编译错误稍微看一下应该就可以解决了
3、如果真的插件依赖关系比较复杂,可以借助Plug-in Dependencies视图
2008-10-21 09:39 | zhuxing

# re: 【Eclipse插件开发】基于WTP开发自定义的JSP编辑器(十二):定制自动编辑策略(Auto Edit Strategy)  回复  更多评论   

如果想实现验证后对编辑器属性文字进行相关颜色、字体样式设置,应该怎么做呢?
2013-08-29 10:38 | cat

只有注册用户登录后才能发表评论。


网站导航: