タツノオトシゴのブログ

主にJavaに関するものです。

POIの小ネタ - セルの「縮小して全体を表示する」の設定

POI ver3.10から、セルの「縮小して全体を表示」の設定が正式サポートされました。

今まで、「折り返して全体を表示する」は、CellStyle.setWrapText(boolean)でサポートされていたのに不思議です。

メソッドとして、CellStyle.setShrinkToFit(boolean)を使用します。

POI ver.3.9以前にも、実装されていましたが、そのメソッドは公開されていませんでした。

そのため、リフレクションでフィールドの値を取得し、無理矢理変更する方法があります。


【注意事項】
セルの設定の「縮小して全体を表示する」と「折り返して全体を表示する」はどちらか一方のみ有効にできます。
どちらも設定値をtrueにした場合、「折り返して全体を表示する」の設定が優先されるようです。

import org.apache.poi.hssf.record.ExtendedFormatRecord;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.extensions.XSSFCellAlignment;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCellAlignment;


    // リフレクションを使い、「縮小して全体を表示する」を設定する。
    public void setShrinkToFit(final Cell cell, boolean shrinkToFit) {
        
        final CellStyle style = cell.getCellStyle();
        
        // POI-3.10以上の場合(正式対応)
//        try {
//            style.setShrinkToFit(shrinkToFit);
//            return;
//        } catch(Exception e) {
//            // POI-3.9以前の場合は、メソッドがないのでエラーが発生
//        }
        
        try {
            //POI-3.10以降(リフレクションで呼ぶ)
            final Method method = style.getClass().getMethod("setShrinkToFit", boolean.class);
            method.setAccessible(true);
            method.invoke(style, shrinkToFit);
            
            cell.setCellStyle(style);
            
            return;
            
        } catch (Exception e) { } 
        
        // POI-3.9以前の場合(リフレクションして呼ぶ)
        if(style instanceof HSSFCellStyle) {
            // POI-3.9以前のExcel2003形式
            try {
                final Field field = style.getClass().getDeclaredField("_format");
                field.setAccessible(true);
                
                ExtendedFormatRecord record = (ExtendedFormatRecord) field.get(style);
                record.setShrinkToFit(shrinkToFit);
                
                cell.setCellStyle(style);
                return;
            } catch (Exception e ) {
                
            }
            
        } else if(style instanceof XSSFCellStyle) {
            // POI-3.9以前のExcel2007形式
            try {
                final Method aligngmentMethod = style.getClass().getDeclaredMethod("getCellAlignment");
                aligngmentMethod.setAccessible(true);
                final XSSFCellAlignment alignment = (XSSFCellAlignment) aligngmentMethod.invoke(style);
                
                final Field alignmentField = alignment.getClass().getDeclaredField("cellAlignement");
                alignmentField.setAccessible(true);
                CTCellAlignment alignment2 = (CTCellAlignment) alignmentField.get(alignment);
                
                alignment2.setShrinkToFit(shrinkToFit);
                
                cell.setCellStyle(style);
                return;
            } catch (Exception e ) {
            }
            
        }
        
    }

POIの小ネタ - セルの入力規則の取得

現在、開発中のPOI ver3.11から、セルの入力規則の取得ができるようになりました。

今まで、入力規則の設定はできていましたが、取得はできませんでした。

取得するには、メソッドとして、Sheet.getDataValidations()を使用します。

取得できることにより、行を追加したときなど、既存の行の入力規則を変更することができるようになります。


【注意事項】
POI-3.11beta3で試しましたが、既存の入力規則の範囲を変更するには、新たに入力規則用のインスタンスであるDataValitaionを再作成し、再追加する必要があるようです。

