S-JIS[2013-01-05/2013-05-09] 変更履歴

Eclipseプラグイン PropertyPageクラス

Eclipseプラグイン開発のPropertyPage(プロパティーの保存)について。


PropertyPageとは

Eclipseでは、リソース(ファイルやプロジェクト等)を選択してからメニューバーの「プロジェクト(P)」→「プロパティー(P)」でプロパティーダイアログを開き、各プラグイン 用の設定を変更・保存する事が出来る。
これはPropertyPageクラスで実現する。

→ワークスペース全体やEclipse全体での設定の保存はPreferenceStoreで行う。


PropertyPageの使用例

メッセージを表示するアクションの例に対し、表示するダイアログのタイトルとメッセージをプロジェクト毎のプロパティーで設定できるように改造してみる。


プロパティーページの作成

まず、プロパティーダイアログでで表示されるページを作成する。
(Preferenceと異なり、イニシャライザーといったものは無い)

これには、EclipseのSWT(GUIの為のクラス群)を使う。
(PreferenceにはFieldEditorという便利なクラスがあったが、プロパティーには無い)

IProjectインターフェースを使うので、依存関係にorg.eclipse.core.resourcesを追加しておく必要がある。
(MANIFEST.MFをダブルクリックしてエディターを開き、「依存関係」タブから「必須プラグイン」の追加ボタンで追加できる)

src/com/example/eclipse/plugin/hello/property/HelloProjectPropertyPage.java

package com.example.eclipse.plugin.hello.property;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.ILog;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.dialogs.PropertyPage;

import com.example.eclipse.plugin.hello.Activator;
import com.example.eclipse.plugin.hello.preference.HelloPreferenceInitializer;
public class HelloProjectPropertyPage extends PropertyPage {
	public static final String KEY_TITLE   = "HELLO_TITLE";
	public static final String KEY_MESSAGE = "HELLO_MESSAGE";

	private Text titleText;
	private Text messageText;
	@Override
	protected Control createContents(Composite parent) {
		IProject project = (IProject) getElement();

		Composite composite = new Composite(parent, SWT.NONE);
		{
			GridLayout layout = new GridLayout();
			layout.numColumns = 2; // 列数
			composite.setLayout(layout);
		}

		{ // タイトルを入力する行
			Label label = new Label(composite, SWT.NONE);
			label.setText("title");

			titleText = new Text(composite, SWT.SINGLE | SWT.BORDER);
			titleText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
			String value = getValue(project, KEY_TITLE);
			if (value != null) {
				titleText.setText(value);
			}
		}
		{ // メッセージを入力する行
			Label label = new Label(composite, SWT.NONE);
			label.setText("message");

			messageText = new Text(composite, SWT.SINGLE | SWT.BORDER);
			messageText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
			String value = getValue(project, KEY_MESSAGE);
			if (value != null) {
				messageText.setText(value);
			}
		}

		super.noDefaultAndApplyButton();

		return composite;
	}

createContents()でSWTを使って入力フィールドを用意していく。
IProjectから値を取得している以外はPreferencePageでのコーディングと全く同じ。
(今回は「デフォルトの復元」ボタンを無くす為にnoDefaultAndApplyButton()を呼び出している)

	@Override
	public boolean performOk() {
		IProject project = (IProject) getElement();

		setValue(project, KEY_TITLE,   titleText.getText());
		setValue(project, KEY_MESSAGE, messageText.getText());

		return true;
	}

performOk()は「OK」ボタンが押されたときに実行される。
テキストフィールドに入力された値をIProjectに保存する。

	private String getValue(IProject project, String key) {
		try {
			return project.getPersistentProperty(new QualifiedName(Activator.PLUGIN_ID, key));
		} catch (CoreException e) {
			ILog log = Activator.getDefault().getLog();
			log.log(e.getStatus());
			return null;
		}
	}

	private void setValue(IProject project, String key, String value) {
		try {
			project.setPersistentProperty(new QualifiedName(Activator.PLUGIN_ID, key), value);
		} catch (CoreException e) {
			ILog log = Activator.getDefault().getLog();
			log.log(e.getStatus());
		}
	}
}

getValue()/setValue()は、IProjectのプロパティーアクセスの為に用意したメソッド。
プロパティーアクセスには、プロパティー値が永続化されるgetPersistentProperty/setPersistentPropertyの他に、セッション内でのみ有効なgetSessionProperty/getSessionPropertyもある。


そして、plugin.xmlに設定ページの記述を追加する。

<plugin>
〜
   <extension
         point="org.eclipse.ui.propertyPages">
      <page
            class="com.example.eclipse.plugin.hello.property.HelloProjectPropertyPage"
            id="com.example.eclipse.plugin.hello.property.page"
            name="plugin-example1">
         <enabledWhen>
            <adapt type="org.eclipse.core.resources.IProject"/>
         </enabledWhen>
      </page>
   </extension>

</plugin>

