首选项

工作台实现类属首选项体系结构, 它允许插件存储用户首选项的值并为工作台首选项对话框添加首选项页面。我们将再次观察自述文件工具示例,以便了解这是如何实现的, 然后观察用于构建首选项页面的一些基础支持。

org.eclipse.ui.preferencePages

org.eclipse.ui.preferencePages 扩展点允许您为工作台首选项(窗口 -> 首选项)对话框添加页面。首选项对话框提供用户首选项条目的分层列表。当选择每个条目时,该条目都会显示相应的首选项页面。

自述文件工具使用此扩展点来添加“自述文件示例”首选项页面。

<extension
    point = "org.eclipse.ui.preferencePages">
    <page 
        id="org.eclipse.ui.examples.readmetool.Page1"
        class="org.eclipse.ui.examples.readmetool.ReadmePreferencePage"
        name="Readme Example">
    </page>
</extension>

此标记定义一个称为“自述文件示例”的首选项页面, 该页面是由类 ReadmePreferencePage 实现的。该类必须实现 IWorkbenchPreferencePage 接口。

工作台使用 PreferenceManager 来保存首选项树中所有节点及其相应页面的列表。可以根据插件注册表中的信息来初始化此列表,而不运行任何插件代码。在运行任何代码之前,将显示插件为首选项对话框添加的内容(“自述文件示例”条目在左边)。

“自述文件示例”首选项被添加到首选项树的顶层的左边。为什么?因为除非指定了类别属性,否则将添加首选项页面添加项作为该树的根目录。(名称类别有点让人产生误解。也许路径这个名称更好一些。) 类别属性指定父页面的标识(或者是根目录中的一系列标识)。例如,下列标记将创建辅助自述文件工具首选项页面“自述文件示例子页面”来作为初始页面的子代。

<extension
    point = "org.eclipse.ui.preferencePages">
    <page 
        id="org.eclipse.ui.examples.readmetool.Page1"
        class="org.eclipse.ui.examples.readmetool.ReadmePreferencePage"
        name="Readme Example">
    </page>    
    <page 
        id="org.eclipse.ui.examples.readmetool.Page2"
        class="org.eclipse.ui.examples.readmetool.ReadmePreferencePage2"
        name="Readme Example Child Page"
        category="org.eclipse.ui.examples.readmetool.Page1>
    </page>
</extension>

一旦用户选择树中的首选项页面左边的条目, 工作台就将使用在扩展定义中指定的来创建和显示首选项页面。此操作将激活插件(如果由于另一个用户操作而使它尚未激活的话)。

首选项页面

定义页面

实现首选项页面类似于为向导创建页面。首选项页面提供 createContents 方法, 该方法创建用来表示页面内容的 SWT 控件,并为感兴趣的所有事件添加侦听器。页面负责创建和返回将作为页面中所有控件的父代的组合体。以下代码片段显示突出显示内容:

protected Control createContents(Composite parent)
{
    ...
    //composite_textField << 父代
    Composite composite_textField = createComposite(parent, 2);
    Label label_textField = createLabel(composite_textField, "Text Field"); 
    textField = createTextField(composite_textField);
    pushButton_textField = createPushButton(composite_textField, "Change");

    //composite_tab << 父代
    Composite composite_tab = createComposite(parent, 2);
    Label label1 = createLabel(composite_tab, "Radio Button Options");

    tabForward(composite_tab);
    //单选按钮组合体 << 选项卡组合体
    Composite composite_radioButton = createComposite(composite_tab, 1);
    radioButton1 = createRadioButton(composite_radioButton, "Radio button 1");
    radioButton2 = createRadioButton(composite_radioButton, "Radio button 2");
    radioButton3 = createRadioButton(composite_radioButton, "Radio button 3");
    ...
    initializeValues();
    ...
    return new Composite(parent, SWT.NULL);
}

此方法中的大多数代码都与控件的创建和布局有关, 因此,在此处我们将不会详细研究它。以下是相应页面的外观:

首选项页面的另一主要功能是响应 performOk 消息。通常,此方法更新和存储用户首选项, 并且,如果需要的话,将更新所有其他插件对象以反映首选项中的更改。

首选项页面应重设 doGetPreferenceStore() 方法,以返回首选项仓库从而存储它们的值。

插件首选项仓库

首选项仓库的性质类似于对话框设置。在对话框设置中, 我们了解了 AbstractUIPlugin 类如何在插件的有效期内维护对话框设置。为用户首选项部署了相同的策略。插件可以将条目添加到首选项仓库中,并在用户更改首选项页面中的设置时更新这些值。平台将小心地将这些值保存在插件的工作目录中, 并根据保存的设置来初始化首选项仓库。

ReadmePreferencePage 中的以下代码获得了 ReadmePlugin 的首选项仓库。

protected IPreferenceStore doGetPreferenceStore() {

 return ReadmePlugin.getDefault().getPreferenceStore();

}