入力範囲を書き換えるには、現状メソッドがないため、リフレクションなどを利用して無理矢理変更します。
詳細は、POIの小ネタ - セルの入力規則の修正 - タツノオトシゴの日記を参照。

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DataValidation;
import org.apache.poi.ss.usermodel.DataValidationConstraint;
import org.apache.poi.ss.usermodel.DataValidationHelper;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellRangeAddressList;

    public void fixValidationRule(final Cell cell) {
        
        // 行を1つ挿入する
        Sheet sheet = cell.getSheet();
        int lastRow = sheet.getLastRowNum();
        if(lastRow == cell.getRowIndex()) {
            lastRow++;
        }
        sheet.shiftRows(cell.getRowIndex()+1, lastRow, 1);
        
        DataValidationHelper helper = sheet.getDataValidationHelper();
        
        // 入力規則の範囲を修正する
        List<? extends DataValidation> list = sheet.getDataValidations();
        for(DataValidation validation : list) {
            
            // 自身のセルの入力規則を探し出す
            CellRangeAddressList region = validation.getRegions();
            for(CellRangeAddress range : region.getCellRangeAddresses()) {
                if(range.isInRange(lastRow-1, cell.getColumnIndex())) {
                    // 追加した行に対して入力規則の設定範囲を広げる(新たに領域を追加する)
                    range.setLastRow(lastRow);
                    break;
                }
                
            }
            
            // 規則を作り直して、再度シートに追加する
            // ※再追加すると既存の範囲が残ったままになるため、実際は、下記URLを参照。
            // http://d.hatena.ne.jp/tatsu-no-toshigo/20150612/1434131054
            sheet.addValidationData(helper.createValidation(validation.getValidationConstraint(), region));
            
            
        }
    }

続・JavaFX8の印刷機能によるHTMLのPDF変換

以前の記事では失敗した、Java8の印刷機能を使ったHTMLのPDF変換を再度試してみた。

結果、上手くいきました

【環境】

  • OS:CentOS6.6 64bit
    • kernel:2.6.32-504.el6.x86_64
  • Java:build 1.8.0_25-b17
  • 仮想プリンタ:cups-pdf(cups-pdf-2.6.1-4.el6.x86_64)