enabledWhenによって、特定のリソースの場合だけプロパティーページを有効にすることが出来る。
今回はIProjectの場合だけ有効にしている。
(これにより、getElement()の戻り型をIProjectに決め打ちしてキャストしている)
enabledWhenの例

※enabledWhenを何も付けないと、プロパティーページ以外のとんでもない所でもページが表示されてしまうので、絶対に条件を付けるべき![2013-05-09]


設定の読み込み

今回の例の対象であるアクションクラスを修正し、プロパティーから値を読み込むようにする。

src/com/example/eclipse/plugin/hello/actions/HelloAction.java:

	@Override
	public void run(IAction action) {
		IProject project = getProject();

		String title;
		try {
			title = project.getPersistentProperty(new QualifiedName(Activator.PLUGIN_ID, HelloProjectPropertyPage.KEY_TITLE));
		} catch (CoreException e) {
			title = null;
		}
		String message;
		try {
			message = project.getPersistentProperty(new QualifiedName(Activator.PLUGIN_ID, HelloProjectPropertyPage.KEY_MESSAGE));
		} catch (CoreException e) {
			message = null;
		}

		ILog log = Activator.getDefault().getLog();
		log.log(new Status(IStatus.INFO, Activator.PLUGIN_ID, String.format("action title=[%s], message=[%s]", title, message)));

		MessageDialog.openInformation(window.getShell(), title, message);
	}

IProjectが取れさえすれば、getPersistentProperty()でプロパティーを取得することが出来る。

が、肝心のgetProject()は自分で実装しなければならない。
アクティブなプロジェクトを単純に取得する方法は無いようなので、割愛。


okToLeave

okToLeaveメソッドをオーバーライドすることで、ユーザーがツリー上の別ページを選択した際にページ移動してよいかどうかを判定できる。[2014-01-12]
つまり、自分のページの設定値が変更されているのにまだ未適用だったら、「ページ移動してよいかどうか」を確認するダイアログを出すことが出来る。

okToLeave()でtrueを返せばページ移動可能、falseを返せばページ移動しない。
のだが、falseを返した場合、「Could Not Accept Changes」「The currently displayed page contains invalid values.」というエラーダイアログが出てしまう(Eclipse4.3)。
プロパティーページ上の設定値が不正だからページ移動できない、という旨だと思う。
このエラーダイアログは消せないみたいなので、falseを返さない方が良さそう(苦笑)

src/com/example/eclipse/plugin/hello/property/HelloProjectPropertyPage.java:

public class HelloProjectPropertyPage extends PropertyPage {
〜
	private Text titleText;
	private Text messageText;

	private String firstTitle;
	private String firstMessage;
	@Override
	protected Control createContents(Composite parent) {
〜
		this.firstTitle = titleText.getText();
		this.firstMessage = messageText.getText();

		return composite;
	}
	@Override
	public boolean okToLeave() {
		if (!titleText.getText().equals(firstTitle) || !messageText.getText().equals(firstMessage)) {
			String title = "Setting Hello Properties";
			String message = "設定値が変更されています。\n変更を適用しますか?";
			String[] buttonLabels = new String[] { "Apply", "Discard" };
			MessageDialog dialog = new MessageDialog(getShell(), title, null, message, MessageDialog.QUESTION, buttonLabels, 0);
			int res = dialog.open();
			if (res == 0) { // save
				return performOk() && super.okToLeave();
			} else { // discard
				return performFirst() && super.okToLeave();
			}
		}
		return super.okToLeave();
	}

	private boolean performFirst() {
		titleText.setText(firstTitle);
		messageText.setText(firstMessage);
		return true;
	}

enabledWhen

plugin.xmlのorg.eclipse.ui.propertyPagesのenabledWhenでプロパティーページを表示する条件を指定することが出来る。[2013-04-06]

条件 plugin.xml記述例 element取得例 更新日
プロジェクトのプロパティー
<enabledWhen>
   <adapt type="org.eclipse.core.resources.IProject"/>
</enabledWhen>
  2013-05-09
プロジェクト
<enabledWhen>
   <instanceof value="org.eclipse.core.resources.IProject" />
</enabledWhen>
IProject project = (IProject) getElement();  
通常ファイル・ディレクトリー
または
Javaファイル・ディレクトリー
<enabledWhen>
   <or>
      <instanceof
            value="org.eclipse.core.resources.IResource">
      </instanceof>
      <instanceof
            value="org.eclipse.jdt.core.IJavaElement">
      </instanceof>
   </or>
</enabledWhen>
private IProject getProject() {
  IAdaptable element = getElement();
  if (element instanceof IResource) {
    return ((IResource) getElement()).getProject();
  }
  if (element instanceof IJavaElement) {
    return ((IJavaElement) element).getJavaProject().getProject();
  }
  return null;
}
2013-04-06

Eclipseプラグインへ戻る / Eclipseへ戻る / 技術メモへ戻る
メールの送信先:ひしだま