Symfoware

Symfowareについての考察blog

JavaでSQL構文等のハイライトを行う jsyntaxpane

Javaのテキスト領域にSQLを入力。入力されたSQLの構文をハイライト表示したい。
と思って、良い方法はないか調べてみると

SQL-syntax aware Swing component?
http://stackoverflow.com/questions/3777512/is-there-sql-syntax-aware-swing-component


jsyntaxpane
https://code.google.com/p/jsyntaxpane/

これを使用すれば実現できるようです。
使い方を調べてみます。





jarのダウンロード



以下のページの右下、「Downloads」から「jsyntaxpane-0.9.5-b29.jar」をダウンロードします。

https://code.google.com/p/jsyntaxpane/

191_01.png

191_02.png


ダウンロードしたjarファイルをビルドパスに含めておきます。





簡単な使い方



まず、DefaultSyntaxKit.initKit();を呼び出します。

呼び出すと、javax.swing.JEditorPaneのsetContentTypeに指定できる
値が拡張されるイメージです。

jsyntaxpaneのサイトに掲載されているサンプルを実行してみます。


  1. package sample;
  2. import java.awt.Dimension;
  3. import java.awt.Font;
  4. import javax.swing.JEditorPane;
  5. import javax.swing.JFrame;
  6. import javax.swing.JScrollPane;
  7. import javax.swing.SwingUtilities;
  8. import jsyntaxpane.DefaultSyntaxKit;
  9. @SuppressWarnings("serial")
  10. public class Sample extends JFrame {
  11.     
  12.     private Sample() {
  13.         
  14.         DefaultSyntaxKit.initKit();
  15.         
  16.         setTitle("jsyntaxpane");
  17.         
  18.         final JEditorPane codeEditor = new JEditorPane();
  19.         JScrollPane scrPane = new JScrollPane(codeEditor);
  20.         
  21.         // 表示するスタイルを指定
  22.         codeEditor.setContentType("text/java");
  23.         codeEditor.setText("public static void main(String[] args) {\n}");
  24.         
  25.         // デモ用に大きめのフォントサイズを指定
  26.         Font font = codeEditor.getFont();
  27.         codeEditor.setFont(new Font(font.getName(), font.getStyle(), 16));
  28.         getContentPane().add(scrPane);
  29.     }
  30.     
  31.     private static void startup() {
  32.         Sample frame = new Sample();
  33.         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  34.         frame.setSize(new Dimension(500, 300));
  35.         frame.setLocationRelativeTo(null);
  36.         frame.setVisible(true);
  37.     }
  38.     
  39.     public static void main(String args[]) {
  40.         SwingUtilities.invokeLater(new Runnable() {
  41.             @Override
  42.             public void run() {
  43.                 startup();
  44.             }
  45.         });
  46.     }
  47. }




実行してみるとこんな感じです。
簡単にJavaのシンタックスハイライトが行えました。

191_03.png






SQLの構文をハイライト



setContentTypeに指定する内容を変更すれば良さそうですが、
何を指定すればよいかわからない。

ヒントは、resources/META-INF/services/jsyntaxpane.kitsfortypes.properties
に記載されています。

191_04.png


jsyntaxpane.kitsfortypes.propertiesの内容は以下のとおり。


# This file contains the default content types and the SyntaxKit class names
# that will be used for them.
# The keys are content types, and the values are the fully qualified class
# names
text/c=jsyntaxpane.syntaxkits.CSyntaxKit
text/cpp=jsyntaxpane.syntaxkits.CppSyntaxKit
text/java=jsyntaxpane.syntaxkits.JavaSyntaxKit
text/groovy=jsyntaxpane.syntaxkits.GroovySyntaxKit
text/javascript=jsyntaxpane.syntaxkits.JavaScriptSyntaxKit
text/xml=jsyntaxpane.syntaxkits.XmlSyntaxKit
text/sql=jsyntaxpane.syntaxkits.SqlSyntaxKit
text/properties=jsyntaxpane.syntaxkits.PropertiesSyntaxKit
text/python=jsyntaxpane.syntaxkits.PythonSyntaxKit
text/tal=jsyntaxpane.syntaxkits.TALSyntaxKit
text/jflex=jsyntaxpane.syntaxkits.JFlexSyntaxKit
text/ruby=jsyntaxpane.syntaxkits.RubySyntaxKit
text/scala=jsyntaxpane.syntaxkits.ScalaSyntaxKit
text/clojure=jsyntaxpane.syntaxkits.ClojureSyntaxKit
text/dosbatch=jsyntaxpane.syntaxkits.DOSBatchSyntaxKit
text/bash=jsyntaxpane.syntaxkits.BashSyntaxKit



「text/sql」を指定すれば良さそうです。
その他、cやgroovy、xmlやpythonのシンタックスハイライトにも対応しているようです。



