前文回顧:html
1 插件學習篇java
2 簡單的創建插件工程以及模型文件分析sql
3 利用擴展點,開發透視圖編程
4 SWT編程須知api
5 SWT簡單控件的使用與佈局搭配數組
6 SWT複雜空間與佈局搭配eclipse
7 SWT佈局詳解jsp
8 IPreferenceStore使用詳解編輯器
這篇講解依然是一個重頭的技巧,就是【代碼的着色】。你們在使用各類編輯器的時候都會發現,有些關鍵詞和一些註釋之類的都會以不一樣的顏色進行顯示,那麼它是怎麼作到呢?先看一下示例的運行效果!ide
憑空思考下:
【IO書寫】首先這些輸入的東西多是以一些字符串的形式進行書寫。
【分詞分塊】而後必然通過分詞,把他們分紅一塊一塊的。
【着色】這樣以後掃描每一個分塊進行分類,不一樣的分類顯示不一樣的顏色!
SourceViewer!—— 代碼編寫的視圖窗口
這裏主要是用了一個特殊的view模型:SourceViewer,它是一種特殊的文本視圖,讓咱們能夠配置本身的代碼顯示規則!看一下官方的API
SourceViewer(Composite parent, IVerticalRuler ruler, int styles) //Constructs a new source viewer.
這裏第一個跟第三個參數都跟普通的Control控件差很少。
中間的參數用於設置代碼的一個垂直規則(其實就是編輯器左邊和右邊有提示效果的垂直邊欄),想了解的話能夠參考它的官方API。
使用方法以下:
VerticalRuler(int width) //Constructs a vertical ruler with the given width.
若是不想有其餘的配置,能夠設置它的寬度爲0。
接下來須要設置它的配置對象,用於對着色,分詞等信息進行配置。
public void configure(SourceViewerConfiguration configuration); /*Description copied from interface: ISourceViewer Configures the source viewer using the given configuration. Prior to 3.0 this method can only be called once. Since 3.0 this method can be called again after a call to ISourceViewerExtension2.unconfigure(). Specified by: configure in interface ISourceViewer Parameters: configuration - the source viewer configuration to be used */
Document!—— 代碼文檔,提供切分分塊等操做.
這個文檔對象須要咱們提供一個分塊對象,對輸入的文件流進行分塊。這裏主要使用一個接口IDocumentPartitioner,經常使用的實現類是FastPartitioner。
public FastPartitioner(IPartitionTokenScanner scanner, String[] legalContentTypes)
第一個參數是一個掃描對象,第二個參數用於分塊的規則。
抽象的設想大概如上面所述,可是作起來仍是很困難,雖然知道了用什麼類或者方法,可是如何組織纔是最大的困難!這裏藉助一個開源源碼,書寫SQL語句的編輯器,來說解一下代碼着色的主要過程!
咱們要解決的問題大體以下:
如何進行分塊?
如何進行着色?
如何附加到編輯器上?
一下是代碼編寫的思惟導圖
全部自定儀的配置類都要繼承Eclipse的SourceViewerConfiguration類。
須要重寫的類大體有以下幾個:
1.1 getConfiguredContentTypes 這個方法用於返回一個數組,這個數組規定了須要進行處理的類型,當遇到這種類型匹配的分塊時,就會進行響應的處理。這裏的業務場景是這樣:咱們編寫SQL語句,相應進行處理着色的應該是關鍵字、字符串、註釋。其餘的輸入對象咱們就不須要進行處理了。下面即是返回的三種類型標識。
public String[] getConfiguredContentTypes(ISourceViewer sourceViewer) { return new String[] { IDocument.DEFAULT_CONTENT_TYPE, SQLPartitionScanner.SQL_COMMENT, SQLPartitionScanner.SQL_STRING }; }
1.2 接下來是對應的三種掃描器
private RuleBasedScanner getCommentScanner(){//註釋掃描器 RuleBasedScanner scanner = new RuleBasedScanner(); EditorColorProvider colorProvider = Activator.getDefault().getEditorColorProvider(); scanner.setDefaultReturnToken( colorProvider.getToken(Activator.PREF_COLOR_COMMENT)); return scanner; } private RuleBasedScanner getStringScanner(){//字符串掃描器 RuleBasedScanner scanner = new RuleBasedScanner(); EditorColorProvider colorProvider = Activator.getDefault().getEditorColorProvider(); scanner.setDefaultReturnToken( colorProvider.getToken(Activator.PREF_COLOR_STRING)); return scanner; } private RuleBasedScanner getDefaultScanner(){//默認關鍵字掃描器 return new SQLKeywordPartitionScanner(); }
這裏根據自定義編寫咱們本身的關鍵字掃描器
public static class SQLKeywordPartitionScanner extends RuleBasedScanner { private static String[] KEYWORDS = {"select", "update", "insert", "into", "delete", "from", "where", "values", "set", "order", "by", "left", "outer", "join", "having", "group", "create", "alter", "drop", "table"}; public SQLKeywordPartitionScanner(){ IToken keyword = Activator.getDefault().getEditorColorProvider().getToken( Activator.PREF_COLOR_KEYWORD); IToken other = Activator.getDefault().getEditorColorProvider().getToken( Activator.PREF_COLOR_DEFAULT); WordRule wordRule = new WordRule(new IWordDetector() { public boolean isWordPart(char c) { return Character.isJavaIdentifierPart(c); } public boolean isWordStart(char c) { return Character.isJavaIdentifierStart(c); } }, other); for (int i = 0; i < KEYWORDS.length; i++) { wordRule.addWord(KEYWORDS[i], keyword); wordRule.addWord(KEYWORDS[i].toUpperCase(), keyword); } IRule[] rules = new IRule[2]; rules[0] = wordRule; rules[1] = new WhitespaceRule(new IWhitespaceDetector() { public boolean isWhitespace(char character) { return Character.isWhitespace(character); } }); setRules(rules); } }
1.3 getPresentationReconciler 是源碼視圖使用的表現協調器,翻譯的比較蹩腳,其實就是每一種類型的分塊如何展示!
public IPresentationReconciler getPresentationReconciler(ISourceViewer sourceViewer) { PresentationReconciler reconciler = new PresentationReconciler(); DefaultDamagerRepairer commentDR = new DefaultDamagerRepairer(getCommentScanner()); reconciler.setDamager(commentDR, SQLPartitionScanner.SQL_COMMENT); reconciler.setRepairer(commentDR, SQLPartitionScanner.SQL_COMMENT); DefaultDamagerRepairer stringDR = new DefaultDamagerRepairer(getStringScanner()); reconciler.setDamager(stringDR, SQLPartitionScanner.SQL_STRING); reconciler.setRepairer(stringDR, SQLPartitionScanner.SQL_STRING); DefaultDamagerRepairer keywordDR = new DefaultDamagerRepairer(getDefaultScanner()); reconciler.setDamager(keywordDR, IDocument.DEFAULT_CONTENT_TYPE); reconciler.setRepairer(keywordDR, IDocument.DEFAULT_CONTENT_TYPE); return reconciler; }
1.4 着色方法EditorColorProvider,提供對不一樣的類型顯示不一樣的顏色
這個類提供了一個map,裏面包含了對應的類型及其對應的RGB顏色的Color對象,經過查詢這個map,能夠獲取相應的顏色,進行着色。
public IToken getToken(String prefKey){ Token token = (Token) tokenTable.get(prefKey); if (token == null){ String colorName = store.getString(prefKey); RGB rgb = StringConverter.asRGB(colorName); token = new Token(new TextAttribute(getColor(rgb))); tokenTable.put(prefKey, token); } return token; }
關於這裏面的store,是前一篇講解過的插件初始化設定的參數。用法能夠參考前一篇帖子,這裏貼出initializer類中的實現:
store.setDefault(Activator.PREF_COLOR_DEFAULT, StringConverter.asString(new RGB(0,0,0))); store.setDefault(Activator.PREF_COLOR_COMMENT, StringConverter.asString(new RGB(0,128,0))); store.setDefault(Activator.PREF_COLOR_STRING, StringConverter.asString(new RGB(0,0,255))); store.setDefault(Activator.PREF_COLOR_KEYWORD, StringConverter.asString(new RGB(128,0,128)));
這裏是針對註釋以及字符串進行分塊。
須要在夠咱函數中建立一個分塊規則:IPredicateRule 數組。具體規則的參數能夠參考下面的參數。
public class SQLPartitionScanner extends RuleBasedPartitionScanner { public static final String SQL_COMMENT = "__sql_comment"; public static final String SQL_STRING = "__sql_string"; public SQLPartitionScanner() { IPredicateRule[] rules = new IPredicateRule[4]; IToken comment = new Token(SQL_COMMENT); rules[0] = new MultiLineRule("/*", "*/", comment, (char) 0, true);
/*
startSequence the pattern's start sequence
endSequence the pattern's end sequence
token the token to be returned on success
escapeCharacter the escape character
breaksOnEOF indicates whether the end of the file terminates this rule successfully
*/ rules[1] = new EndOfLineRule("--", comment); /*
startSequence the pattern's start sequence
token the token to be returned on success
*/ IToken string = new Token(SQL_STRING); rules[2] = new SingleLineRule("\"", "\"", string, '\\'); rules[3] = new SingleLineRule("\'", "\'", string, '\\'); /*
startSequence the pattern's start sequence
endSequence the pattern's end sequence
token the token to be returned on success
escapeCharacter the escape character
*/ setPredicateRules(rules); } }
首先在合適的位置觸發編輯對話框的彈出!
DDLEditDialog dialog = new DDLEditDialog(viewer.getControl().getShell()); dialog.open();
設定SQL配置類,以及分塊掃描器
SourceViewer sqlEditor = new SourceViewer(parent, new VerticalRuler(0), SWT.V_SCROLL | SWT.H_SCROLL); //設置配置項 sqlEditor.configure(new SQLConfiguration()); sqlEditor.getTextWidget().setFont(JFaceResources.getTextFont()); Document document = new Document();
//設置分塊掃描器 IDocumentPartitioner partitioner = new FastPartitioner( new SQLPartitionScanner(), new String[] { SQLPartitionScanner.SQL_COMMENT, SQLPartitionScanner.SQL_STRING }); partitioner.connect(document); document.setDocumentPartitioner(partitioner); sqlEditor.setDocument(document); sqlEditor.getControl().setLayoutData(new GridData(GridData.FILL_BOTH)); StyledText text = sqlEditor.getTextWidget();
源碼ZIP包下載:源碼插件下載
使用方法:
1 打開視圖SampleView
2 雙擊下面的任意一行!
3 彈出對話框進行編輯!
1 Activator插件啓動類
1 package testpreference; 2 3 import org.eclipse.jface.preference.IPreferenceStore; 4 import org.eclipse.jface.resource.ImageDescriptor; 5 import org.eclipse.ui.plugin.AbstractUIPlugin; 6 import org.osgi.framework.BundleContext; 7 8 import testpreference.dialog.EditorColorProvider; 9 10 /** 11 * The activator class controls the plug-in life cycle 12 */ 13 public class Activator extends AbstractUIPlugin { 14 15 // The plug-in ID 16 public static final String PLUGIN_ID = "TestPreference"; 17 18 // for SQL editor 19 public static final String PREF_COLOR_DEFAULT = "colorDefault"; 20 public static final String PREF_COLOR_COMMENT = "colorComment"; 21 public static final String PREF_COLOR_STRING = "colorString"; 22 public static final String PREF_COLOR_KEYWORD = "colorKeyword"; 23 24 private IPreferenceStore store; 25 private EditorColorProvider colorProvider; 26 // The shared instance 27 private static Activator plugin; 28 29 public Activator() { 30 } 31 32 public void start(BundleContext context) throws Exception { 33 super.start(context); 34 plugin = this; 35 this.colorProvider = new EditorColorProvider(getPreferenceStore()); 36 } 37 38 public EditorColorProvider getEditorColorProvider(){ 39 return this.colorProvider; 40 } 41 42 ... 43 44 public static Activator getDefault() { 45 return plugin; 46 } 47 }
2 Action觸發對話框
1 doubleClickAction = new Action() { 2 public void run() { 3 DDLEditDialog dialog = new DDLEditDialog(viewer.getControl().getShell()); 4 dialog.open(); 5 } 6 };
3 對話框實現類
1 package testpreference.dialog; 2 3 import org.eclipse.jface.dialogs.Dialog; 4 import org.eclipse.jface.dialogs.IDialogConstants; 5 import org.eclipse.jface.resource.JFaceResources; 6 import org.eclipse.jface.text.Document; 7 import org.eclipse.jface.text.IDocument; 8 import org.eclipse.jface.text.IDocumentPartitioner; 9 import org.eclipse.jface.text.presentation.IPresentationReconciler; 10 import org.eclipse.jface.text.presentation.PresentationReconciler; 11 import org.eclipse.jface.text.rules.DefaultDamagerRepairer; 12 import org.eclipse.jface.text.rules.EndOfLineRule; 13 import org.eclipse.jface.text.rules.FastPartitioner; 14 import org.eclipse.jface.text.rules.IPredicateRule; 15 import org.eclipse.jface.text.rules.IRule; 16 import org.eclipse.jface.text.rules.IToken; 17 import org.eclipse.jface.text.rules.IWhitespaceDetector; 18 import org.eclipse.jface.text.rules.IWordDetector; 19 import org.eclipse.jface.text.rules.MultiLineRule; 20 import org.eclipse.jface.text.rules.RuleBasedPartitionScanner; 21 import org.eclipse.jface.text.rules.RuleBasedScanner; 22 import org.eclipse.jface.text.rules.SingleLineRule; 23 import org.eclipse.jface.text.rules.Token; 24 import org.eclipse.jface.text.rules.WhitespaceRule; 25 import org.eclipse.jface.text.rules.WordRule; 26 import org.eclipse.jface.text.source.ISourceViewer; 27 import org.eclipse.jface.text.source.SourceViewer; 28 import org.eclipse.jface.text.source.SourceViewerConfiguration; 29 import org.eclipse.jface.text.source.VerticalRuler; 30 import org.eclipse.swt.SWT; 31 import org.eclipse.swt.custom.StyledText; 32 import org.eclipse.swt.graphics.Point; 33 import org.eclipse.swt.layout.GridData; 34 import org.eclipse.swt.widgets.Composite; 35 import org.eclipse.swt.widgets.Control; 36 import org.eclipse.swt.widgets.Shell; 37 38 import testpreference.Activator; 39 40 public class DDLEditDialog extends Dialog{ 41 42 public DDLEditDialog(Shell parent) { 43 super(parent); 44 setShellStyle(getShellStyle()|SWT.RESIZE); 45 } 46 47 protected Point getInitialSize() { 48 return new Point(600, 450); 49 } 50 51 protected Control createDialogArea(Composite parent) { 52 getShell().setText("DDL"); 53 54 SourceViewer sqlEditor = new SourceViewer(parent, new VerticalRuler(0), SWT.V_SCROLL | SWT.H_SCROLL); 55 //設置配置項 56 sqlEditor.configure(new SQLConfiguration()); 57 58 sqlEditor.getTextWidget().setFont(JFaceResources.getTextFont()); 59 60 Document document = new Document(); 61 IDocumentPartitioner partitioner = new FastPartitioner( 62 new SQLPartitionScanner(), 63 new String[] { 64 SQLPartitionScanner.SQL_COMMENT, 65 SQLPartitionScanner.SQL_STRING 66 }); 67 partitioner.connect(document); 68 document.setDocumentPartitioner(partitioner); 69 sqlEditor.setDocument(document); 70 sqlEditor.getControl().setLayoutData(new GridData(GridData.FILL_BOTH)); 71 72 StyledText text = sqlEditor.getTextWidget(); 73 74 return text; 75 } 76 77 protected void createButtonsForButtonBar(Composite parent) { 78 createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true); 79 } 80 81 public class SQLConfiguration extends SourceViewerConfiguration { 82 83 public String[] getConfiguredContentTypes(ISourceViewer sourceViewer) { 84 return new String[] { IDocument.DEFAULT_CONTENT_TYPE, 85 SQLPartitionScanner.SQL_COMMENT, 86 SQLPartitionScanner.SQL_STRING }; 87 } 88 89 private RuleBasedScanner getCommentScanner(){ 90 RuleBasedScanner scanner = new RuleBasedScanner(); 91 EditorColorProvider colorProvider = Activator.getDefault().getEditorColorProvider(); 92 scanner.setDefaultReturnToken( 93 colorProvider.getToken(Activator.PREF_COLOR_COMMENT)); 94 return scanner; 95 } 96 97 private RuleBasedScanner getStringScanner(){ 98 RuleBasedScanner scanner = new RuleBasedScanner(); 99 EditorColorProvider colorProvider = Activator.getDefault().getEditorColorProvider(); 100 scanner.setDefaultReturnToken( 101 colorProvider.getToken(Activator.PREF_COLOR_STRING)); 102 return scanner; 103 } 104 105 private RuleBasedScanner getDefaultScanner(){ 106 return new SQLKeywordPartitionScanner(); 107 } 108 109 110 public IPresentationReconciler getPresentationReconciler(ISourceViewer sourceViewer) { 111 112 PresentationReconciler reconciler = new PresentationReconciler(); 113 114 DefaultDamagerRepairer commentDR = new DefaultDamagerRepairer(getCommentScanner()); 115 reconciler.setDamager(commentDR, SQLPartitionScanner.SQL_COMMENT); 116 reconciler.setRepairer(commentDR, SQLPartitionScanner.SQL_COMMENT); 117 118 DefaultDamagerRepairer stringDR = new DefaultDamagerRepairer(getStringScanner()); 119 reconciler.setDamager(stringDR, SQLPartitionScanner.SQL_STRING); 120 reconciler.setRepairer(stringDR, SQLPartitionScanner.SQL_STRING); 121 122 DefaultDamagerRepairer keywordDR = new DefaultDamagerRepairer(getDefaultScanner()); 123 reconciler.setDamager(keywordDR, IDocument.DEFAULT_CONTENT_TYPE); 124 reconciler.setRepairer(keywordDR, IDocument.DEFAULT_CONTENT_TYPE); 125 126 return reconciler; 127 } 128 } 129 130 131 132 133 /** 134 * 關鍵詞分詞 135 * @author Administrator 136 * 137 */ 138 public static class SQLKeywordPartitionScanner extends RuleBasedScanner { 139 140 private static String[] KEYWORDS = {"select", "update", "insert", 141 "into", "delete", "from", "where", "values", "set", "order", "by", 142 "left", "outer", "join", "having", "group", "create", "alter", "drop", "table"}; 143 144 public SQLKeywordPartitionScanner(){ 145 IToken keyword = Activator.getDefault().getEditorColorProvider().getToken( 146 Activator.PREF_COLOR_KEYWORD); 147 IToken other = Activator.getDefault().getEditorColorProvider().getToken( 148 Activator.PREF_COLOR_DEFAULT); 149 150 WordRule wordRule = new WordRule(new IWordDetector() { 151 public boolean isWordPart(char c) { 152 return Character.isJavaIdentifierPart(c); 153 } 154 155 public boolean isWordStart(char c) { 156 return Character.isJavaIdentifierStart(c); 157 } 158 }, other); 159 for (int i = 0; i < KEYWORDS.length; i++) { 160 wordRule.addWord(KEYWORDS[i], keyword); 161 wordRule.addWord(KEYWORDS[i].toUpperCase(), keyword); 162 } 163 IRule[] rules = new IRule[2]; 164 rules[0] = wordRule; 165 rules[1] = new WhitespaceRule(new IWhitespaceDetector() { 166 public boolean isWhitespace(char character) { 167 return Character.isWhitespace(character); 168 } 169 }); 170 171 setRules(rules); 172 } 173 174 } 175 176 /** 177 * 用於SQL編輯分區,區分字符串或者註釋 178 * @author Administrator 179 * 180 */ 181 public class SQLPartitionScanner extends RuleBasedPartitionScanner { 182 183 public static final String SQL_COMMENT = "__sql_comment"; 184 public static final String SQL_STRING = "__sql_string"; 185 186 public SQLPartitionScanner() { 187 IPredicateRule[] rules = new IPredicateRule[4]; 188 189 IToken comment = new Token(SQL_COMMENT); 190 rules[0] = new MultiLineRule("/*", "*/", comment, (char) 0, true); 191 rules[1] = new EndOfLineRule("--", comment); 192 193 IToken string = new Token(SQL_STRING); 194 rules[2] = new SingleLineRule("\"", "\"", string, '\\'); 195 rules[3] = new SingleLineRule("\'", "\'", string, '\\'); 196 197 setPredicateRules(rules); 198 } 199 200 } 201 }
4 顏色提供類
1 package testpreference.dialog; 2 3 import java.util.HashMap; 4 import java.util.Iterator; 5 import java.util.Map; 6 7 import org.eclipse.jface.preference.IPreferenceStore; 8 import org.eclipse.jface.resource.StringConverter; 9 import org.eclipse.jface.text.TextAttribute; 10 import org.eclipse.jface.text.rules.IToken; 11 import org.eclipse.jface.text.rules.Token; 12 import org.eclipse.jface.util.PropertyChangeEvent; 13 import org.eclipse.swt.graphics.Color; 14 import org.eclipse.swt.graphics.RGB; 15 import org.eclipse.swt.widgets.Display; 16 17 public class EditorColorProvider { 18 19 private Map<RGB, Color> colorTable = new HashMap<RGB, Color>(10); 20 private Map<String, IToken> tokenTable = new HashMap<String, IToken>(10); 21 IPreferenceStore store; 22 23 public EditorColorProvider(IPreferenceStore store) { 24 this.store = store; 25 } 26 27 public IToken getToken(String prefKey){ 28 Token token = (Token) tokenTable.get(prefKey); 29 if (token == null){ 30 String colorName = store.getString(prefKey); 31 RGB rgb = StringConverter.asRGB(colorName); 32 token = new Token(new TextAttribute(getColor(rgb))); 33 tokenTable.put(prefKey, token); 34 } 35 return token; 36 } 37 38 public void dispose(){ 39 Iterator<Color> e = colorTable.values().iterator(); 40 while (e.hasNext()){ 41 e.next().dispose(); 42 } 43 } 44 45 public Color getColor(String prefKey){ 46 String colorName = store.getString(prefKey); 47 RGB rgb = StringConverter.asRGB(colorName); 48 return getColor(rgb); 49 } 50 51 private Color getColor(RGB rgb) { 52 Color color = (Color) colorTable.get(rgb); 53 if (color == null){ 54 color = new Color(Display.getCurrent(), rgb); 55 colorTable.put(rgb, color); 56 } 57 return color; 58 } 59 60 public boolean affectsTextPresentation(PropertyChangeEvent event){ 61 Token token = (Token) tokenTable.get(event.getProperty()); 62 return (token != null); 63 } 64 65 public void handlePreferenceStoreChanged(PropertyChangeEvent event){ 66 String prefKey = event.getProperty(); 67 Token token = (Token) tokenTable.get(prefKey); 68 if (token != null){ 69 String colorName = store.getString(prefKey); 70 RGB rgb = StringConverter.asRGB(colorName); 71 token.setData(new TextAttribute(getColor(rgb))); 72 } 73 } 74 }
5 preferenceStore設置初始化參數
1 package testpreference.preference; 2 3 import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer; 4 import org.eclipse.jface.preference.IPreferenceStore; 5 import org.eclipse.jface.resource.StringConverter; 6 import org.eclipse.swt.graphics.RGB; 7 8 import testpreference.Activator; 9 10 public class AbstractPreferenceInitializer1 extends 11 AbstractPreferenceInitializer { 12 13 public AbstractPreferenceInitializer1() { 14 // TODO Auto-generated constructor stub 15 } 16 17 @Override 18 public void initializeDefaultPreferences() { 19 IPreferenceStore store = Activator.getDefault().getPreferenceStore(); 20 21 // store.setDefault(Activator.PREF_PARAM_1, "hello"); 22 // store.setDefault(Activator.PREF_PARAM_2, "xingoo"); 23 24 store.setDefault(Activator.PREF_COLOR_DEFAULT, StringConverter.asString(new RGB(0,0,0))); 25 store.setDefault(Activator.PREF_COLOR_COMMENT, StringConverter.asString(new RGB(0,128,0))); 26 store.setDefault(Activator.PREF_COLOR_STRING, StringConverter.asString(new RGB(0,0,255))); 27 store.setDefault(Activator.PREF_COLOR_KEYWORD, StringConverter.asString(new RGB(128,0,128))); 28 } 29 }
因爲博主本身對這部分的代碼也沒有達到熟練使用的地步,所以編碼的過程有些混亂,這裏還須要多加練習和實踐,才能領會其中的妙處!本文也僅僅是做爲一個入門而已。