【はまったこと】
WebViewノードを印刷するときに、一般的な方法であるノードの印刷方法(PrinterJob#printPage)を使用すると、複数ページにまたがる場合や、縮小して印刷する際には自前で設定する必要がある。


専用のメソッドWebEngine#print()を使うと、自動的に縮小したりしてくれる。
さらに、CSSの印刷用メディアにも対応してくれる。


JavaFXの公式ページにも、このことは載っていました。


専用の「WebEngine#print」を使用した印刷

  • cups-pdfを使用した場合は、ダイアログなしても印刷できる。
    • 出力ファイル名は、プリンタのジョブ名になるため、ジョブ名を指定する。
  • 今回は、デフォルトのプリンタをcups-pdfにしているが、通常は「Printer#getAllPrinters()」で全てのプリンタを取得して、目的のプリンタを取得する。
import java.io.Serializable;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Worker;
import javafx.print.PageLayout;
import javafx.print.PageOrientation;
import javafx.print.Paper;
import javafx.print.Printer;
import javafx.print.PrinterJob;
import javafx.scene.Scene;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import javafx.stage.Window;

public class Html2PdfApplication0 extends Application {
    
    public static void main(String[] args) {
        String url = "http://www.yahoo.co.jp/";
//        url = "http://ja.wikipedia.org/wiki/JavaFX";
        try {
            launch(new String[] {"--url=" + url});
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    @Override
    public void start(final Stage primaryStage) throws Exception {
        final Application.Parameters params = getParameters();
        final String url = params.getNamed().get("url");
        final WebView webView = new WebView();
        final WebEngine engine = webView.getEngine();
        
        webView.autosize();
        final Scene scene = new Scene(webView);
        primaryStage.setScene(scene);
        
        engine.getLoadWorker().stateProperty().addListener(new ChangeListener<Worker.State>() {
            
            @Override
            public void changed(ObservableValue ov, Worker.State oldState, Worker.State newState) {
                
                if(newState == Worker.State.SUCCEEDED) {
                    System.out.println("complete load.");
                    
                    try {
                        saveNodeAsPdf(webView);
//                        saveNodeAsPdfWithMultiple(webView, scene);
                    } finally {
                        // 印刷したらアプリケーションの終了
                         Platform.exit();
                    }
                }
            }
        });
        
        engine.load(url);
        primaryStage.show();
    }
    
    /**
     * 一般的な印刷用メディアで印刷する。
     * @param webView
     */
    private void saveNodeAsPdf(final WebView webView) {
        System.out.println("==== start print pdf");
        
        // プリンタの取得
        final Printer printer = Printer.getDefaultPrinter();
        if(printer == null) {
            System.err.println("printe is null");
            return;
        } else {
            System.out.println("print name:" + printer.getName());
        }
        
        // レイアウトの設定
        PageLayout pageLayout = printer.createPageLayout(Paper.A4, PageOrientation.PORTRAIT, Printer.MarginType.DEFAULT);
        
        // Printerジョブの取得。
        // ジョブ名が出力するファイル名となるため変更する。
        PrinterJob job = PrinterJob.createPrinterJob(printer);
        job.getJobSettings().setJobName("javafx2pdf");
        System.out.printf("jobName [%s]\n", job.getJobSettings().getJobName());
        
        if(job != null) {
            // CSSの印刷用メディア印刷するには、WebEngin#printを使用する。
            webView.getEngine().print(job);
            job.endJob();
        }
        System.out.println("==== end print pdf");
    }
}

一般的な「PrinterJob#printPage」を使用した印刷

非常に面倒です。

  • PrinterJob#printPageメソッドは、表示されているそのままを印刷するメソッドのため、印刷使用とするページサイズに収まるように縮小表示する必要がある。
  • さらにStage(Window)のウィンドウサイズを調整する必要がある。
    • 現在のWebページのサイズやスクロール表示を考慮する必要がある。
    • Webページのサイズは、WebEngine#executeScript()を使って、JavaScriptで取得する必要がある。
  • 複数ページ印刷する場合、WebViewをスクロールする必要がある。
    • WebViewは自動的にスクロールバーが表示されるが、これはJavaFXのScrollPaneではなく、WebKitの部品のものなので、JavaScriptでスクロールする必要がある。


非常に面倒ですが、WebView#snapshot()でWebページを画像として保存するも同様に、このような方法で色々と考慮する必要があります。

public class Html2PdfApplication0 extends Application {
  // 呼び出す部分は省略

   /**
     * WebViewのノードに対して印刷する。
     * 自分で縮小、スクロールする必要がある。
     * @param webView
     * @param scene
     */
    private void saveNodeAsPdfWithMultiple(final WebView webView, final Scene scene) {
        System.out.println("==== start print pdf");
        
        /*
         * スクロールバーの非表示
         * CSSは下記の内容
         * body {overflow-x: hidden; overflow-y: hidden;}
         */
        webView.getEngine().setUserStyleSheetLocation(getClass().getResource("no-scroll.css").toExternalForm());
        
        // プリンタの取得
        final Printer printer = Printer.getDefaultPrinter();
        if(printer == null) {
            System.err.println("printe is null");
            return;
        } else {
            System.out.println("print name:" + printer.getName());
        }
        
        // 現在のウィンドウ情報を取得
        final WebEngine engine = webView.getEngine();
        WebViewSize viewSize = printWindowInfo(engine);
        
        // レイアウトの設定
        PageLayout pageLayout = printer.createPageLayout(
                Paper.A4,
                PageOrientation.PORTRAIT,
                Printer.MarginType.DEFAULT
                );
        
        // 用紙に合わせてWebViewを縮小表示する
        double scaleX = (pageLayout.getPrintableWidth() - pageLayout.getLeftMargin() - pageLayout.getRightMargin() ) / webView.getBoundsInParent().getWidth();
        webView.setZoom(scaleX);
        System.out.printf("zoom size=%f\n", scaleX);
        
        // ウィンドウの横サイズを調整し、全て表示できるようにする
        Window stage = scene.getWindow();
        int scrollBarWidth = 20;
        double windowWidth = viewSize.documentWidth * scaleX + scrollBarWidth;
        stage.setWidth(windowWidth);
        
        // Printerジョブの取得。
        // ジョブ名が出力するファイル名となるため変更する。
        final PrinterJob job = PrinterJob.createPrinterJob(printer);
        job.getJobSettings().setJobName("javafx2pdf");
        System.out.printf("jobName [%s]\n", job.getJobSettings().getJobName());
        
        
        if(job != null) {
            
            // 印刷するページ数のトータルページの計算
            viewSize = printWindowInfo(engine); // 縮小表示した場合、現在のサイズを再取得する
            int pages = viewSize.documentHeight / viewSize.windowHeight;
            if(viewSize.documentHeight % viewSize.windowHeight != 0) {
                pages++;
            }
            
            
            // 複数ページの印刷
            boolean success = false;
            for(int i=0; i < pages; i++) {
                if(i > 0) {
                    // JavaScriptを使ってスクロール
                    int scolled = i*viewSize.windowHeight;
                    engine.executeScript(String.format("window.scrollTo(%d, %d);", 0, scolled));
                }
                
                success = job.printPage(pageLayout, webView);
                System.out.printf("... page[%d/%d] - print result=%b\n", i+1, pages, success);
                
                if(!success) {
                    job.endJob();
                    break;
                }
            }
            
            if(success) {
                job.endJob();
            }
        }
        System.out.println("==== end print pdf");
    }
    
    
    /**
     * JavaScriptで画面サイズ情報などを取得する
     * http://archiva.jp/web/javascript/get_page-size.html
     * 
     */
    WebViewSize printWindowInfo(WebEngine engine) {
        System.out.println("-------------------------");
        
        // ウィンドウサイズの取得
        int windowWidth = (Integer) engine.executeScript("document.documentElement.clientWidth || document.body.clientWidth || document.body.scrollWidth;");
        int windowHeight = (Integer) engine.executeScript("document.documentElement.clientHeight || document.body.clientHeight || document.body.scrollHeight;");
        
        System.out.printf("windowSize : width=%d, height=%d\n", windowWidth, windowHeight);
        
        // ドキュメントサイズの取得
        int documentWidth = (Integer) engine.executeScript("document.documentElement.scrollWidth || document.body.scrollWidth;");
        int documentHeight = (Integer) engine.executeScript("document.documentElement.scrollHeight || document.body.scrollHeight;");
        
        System.out.printf("documentSize : width=%d, height=%d\n", documentWidth, documentHeight);
        
        // スクロール位置
        int scrollWidth = (Integer) engine.executeScript("document.documentElement.scrollLeft || document.body.scrollLeft;");
        int scrollHeight = (Integer) engine.executeScript("document.documentElement.scrollLeft || document.body.scrollLeft;");
        
        System.out.printf("scrollPosition : width=%d, height=%d\n", scrollWidth, scrollHeight);
        
        
        System.out.println("-------------------------");
        
        WebViewSize size = new WebViewSize();
        size.windowWidth = windowWidth;
        size.windowHeight = windowHeight;
        
        size.documentWidth = documentWidth;
        size.documentHeight = documentHeight;
        
        size.scrollWidth = scrollWidth;
        size.scrollHeight = scrollHeight;
        
        return size;
    }
    
    public static class WebViewSize implements Serializable {
        
        public int windowWidth;
        
        public int windowHeight;
        
        public int documentWidth;
        
        public int documentHeight;
        
        public int scrollWidth;
        
        public int scrollHeight;
        
    }
}

EL式をスタンドアローンで使用する

BeanValidation1.1でEL式が利用できるようになったので、他のライブラリでもメッセージ中にEL式が利用できる方法を調べて見た。

ようは、Servletコンテナなして、EL式を利用する方法を紹介します。

EL2.0

EL2.0の実装としてcommons-el
があります。

ただし、2003年作成と古いです。

EL2.x

EL2.xを単独で利用するには、Glassfishが提供しているライブラリを利用します。

ただし、これだけではだめで、ELContext、ELResolverなど単独で利用できるように別途実装が必要になります。

実は、Hibernate Validator5.xのパッケージ「org.hibernate.validator.internal.engine.messageinterpolation.el」内のクラスがその実装になります。

【参考】


【準備】
EL式のライブラリとその実装用のライブラリを追加します。

<dependency>
	<groupId>javax.el</groupId>
	<artifactId>el-api</artifactId>
	<version>2.2</version>
</dependency>
<dependency>
	<groupId>org.glassfish</groupId>
	<artifactId>el-impl</artifactId>
	<version>2.2</version>
</dependency>

【単独で利用できるように実装したもの】
Githubに参考にして作った実装を上げておきます。
EL3.0のELProcessorと似た使い方ができます。

ELProcessor elProc = new ELProcessor();

elProc.setVariable("currentDate", new Date());
elProc.setVariable("formatter", new FormatterWrapper(Locale.getDefault()));

String eval = elProc.eval("formatter.format('%1$tY/%1$tm/%1$td%n', currentDate)", String.class);

System.out.println(eval);

【注意点】
EL式中で呼び出すオブジェクトの中のメソッドは、オーバライドオーバロードしていると、区別つかないためラップなどして使用する。

'java.util.Formatter#formatter'は、FormatterWrapperクラスでラップして呼び出す必要がある。

EL3.x

EL3.xから、スタンドアローンで利用できるように、専用クラスELProcessor、StandartELContextクラスが追加になりました。

【参考】

【準備】
EL式のライブラリとその実装用のライブラリを追加します。

<dependency>
	<groupId>javax.el</groupId>
	<artifactId>javax.el-api</artifactId>
	<version>3.0.0</version>
</dependency>
<dependency>
	<groupId>org.glassfish</groupId>
	<artifactId>javax.el</artifactId>
	<version>3.0.0</version>
</dependency>

【使い方】

ELProcessor elProc = new ELProcessor();

// 式中で利用する変数の追加
elProc.defineBean("a1", 5);
elProc.defineBean("a2", 3);

// 式の評価
int ret = elProc.eval("a1 + a2");

Hibernate Validator5.x(Bean Validatoin1.1)中のEL式

Hibernate Valiador5.xから、EL式が利用できるようになりました。
しかし、ラムダ式などのEL3.xで追加された機能は利用できません


基本的にEL2.xの機能が利用できます。

Hibernate ValidatorのEL式を解釈するクラス「org.hibernate.validator.internal.engine.messageinterpolation.InterpolationTerm」を見ると、EL2.x系の使い方になっているためということがわかります。


EL3.0で追加された、ELProcessorを利用するように実装を切り替えれば、EL3.0が使えるようになります。


BeanValidationからMessageInterpolatorが独自のものが設定できるようになっているため、org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator中のメソッド「interpolateExpression」の中を変更すれば動作するようになると思います。

public class ResourceBundleMessageInterpolator implements MessageInterpolator

	private String interpolateExpression(TokenIterator tokenIterator, Context context, Locale locale)
			throws MessageDescriptorFormatException {
		while ( tokenIterator.hasMoreInterpolationTerms() ) {
			String term = tokenIterator.nextInterpolationTerm();
			
			// EL式の処理部分。↓の処理を独自なものに変更する。
			InterpolationTerm expression = new InterpolationTerm( term, locale );
			String resolvedExpression = expression.interpolate( context );
			tokenIterator.replaceCurrentInterpolationTerm( resolvedExpression );
		}
		return tokenIterator.getInterpolatedMessage();
	}
	
}	

XlsMapperのリリース

以前に作っていた、XLSBeansの拡張版を「XlsMapper」としてリリースしました。

書き込み機能の他、Validation機能を追加しました。

Validation機能は、Springの仕様を参考に作りましたが、途中からSpring依存でも良さそうな気がしてきました。


FieldProcessorのロジック部分、AnnotationReader部分はXLSBeansのコードが残っていますが、他は書き換えました。

XLSBeansとの違い

下記のURLにまとめてあります。
http://mygreen.github.io/xlsmapper/diff_xlsbeans.html

【改善機能】

  • アノテーションの名称を"@Xls〜"として、他のライブラリのアノテーションと区別がつきやすいようにしています。
  • エラーメッセージの内容を詳細に表示し、設定間違いの対応をしやすくしています。
  • Generics対応として、@XlsMapColums、@XlsIterateTablesにも対応しており、マッピング先のClassを指定する必要がありません。
  • シートの座標位置の取得が、@XlsMapColumnを付与したフィールドにも対応しています。
  • アノテーションを付与するフィールドの修飾子として、public以外のprivate/protectedにも対応しています。

【追加機能】

  • 書き込み機能があります。
    • @XlsHorizontalRecords/@XlsVerticalRecordsに書き込み用の属性を追加し、 行が余ったときや足りないときの動作をカスタマイズできます。
  • 読み込み時、書き込み時のコールバック用メソッドを定義するためのアノテーション @XlsPreLoad/@XlsPostLoad/@XlsPreSave/@XlsPostLoadが使用できます。
  • 型変換機能として、専用のアノテーションを利用して各フィールドごとに細かく設定できます。
  • 読み込んだシートの内容をチェックするValidation機能があります。
    • 独自にValidatorを実装する方式の他、Bean Validation 1.0/1.1に対応しています。
  • セルの座標位置のように、マッピング対象の見出し名を取得するこができます。

【削除機能】

  • コードをシンプルにするため、jExcel API対応を排除し、Apache POIのみに対応しています。
  • アノテーション@PostProcessorを削除しました。 代わりに、@XlsPreLoad/@XlsPostLoad/@XlsPreSave/@XlsPostLoadが使用できます。

今後の予定

  • マニュアルをもう少し詳しく書く。
  • テスタを作成して、品質を上げる。

SuperCSV Annotationのリリース

以前作った、CSV用ライブラリ「SuperCSV」で、アノテーションによるマッピングをできるようにするライブラリ「Super CSV Annotation」をセントラルリポジトリに登録しました。

マニュアルも、作成しました。

【Supser CSV 2.x用】

【Supser CSV 1.5用】

Velocityの簡易エディタを求めて

システム導入時などにVelocityのテンプレートをいじる機会があった。

EclipseとかのIDEだと重く、また、プロジェクト形式にする必要があるので、気軽には使えない。

ネットで探したり、Velocityの公式サイトにあるエディタ一覧を参考にして、「jEdit」にした。


jEditJava製のエディタで、WindowsLinuxなどで動作が可能で、プラグインも充実しています。
しかし、プラグインを入れないと使い勝手が悪いといものもあります。


また、大学生時代の研究で、独自システムの専用言語のエディタとして、自分でカスタマイズして使っていたというのもあり、これにしました。


jEditは標準で、Velosityのシンタクス表示、コード補完も対応しています。。

しかし、マクロや変数などのアウトライン表示は、ctagsを使ったプラグイン「CtagsSideKicker」が必要です。

設定ファイルで簡易的なアウトライン表示にも対応可能です。


jEditのVelocityの設定「CtagsSideKicker(旧CodeBrowser)」

  1. 前提のプラグインに「ErrorList」が必要なので、先にインストールしておく。
    • 先にErrorListをインストールしないとエラーが出る。
  2. 続いて、プラグインマネージャから「CtagsSideKicker」をインストールする。
  3. インストール後、「CtagsSideKicker」のプラグインオプションの項目「ctags Path」で「ctags.exe」のパスを指定する。
  4. 環境変数「HOME」に、設定ファイル「.ctags」を次の内容で配置する。
    • Windowsではファイル名の先頭が「.〜」から始まる場合は標準では作成できないので、コマンドプロンプトの「rename」「copy」コマンドでフィル名を変更する必要がある。
    • この設定は、行の先頭がマクロ定義用の「#macro」、変数定義用の「#set」から始まる場合に、マクロ名、変数名を抽出する。
--langdef=velocity
--langmap=velocity:.vm
--regex-velocity=/^#macro[ ]*\([ ]*([a-zA-Z0-9_]+)/#macro \1/m,macro/i
--regex-velocity=/^#set[ ]*\([ ]*(\$[a-zA-Z0-9_]+)/#set \1/m,macro/i
    • Windowsでは環境変数HOMEがない場合、Windowsユーザのフォルダに配置してもよい。
    • 設定ファイルの改行コードはLFにする。
  1. 設定ファイルを設置後、プラグイン「SideKick」のプラグインオプション「Parsers」で、モードに対するパーサとして「ctags」を指定する。
    • モード「velocity」に対して、パーサ「ctags」を指定する。


注意事項として、設定ファイルいよるアウトラインは正規表現で定義するため、複数行にわたるコメント(#*〜*#)中に、定義対象の文字が見つかった場合は誤検出する。

誤検出を許したくない場合は、自分でctagsにパーサを追加する必要がある。
c言語で比較的、簡単にできるが、ctagsを再ビルドする必要がある。

自分で、ctagsを拡張したい場合は、次のサイトを参考にするとよい。

jEditのお薦めプラグイン

「Column Ruler」

エディタ上で列番号を表示するプラグイン

  • インストール後は、プラグインのメニューからチェックを入れて有効化する必要がある。
  • さらに、起動時にも有効にするために、プラグインのオプションから、「Active by Default」にチェックを入れる。
「BufferTabs」

複数開いている場合にタブ表示する。

  • インストール後は、プラグインのメニューからチェックを入れて有効化する必要がある。
「WhiteSpace」

タブ文字や空白を可視化する。

  • インストール後は、プラグインのオプション「Tabs」の「Show tabs by default」「Show leading tabs by default」などのチェックを入れないと、起動時に有効化されないので注意。
  • 全角の空白を可視化する場合は、プラグインオプション「Other whitespace」のチェックを有効化する。

jEditのその他の設定

jEditの設定は、メニュー「ユーティリティ」−「グローバルオプション」から変更できる。

よく設定する値
  • ラップマージン:「編集」の「ラップマージン」から設定する。100または120くらいにする。
  • タブの表示幅:「編集」の「タブ幅」から設定する。値は、4にする。
  • インデント幅:「編集」の「インデント幅」を4にする。
  • エディタのフォント:「テキストエリア」の「テキストフォント」から設定可能。「MS ゴシック」など等幅かつ日本語対応のフォントにする。
  • 現在のカーソル行の表示:「テキストエリア」の「行列マーカー」にチェックを入れる。
バックアップファイルを作りたくない場合

jEditは標準で、「sample.txt~」というように、バックアップファイルが作られる。

これを作りたくない場合は、メニュー「ユーティリティ」−「グローバルオプション」の「保存&バックアップ」から変更できる。

  • 「保存&バックアップ」の項目「バックアップの最大数」を“1”→”(空)”にクリアする。
  • 「保存&バックアップ」の項目「バックアップファイル名サフィクス」を“~”→”(空)”にクリアする。