プログラムを以下のように修正して実行してみます。


  1. package sample;
  2. import java.awt.Dimension;
  3. import java.awt.Font;
  4. import javax.swing.JEditorPane;
  5. import javax.swing.JFrame;
  6. import javax.swing.JScrollPane;
  7. import javax.swing.SwingUtilities;
  8. import jsyntaxpane.DefaultSyntaxKit;
  9. @SuppressWarnings("serial")
  10. public class Sample extends JFrame {
  11.     
  12.     private Sample() {
  13.         
  14.         DefaultSyntaxKit.initKit();
  15.         
  16.         setTitle("jsyntaxpane");
  17.         
  18.         final JEditorPane codeEditor = new JEditorPane();
  19.         JScrollPane scrPane = new JScrollPane(codeEditor);
  20.         
  21.         // 表示するスタイルを指定
  22.         codeEditor.setContentType("text/sql");
  23.         codeEditor.setText("SELECT DISTINCT\nCODE_NAME,\nCODE_ID\nFROM\nCODE_MASTER;");
  24.         
  25.         // デモ用に大きめのフォントサイズを指定
  26.         Font font = codeEditor.getFont();
  27.         codeEditor.setFont(new Font(font.getName(), font.getStyle(), 16));
  28.         getContentPane().add(scrPane);
  29.     }
  30.     
  31.     private static void startup() {
  32.         Sample frame = new Sample();
  33.         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  34.         frame.setSize(new Dimension(500, 300));
  35.         frame.setLocationRelativeTo(null);
  36.         frame.setVisible(true);
  37.     }
  38.     
  39.     public static void main(String args[]) {
  40.         SwingUtilities.invokeLater(new Runnable() {
  41.             @Override
  42.             public void run() {
  43.                 startup();
  44.             }
  45.         });
  46.     }
  47. }




ちゃんとSQLの構文がハイライトされました。

191_05.png





日本語の文字化け



日本語表示を試すため、ソースの一部を変更します。


  1.         // 表示するスタイルを指定
  2.         codeEditor.setContentType("text/sql");
  3.         codeEditor.setText("SELECT DISTINCT\nコード名称,\nコードID\nFROM\nCODE_MASTER;");



予想通り、文字化けしてくれました。(Ubuntu 12.04で実行)

191_06.png



回避するため、フォント名称に"Dialog"を指定してやります。


  1. package sample;
  2. import java.awt.Dimension;
  3. import java.awt.Font;
  4. import javax.swing.JEditorPane;
  5. import javax.swing.JFrame;
  6. import javax.swing.JScrollPane;
  7. import javax.swing.SwingUtilities;
  8. import jsyntaxpane.DefaultSyntaxKit;
  9. @SuppressWarnings("serial")
  10. public class Sample extends JFrame {
  11.     
  12.     private Sample() {
  13.         
  14.         DefaultSyntaxKit.initKit();
  15.         
  16.         setTitle("jsyntaxpane");
  17.         
  18.         final JEditorPane codeEditor = new JEditorPane();
  19.         JScrollPane scrPane = new JScrollPane(codeEditor);
  20.         
  21.         // 表示するスタイルを指定
  22.         codeEditor.setContentType("text/sql");
  23.         codeEditor.setText("SELECT DISTINCT\nコード名称,\nコードID\nFROM\nCODE_MASTER;");
  24.         
  25.         // デモ用に大きめのフォントサイズを指定
  26.         // 日本語文字化け対策としてDialogフォントを指定
  27.         codeEditor.setFont(new Font("Dialog", Font.PLAIN, 16));
  28.         getContentPane().add(scrPane);
  29.     }
  30.     
  31.     private static void startup() {
  32.         Sample frame = new Sample();
  33.         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  34.         frame.setSize(new Dimension(500, 300));
  35.         frame.setLocationRelativeTo(null);
  36.         frame.setVisible(true);
  37.     }
  38.     
  39.     public static void main(String args[]) {
  40.         SwingUtilities.invokeLater(new Runnable() {
  41.             @Override
  42.             public void run() {
  43.                 startup();
  44.             }
  45.         });
  46.     }
  47. }




日本語が豆腐にならず表示出来ました。

191_07.png






独自構文対応



独自のハイライト機構を作成する方法も調べてみました。

DefaultSyntaxKitを継承したクラスを作成します。
SimpleRegexLexerに、キーワードを指定したハッシュマップを設定します。

「MY」という文字をキーワードとして登録するサンプルはこんな感じです。


  1. package sample;
  2. import java.util.HashMap;
  3. import java.util.Map;
  4. import jsyntaxpane.DefaultSyntaxKit;
  5. import jsyntaxpane.TokenType;
  6. import jsyntaxpane.lexers.SimpleRegexLexer;
  7. @SuppressWarnings("serial")
  8. public final class MySyntaxKit extends DefaultSyntaxKit {
  9.     
  10.     private static Map<String, String> props;
  11.     static {
  12.         props = new HashMap<String, String>();
  13.         
  14.         // キーワードとして、「MY」という文字を登録
  15.         props.put(TokenType.KEYWORD.toString(), "MY");
  16.     }
  17.     
  18.     public MySyntaxKit() {
  19.         super(new SimpleRegexLexer(props));
  20.     }
  21. }