因为 ReadmePlugin 扩展了 AbstractUIPlugin 类, 所以它将自动继承首选项仓库。此首选项仓库是根据存储在插件的目录中的首选项文件来进行初始化的。ReadmePlugin 需要做的唯一事情就是实现用来将首选项初始化为它们的缺省值的方法。当首次显示首选项页面,或者当用户按了首选项页面中的缺省值按钮时,就会使用这些值。

protected void initializeDefaultPreferences(IPreferenceStore store) {

 // 这些设置将说明何时

 //第一次打开首选项对话框。

 store.setDefault(IReadmeConstants.PRE_CHECK1, true);

 store.setDefault(IReadmeConstants.PRE_CHECK2, true);

 store.setDefault(IReadmeConstants.PRE_CHECK3, false);

 store.setDefault(IReadmeConstants.PRE_RADIO_CHOICE, 2);

 store.setDefault(IReadmeConstants.PRE_TEXT, "Default text");

}

注意:如果没有为插件保存任何首选项,则插件将获得空的首选项仓库。

检索和保存首选项

一旦已经将插件的首选项仓库与首选项页面相关联, 就可以实现用于检索和保存首选项的逻辑。

首选项页面负责使用首选项仓库中的首选项设置来初始化它们的控件的值。此过程类似于根据对话框设置来初始化对话框控件值。ReadmePreferencePage 采用单个方法 initializeValues 初始化它的所有控件, 该方法是从它的 createContents 方法中调用的。

private void initializeValues() {

 IPreferenceStore store = getPreferenceStore();

 checkBox1.setSelection(store.getBoolean(IReadmeConstants.PRE_CHECK1));

 checkBox2.setSelection(store.getBoolean(IReadmeConstants.PRE_CHECK2));

 checkBox3.setSelection(store.getBoolean(IReadmeConstants.PRE_CHECK3));
 ...

当按了确定(或者应用)按钮之后, 首选项页面上的控件的当前值就应该存储回首选项仓库中。ReadmePreferencePage 采用单独的方法 storeValues 来实现此逻辑。

private void storeValues() {

 IPreferenceStore store = getPreferenceStore();

 store.setValue(IReadmeConstants.PRE_CHECK1, checkBox1.getSelection());

 store.setValue(IReadmeConstants.PRE_CHECK2, checkBox2.getSelection());

 store.setValue(IReadmeConstants.PRE_CHECK3, checkBox3.getSelection());

 ...

}

当用户按缺省值按钮时, 平台将使所有首选项仓库值恢复为在插件类中指定的缺省值。然而,首选项页面负责在首选项页面的控件中反映这些缺省值。ReadmePreferencePage 采用 initializeDefaults 实现此过程。

private void initializeDefaults() {

 IPreferenceStore store = getPreferenceStore();

 checkBox1.setSelection(store.getDefaultBoolean(IReadmeConstants.PRE_CHECK1));

 checkBox2.setSelection(store.getDefaultBoolean(IReadmeConstants.PRE_CHECK2));

 checkBox3.setSelection(store.getDefaultBoolean(IReadmeConstants.PRE_CHECK3));

 ...

}

字段编辑器

首选项页面的实现主要是 SWT 代码。SWT 代码用来创建首选项页面控件、设置控件的值以及检索控件的值。org.eclipse.jface.preference 包提供了助手类,称为 字段编辑器, 它创建小窗口,并为最常见的首选项类型实现值设置和检索代码。平台提供了字段编辑器来显示和更新许多值类型, 包括布尔值、颜色、字符串、整数、字体和文件名。

FieldEditorPreferencePage 实现一个页面,它使用这些字段编辑器来显示和存储该页面上的首选项值。

FieldEditorPreferencePage 创建字段编辑器来显示内容,而不是创建 SWT 控件来填充它的内容。

public void createFieldEditors() {

    // 第一个字符串是首选项键名
    // 第二个字符串是显示在小窗口旁的标号 
    addField(new BooleanFieldEditor(USE_OLD_MODE, "Use old mode",
        getFieldEditorParent()));

    addField(new StringFieldEditor(APPLICATION_NAME, "Application Name",
        getFieldEditorParent()));

    addField(new ColorFieldEditor(COLOR, "Text Color", getFieldEditorParent()));
    ...

对每个字段编辑器指定其相应的首选项键的名称以及它将创建的 SWT 控件的文本标签。所创建的控件的种类取决于字段编辑器的类型。例如,布尔字段编辑器将创建复选框。

由于首选项页面与首选项仓库(在 doGetPreferenceStore 中指定的)相关联, 因此,用于存储当前值的代码、 用于通过首选项仓库初始化控件值的代码以及将控件恢复为其缺省值的代码都是在 FieldEditorPreferencePage 中实现的。

FieldEditorPreferencePage 将把网格布局与一列配合使用来作为字段编辑器小窗口的缺省布局。为了满足特殊的布局要求,可以重设 createContents 方法。