hishidaの開発blog

EBシリーズ(EBPocket,EBWin,EBMac,EBStudio),KWIC Finder,xdoc2txt,読書尚友の開発者ブログ

EBWin4,EBMacに「全ての項目の表示」を実装

EBWin4、EBMacに、「検索に一致した全ての項目の表示」機能を追加した。(EBPocket for iOS/Androidも順次対応予定)
これまではEBシリーズの本文の表示モードには、連続表示と項目毎表示しかなかった。
連続表示とは、見出し語の本文を表示する場合に、後続の本文のテキストを続けて表示するモードである。
通常の連続表示の例:検索語 detectiveの後続のテキストを続けて表示

EPWINGはもともと「電子書籍」を目指しており、一冊の本、または巻物のように、最初から最後まで通読できるようになっている。このため、EPWINGの公式ビューアであるCDView(富士通)、Viewing(イースト)、こととい(岩波書店)では、基本的に連続表示を行うようになっていた。(今ではWindows10にインストールできるかどうかも定かでない)
項目毎表示は、検索に一致した見出し語の本文だけを表示するモードである。ただしEPWINGには項目の区切りという概念がないので、ソフトウェアで何の識別子を項目の区切りにするかを決定しないといけない。これはたぶんUnix上のEPWING検索システムや、DDWinのようなサードパーティ製のEPWINGビューアで出てきた概念だと思う。

今回追加した「全ての項目の表示」とは、検索に一致した見出し語の本文だけを、すべて一覧で表示するものであり、項目毎表示の結果を連結したものと考えるといいと思う。

全ての項目の表示:検索に一致した語の本文を連結表示

実はDDWinにはこの機能が昔からあり(項目表示→全て表示)、今でもこの機能のためにDDWinを利用しているというユーザもいらっしゃるらしい。
DDWinには一つ制約があり、串刺し検索で「全て表示」を行なった場合に、先頭の辞書しか外字が表示できなかった。EBWin4/EBMacでは全ての辞書の外字を表示するようになっている。これについては、EBWin3.xまではWin32 APIで描画していたため拡張が難しかったが、EBWin4では本文表示をWebブラウザコントロールで行っているため、実現がしやすくなった。

既知の問題点、および制約についても書いておくと、

  1. 「全ての項目の表示」では縦書き設定は解除される
  2. 「全ての項目の表示」を行なった後で、検索一致リストから項目を選択した時の挙動は、通常の連続表示/項目毎表示に戻る
  3. 串刺し検索の場合、リンクが働くのは先頭の辞書のみ (その後、全辞書のリンクが動作するように修正した)

複合検索のモードレス化

もう一つ、EBWin4で改良を行なったのは、複合検索のダイアログがこれまでモーダルポップアップだったのを、モードレスポップアップに変更した。複合検索ダイアログを表示したままで、次々と絞り込み検索をするという使い方が可能になった。
モードレスにしようとすると、ダイアログ側から、メインスレッドの表示処理をコールバックする必要がある。C++だと関数ポインタを引数で渡すような実装方法になるが、C#にはdelegateという機能があり、もう少し美しく実装できる。

モーダルダイアログの場合。OKボタンを押すまで制御が帰ってこない。OKボタンを押すとダイアログが消え、メインスレッドで検索結果を表示する。

	ComplexSearchDialog cplx_dlg = new ComplexSearchDialog();
	cplx_dlg.Owner = this;
	// モーダルダイアログとして表示
	if (dlg.ShowDialog() == DialogResult.OK)
	{
		// 検索結果を表示
	}

モードレスダイアログの場合。ダイアログを表示したまま、検索結果をメインスレッドで表示する。

	private ComplexSearchDialog cplx_dlg = null

	if ( cplx_dlg == null || cplx_dlg.IsDisposed)   // 二重起動を防ぐ
	{
		cplx_dlg = new ComplexSearchDialog();
		cplx_dlg.RefreshEvent += delegate(object sender, EventArgs e)
		{
			// 検索結果を表示
		};
		cplx_dlg.Owner = this;

		// モードレスダイアログを表示する
		cplx_dlg.Show();
	}					

ダイアログ側

public partial class ComplexSearchDialog : Form
{

	public delegate void RefreshEventHandler(object sender, EventArgs e);
	public event RefreshEventHandler RefreshEvent;

	// OKボタンが押された場合
        private void okButton_Click(object sender, EventArgs e)
        {
		//検索処理をする
		(略)
		//  検索結果をメインスレッドで表示する
		this.RefreshEvent(this, new EventArgs());
 }