次に、作成したクラスを登録します。

text/mysyntaxという名前で登録してみました。


  1. package sample;
  2. import java.awt.Dimension;
  3. import java.awt.Font;
  4. import javax.swing.JEditorPane;
  5. import javax.swing.JFrame;
  6. import javax.swing.JScrollPane;
  7. import javax.swing.SwingUtilities;
  8. import jsyntaxpane.DefaultSyntaxKit;
  9. @SuppressWarnings("serial")
  10. public class Sample extends JFrame {
  11.     
  12.     private Sample() {
  13.         
  14.         DefaultSyntaxKit.initKit();
  15.         // 独自クラスを登録
  16.         DefaultSyntaxKit.registerContentType("text/mysyntax", "sample.MySyntaxKit");
  17.         
  18.         setTitle("jsyntaxpane");
  19.         
  20.         final JEditorPane codeEditor = new JEditorPane();
  21.         JScrollPane scrPane = new JScrollPane(codeEditor);
  22.         
  23.         // 表示するスタイルを指定
  24.         codeEditor.setContentType("text/mysyntax");
  25.         codeEditor.setText("MY SyntaxKit Sample;");
  26.         
  27.         // デモ用に大きめのフォントサイズを指定
  28.         // 日本語文字化け対策としてDialogフォントを指定
  29.         codeEditor.setFont(new Font("Dialog", Font.PLAIN, 16));
  30.         getContentPane().add(scrPane);
  31.     }
  32.     
  33.     private static void startup() {
  34.         Sample frame = new Sample();
  35.         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  36.         frame.setSize(new Dimension(500, 300));
  37.         frame.setLocationRelativeTo(null);
  38.         frame.setVisible(true);
  39.     }
  40.     
  41.     public static void main(String args[]) {
  42.         SwingUtilities.invokeLater(new Runnable() {
  43.             @Override
  44.             public void run() {
  45.                 startup();
  46.             }
  47.         });
  48.     }
  49. }




実行してみると、ちゃんと「MY」という単語がキーワード表示されてます。

191_08.png




指定できるキーワードを網羅してみます。

  1. package sample;
  2. import java.util.HashMap;
  3. import java.util.Map;
  4. import jsyntaxpane.DefaultSyntaxKit;
  5. import jsyntaxpane.TokenType;
  6. import jsyntaxpane.lexers.SimpleRegexLexer;
  7. @SuppressWarnings("serial")
  8. public final class MySyntaxKit extends DefaultSyntaxKit {
  9.     
  10.     private static Map<String, String> props;
  11.     static {
  12.         props = new HashMap<String, String>();
  13.         
  14.         // 色々試してみます
  15.         props.put(TokenType.COMMENT.toString(), "COMMENT");
  16.         props.put(TokenType.COMMENT2.toString(), "COMMENT2");
  17.         props.put(TokenType.DEFAULT.toString(), "DEFAULT");
  18.         props.put(TokenType.DELIMITER.toString(), "DELIMITER");
  19.         props.put(TokenType.ERROR.toString(), "ERROR");
  20.         props.put(TokenType.IDENTIFIER.toString(), "IDENTIFIER");
  21.         props.put(TokenType.KEYWORD.toString(), "KEYWORD");
  22.         props.put(TokenType.KEYWORD2.toString(), "KEYWORD2");
  23.         props.put(TokenType.NUMBER.toString(), "NUMBER");
  24.         props.put(TokenType.OPERATOR.toString(), "OPERATOR");
  25.         props.put(TokenType.REGEX.toString(), "REGEX");
  26.         props.put(TokenType.REGEX2.toString(), "REGEX2");
  27.         props.put(TokenType.STRING.toString(), "STRING");
  28.         props.put(TokenType.STRING2.toString(), "STRING2");
  29.         props.put(TokenType.TYPE.toString(), "TYPE");
  30.         props.put(TokenType.TYPE2.toString(), "TYPE2");
  31.         props.put(TokenType.TYPE3.toString(), "TYPE3");
  32.         props.put(TokenType.WARNING.toString(), "WARNING");
  33.     }
  34.     
  35.     public MySyntaxKit() {
  36.         super(new SimpleRegexLexer(props));
  37.     }
  38. }




表示してみると、こんな感じになりました。


191_09.png


関連記事

テーマ:プログラミング - ジャンル:コンピュータ

  1. 2013/03/31(日) 21:17:43|
  2. Java
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集
次のページ